17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bdstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bdstevel@tonic-gate * (the "License").  You may not use this file except in compliance
77c478bdstevel@tonic-gate * with the License.
87c478bdstevel@tonic-gate *
97c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bdstevel@tonic-gate * See the License for the specific language governing permissions
127c478bdstevel@tonic-gate * and limitations under the License.
137c478bdstevel@tonic-gate *
147c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bdstevel@tonic-gate *
207c478bdstevel@tonic-gate * CDDL HEADER END
217c478bdstevel@tonic-gate */
227c478bdstevel@tonic-gate/*
237c478bdstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bdstevel@tonic-gate * Use is subject to license terms.
257c478bdstevel@tonic-gate */
267c478bdstevel@tonic-gate/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
277c478bdstevel@tonic-gate/*	  All Rights Reserved  	*/
287c478bdstevel@tonic-gate
297c478bdstevel@tonic-gate
307c478bdstevel@tonic-gate#pragma ident	"%Z%%M%	%I%	%E% SMI"
317c478bdstevel@tonic-gate
327c478bdstevel@tonic-gate#include <sys/types.h>
337c478bdstevel@tonic-gate#include <stdio.h>
347c478bdstevel@tonic-gate#include <stdlib.h>
357c478bdstevel@tonic-gate#include <string.h>
367c478bdstevel@tonic-gate#include <ctype.h>
377c478bdstevel@tonic-gate#include <sys/stat.h>
387c478bdstevel@tonic-gate#include <grp.h>
397c478bdstevel@tonic-gate#include <unistd.h>
407c478bdstevel@tonic-gate#include <userdefs.h>
417c478bdstevel@tonic-gate#include <errno.h>
427c478bdstevel@tonic-gate#include <limits.h>
437c478bdstevel@tonic-gate#include "users.h"
447c478bdstevel@tonic-gate#include "messages.h"
457c478bdstevel@tonic-gate
467c478bdstevel@tonic-gate#define	MYBUFSIZE (LINE_MAX)
477c478bdstevel@tonic-gate	/* Corresponds to MYBUFSIZE in grpck.c, BUFCONST in nss_dbdefs.c */
487c478bdstevel@tonic-gate
497c478bdstevel@tonic-gateint
507c478bdstevel@tonic-gateedit_group(char *login, char *new_login, gid_t gids[], int overwrite)
517c478bdstevel@tonic-gate{
527c478bdstevel@tonic-gate	char **memptr;
537c478bdstevel@tonic-gate	char t_name[] = "/etc/gtmp.XXXXXX";
547c478bdstevel@tonic-gate	int fd;
557c478bdstevel@tonic-gate	FILE *e_fptr, *t_fptr;
567c478bdstevel@tonic-gate	struct group *g_ptr;	/* group structure from fgetgrent */
577c478bdstevel@tonic-gate	int i;
587c478bdstevel@tonic-gate	int modified = 0;
597c478bdstevel@tonic-gate	struct stat sbuf;
607c478bdstevel@tonic-gate
617c478bdstevel@tonic-gate	int bufsize, g_length, sav_errno;
627c478bdstevel@tonic-gate	long g_curr = 0L;
637c478bdstevel@tonic-gate	char *g_string, *new_g_string, *gstr_off;
647c478bdstevel@tonic-gate
657c478bdstevel@tonic-gate	if ((e_fptr = fopen(GROUP, "r")) == NULL)
667c478bdstevel@tonic-gate		return (EX_UPDATE);
677c478bdstevel@tonic-gate
687c478bdstevel@tonic-gate	if (fstat(fileno(e_fptr), &sbuf) != 0) {
697c478bdstevel@tonic-gate		(void) fclose(e_fptr);
707c478bdstevel@tonic-gate		return (EX_UPDATE);
717c478bdstevel@tonic-gate	}
727c478bdstevel@tonic-gate
737c478bdstevel@tonic-gate	if ((fd = mkstemp(t_name)) == -1) {
747c478bdstevel@tonic-gate		(void) fclose(e_fptr);
757c478bdstevel@tonic-gate		return (EX_UPDATE);
767c478bdstevel@tonic-gate	}
777c478bdstevel@tonic-gate
787c478bdstevel@tonic-gate	if ((t_fptr = fdopen(fd, "w")) == NULL) {
797c478bdstevel@tonic-gate		(void) close(fd);
807c478bdstevel@tonic-gate		(void) unlink(t_name);
817c478bdstevel@tonic-gate		(void) fclose(e_fptr);
827c478bdstevel@tonic-gate		return (EX_UPDATE);
837c478bdstevel@tonic-gate	}
847c478bdstevel@tonic-gate
857c478bdstevel@tonic-gate	/*
867c478bdstevel@tonic-gate	 * Get ownership and permissions correct
877c478bdstevel@tonic-gate	 */
887c478bdstevel@tonic-gate
897c478bdstevel@tonic-gate	if (fchmod(fd, sbuf.st_mode) != 0 ||
907c478bdstevel@tonic-gate	    fchown(fd, sbuf.st_uid, sbuf.st_gid) != 0) {
917c478bdstevel@tonic-gate		(void) fclose(t_fptr);
927c478bdstevel@tonic-gate		(void) fclose(e_fptr);
937c478bdstevel@tonic-gate		(void) unlink(t_name);
947c478bdstevel@tonic-gate		return (EX_UPDATE);
957c478bdstevel@tonic-gate	}
967c478bdstevel@tonic-gate
977c478bdstevel@tonic-gate	g_curr = ftell(e_fptr);
987c478bdstevel@tonic-gate
997c478bdstevel@tonic-gate	/* Make TMP file look like we want GROUP file to look */
1007c478bdstevel@tonic-gate
1017c478bdstevel@tonic-gate	bufsize = MYBUFSIZE;
1027c478bdstevel@tonic-gate	if ((g_string = malloc(bufsize)) == NULL) {
1037c478bdstevel@tonic-gate		(void) fclose(t_fptr);
1047c478bdstevel@tonic-gate		(void) fclose(e_fptr);
1057c478bdstevel@tonic-gate		(void) unlink(t_name);
1067c478bdstevel@tonic-gate		return (EX_UPDATE);
1077c478bdstevel@tonic-gate	}
1087c478bdstevel@tonic-gate	/*
1097c478bdstevel@tonic-gate	 * bufsize contains the size of the currently allocated buffer
1107c478bdstevel@tonic-gate	 * buffer size, which is initially MYBUFSIZE but when a line
1117c478bdstevel@tonic-gate	 * greater than MYBUFSIZE is encountered then bufsize gets increased
1127c478bdstevel@tonic-gate	 * by MYBUFSIZE.
1137c478bdstevel@tonic-gate	 * g_string always points to the beginning of the buffer (even after
1147c478bdstevel@tonic-gate	 * realloc()).
1157c478bdstevel@tonic-gate	 * gstr_off = g_string + MYBUFSIZE * (n), where n >= 0.
1167c478bdstevel@tonic-gate	 */
1177c478bdstevel@tonic-gate	while (!feof(e_fptr) && !ferror(e_fptr)) {
1187c478bdstevel@tonic-gate		g_length = 0;
1197c478bdstevel@tonic-gate		gstr_off = g_string;
1207c478bdstevel@tonic-gate		while (fgets(gstr_off, (bufsize - g_length), e_fptr) != NULL) {
1217c478bdstevel@tonic-gate			g_length += strlen(gstr_off);
1227c478bdstevel@tonic-gate			if (g_string[g_length - 1] == '\n' || feof(e_fptr))
1237c478bdstevel@tonic-gate				break;
1247c478bdstevel@tonic-gate			new_g_string = realloc(g_string, (bufsize + MYBUFSIZE));
1257c478bdstevel@tonic-gate			if (new_g_string == NULL) {
1267c478bdstevel@tonic-gate				free(g_string);
1277c478bdstevel@tonic-gate				(void) fclose(t_fptr);
1287c478bdstevel@tonic-gate				(void) fclose(e_fptr);
1297c478bdstevel@tonic-gate				(void) unlink(t_name);
1307c478bdstevel@tonic-gate				return (EX_UPDATE);
1317c478bdstevel@tonic-gate			}
1327c478bdstevel@tonic-gate			bufsize += MYBUFSIZE;
1337c478bdstevel@tonic-gate			g_string = new_g_string;
1347c478bdstevel@tonic-gate			gstr_off = g_string + g_length;
1357c478bdstevel@tonic-gate		}
1367c478bdstevel@tonic-gate		if (g_length == 0) {
1377c478bdstevel@tonic-gate			continue;
1387c478bdstevel@tonic-gate		}
1397c478bdstevel@tonic-gate
1407c478bdstevel@tonic-gate		/* While there is another group string */
1417c478bdstevel@tonic-gate
1427c478bdstevel@tonic-gate		(void) fseek(e_fptr, g_curr, SEEK_SET);
1437c478bdstevel@tonic-gate		errno = 0;
1447c478bdstevel@tonic-gate		g_ptr = fgetgrent(e_fptr);
1457c478bdstevel@tonic-gate		sav_errno = errno;
1467c478bdstevel@tonic-gate		g_curr = ftell(e_fptr);
1477c478bdstevel@tonic-gate
1487c478bdstevel@tonic-gate		if (g_ptr == NULL) {
1497c478bdstevel@tonic-gate			/* tried to parse a group string over MYBUFSIZ char */
1507c478bdstevel@tonic-gate			if (sav_errno == ERANGE)
1517c478bdstevel@tonic-gate				errmsg(M_GROUP_ENTRY_OVF);
1527c478bdstevel@tonic-gate			else
1537c478bdstevel@tonic-gate				errmsg(M_READ_ERROR);
1547c478bdstevel@tonic-gate
1557c478bdstevel@tonic-gate			modified = 0; /* bad group file: cannot rebuild */
1567c478bdstevel@tonic-gate			break;
1577c478bdstevel@tonic-gate		}
1587c478bdstevel@tonic-gate
1597c478bdstevel@tonic-gate		/* first delete the login from the group, if it's there */
1607c478bdstevel@tonic-gate		if (overwrite || !gids) {
1617c478bdstevel@tonic-gate			if (g_ptr->gr_mem != NULL) {
1627c478bdstevel@tonic-gate				for (memptr = g_ptr->gr_mem; *memptr;
1637c478bdstevel@tonic-gate				    memptr++) {
1647c478bdstevel@tonic-gate					if (strcmp(*memptr, login) == 0) {
1657c478bdstevel@tonic-gate						/* Delete this one */
1667c478bdstevel@tonic-gate						char **from = memptr + 1;
1677c478bdstevel@tonic-gate
1687c478bdstevel@tonic-gate						g_length -= (strlen(*memptr)+1);
1697c478bdstevel@tonic-gate
1707c478bdstevel@tonic-gate						do {
1717c478bdstevel@tonic-gate							*(from - 1) = *from;
1727c478bdstevel@tonic-gate						} while (*from++);
1737c478bdstevel@tonic-gate
1747c478bdstevel@tonic-gate						modified++;
1757c478bdstevel@tonic-gate						break;
1767c478bdstevel@tonic-gate					}
1777c478bdstevel@tonic-gate				}
1787c478bdstevel@tonic-gate			}
1797c478bdstevel@tonic-gate		}
1807c478bdstevel@tonic-gate
1817c478bdstevel@tonic-gate		/* now check to see if group is one to add to */
1827c478bdstevel@tonic-gate		if (gids) {
1837c478bdstevel@tonic-gate			for (i = 0; gids[i] != -1; i++) {
1847c478bdstevel@tonic-gate				if (g_ptr->gr_gid == gids[i]) {
1857c478bdstevel@tonic-gate					/* Find end */
1867c478bdstevel@tonic-gate					for (memptr = g_ptr->gr_mem; *memptr;
1877c478bdstevel@tonic-gate						memptr++)
1887c478bdstevel@tonic-gate						;
1897c478bdstevel@tonic-gate					g_length += strlen(new_login ?
1907c478bdstevel@tonic-gate							new_login : login)+1;
1917c478bdstevel@tonic-gate
1927c478bdstevel@tonic-gate					*memptr++ = new_login ?
1937c478bdstevel@tonic-gate						new_login : login;
1947c478bdstevel@tonic-gate					*memptr = NULL;
1957c478bdstevel@tonic-gate
1967c478bdstevel@tonic-gate					modified++;
1977c478bdstevel@tonic-gate				}
1987c478bdstevel@tonic-gate			}
1997c478bdstevel@tonic-gate		}
2007c478bdstevel@tonic-gate		putgrent(g_ptr, t_fptr);
2017c478bdstevel@tonic-gate	}
2027c478bdstevel@tonic-gate	free(g_string);
2037c478bdstevel@tonic-gate
2047c478bdstevel@tonic-gate	(void) fclose(e_fptr);
2057c478bdstevel@tonic-gate
2067c478bdstevel@tonic-gate	if (fclose(t_fptr) != 0) {
2077c478bdstevel@tonic-gate		(void) unlink(t_name);
2087c478bdstevel@tonic-gate		return (EX_UPDATE);
2097c478bdstevel@tonic-gate	}
2107c478bdstevel@tonic-gate
2117c478bdstevel@tonic-gate	/* Now, update GROUP file, if it was modified */
2127c478bdstevel@tonic-gate	if (modified) {
2137c478bdstevel@tonic-gate		if (rename(t_name, GROUP) != 0) {
2147c478bdstevel@tonic-gate			(void) unlink(t_name);
2157c478bdstevel@tonic-gate			return (EX_UPDATE);
2167c478bdstevel@tonic-gate		}
2177c478bdstevel@tonic-gate		return (EX_SUCCESS);
2187c478bdstevel@tonic-gate	} else {
2197c478bdstevel@tonic-gate		(void) unlink(t_name);
2207c478bdstevel@tonic-gate		return (EX_SUCCESS);
2217c478bdstevel@tonic-gate	}
2227c478bdstevel@tonic-gate}
223