edgroup.c revision 30259
119370Spst/*-
219370Spst * Copyright (C) 1996
319370Spst *	David L. Nugent.  All rights reserved.
419370Spst *
546283Sdfr * Redistribution and use in source and binary forms, with or without
619370Spst * modification, are permitted provided that the following conditions
719370Spst * are met:
819370Spst * 1. Redistributions of source code must retain the above copyright
919370Spst *    notice, this list of conditions and the following disclaimer.
1019370Spst * 2. Redistributions in binary form must reproduce the above copyright
1119370Spst *    notice, this list of conditions and the following disclaimer in the
1219370Spst *    documentation and/or other materials provided with the distribution.
1319370Spst *
1419370Spst * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND
1519370Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1619370Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1719370Spst * ARE DISCLAIMED.  IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE
1819370Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1919370Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2019370Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2119370Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2219370Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2319370Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2419370Spst * SUCH DAMAGE.
2519370Spst */
2619370Spst
2719370Spst#ifndef lint
2819370Spststatic const char rcsid[] =
2919370Spst	"$Id$";
3019370Spst#endif /* not lint */
3119370Spst
3219370Spst#include <stdio.h>
3319370Spst#include <stdlib.h>
3419370Spst#include <string.h>
3519370Spst#include <unistd.h>
3619370Spst#include <stdarg.h>
3719370Spst#include <sys/types.h>
3819370Spst#include <sys/stat.h>
3919370Spst#include <pwd.h>
4019370Spst#include <grp.h>
4119370Spst#include <fcntl.h>
4219370Spst#include <sys/param.h>
4319370Spst#include <ctype.h>
4419370Spst
4519370Spst#include "pwupd.h"
4619370Spst
4719370Spststatic int
4819370Spstisingroup(char const * name, char **mem)
4919370Spst{
5019370Spst	int             i;
5119370Spst
5219370Spst	for (i = 0; mem[i] != NULL; i++)
5319370Spst		if (strcmp(name, mem[i]) == 0)
5419370Spst			return i;
5519370Spst	return -1;
5619370Spst}
5719370Spst
5819370Spststatic char     groupfile[] = _PATH_GROUP;
5919370Spststatic char     grouptmp[] = _PATH_GROUP ".new";
6019370Spst
6119370Spstint
6219370Spsteditgroups(char *name, char **groups)
6319370Spst{
6419370Spst	int             rc = 0;
6519370Spst	int             infd;
6619370Spst
6719370Spst	if ((infd = open(groupfile, O_RDWR | O_CREAT | O_EXLOCK, 0644)) != -1) {
6819370Spst		FILE           *infp;
6919370Spst
7019370Spst		if ((infp = fdopen(infd, "r+")) == NULL)
7119370Spst			close(infd);
7219370Spst		else {
7319370Spst			int             outfd;
7419370Spst
7519370Spst			if ((outfd = open(grouptmp, O_RDWR | O_CREAT | O_TRUNC | O_EXLOCK, 0644)) != -1) {
7619370Spst				FILE           *outfp;
7719370Spst
7819370Spst				if ((outfp = fdopen(outfd, "w+")) == NULL)
7919370Spst					close(outfd);
8019370Spst				else {
8119370Spst					int		linelen = PWBUFSZ;
8219370Spst					int		outlen =  PWBUFSZ;
8319370Spst					int		memlen = 200; /* Arbitrary */
8419370Spst					char           *line = malloc(linelen);
8519370Spst					char           *outl = malloc(outlen);
8619370Spst					char	      **mems = malloc(memlen * sizeof(char *));
8719370Spst					int		namlen = strlen(name);
8819370Spst
8919370Spst					if (line == NULL || outl == NULL || mems == NULL) {
9019370Spst					    mem_abort:
9119370Spst						rc = 0;
9219370Spst					} else {
9319370Spst						while (fgets(line, linelen, infp) != NULL) {
9419370Spst							char           *p;
9519370Spst							int		l;
9619370Spst
9719370Spst							while ((p = strchr(line, '\n')) == NULL)
9819370Spst							{
9919370Spst								if (extendline(&line, &linelen, linelen + PWBUFSZ) == -1) {
10019370Spst									goto mem_abort;
10119370Spst								}
10219370Spst								l = strlen(line);
10319370Spst								if (fgets(line + l, linelen - l, infp) == NULL)
10419370Spst									break;	/* No newline terminator on last line */
10519370Spst							}
10619370Spst							l = strlen(line) + namlen + 1;
10719370Spst							if (extendline(&outl, &outlen, l) == -1) {
10819370Spst								goto mem_abort;
10919370Spst							}
11019370Spst							if (*line == '#')
11119370Spst								strcpy(outl, line);
11219370Spst							else if (*line == '\n')
11319370Spst								*outl = '\0';
11419370Spst							else {
11519370Spst								int             i,
11619370Spst									        mno = 0;
11719370Spst								char           *cp = line;
11819370Spst								char const     *sep = ":\n";
11919370Spst								struct group    grp;
12019370Spst
12119370Spst								memset(&grp, 0, sizeof grp);
12219370Spst								for (i = 0; (p = strsep(&cp, sep)) != NULL; i++) {
12319370Spst									switch (i) {
12419370Spst									case 0:	/* Group name */
12519370Spst										grp.gr_name = p;
12619370Spst										break;
12719370Spst									case 1:	/* Group password */
12819370Spst										grp.gr_passwd = p;
12919370Spst										break;
13019370Spst									case 2:	/* Group id */
13119370Spst										grp.gr_gid = atoi(p);
13219370Spst										break;
13319370Spst									case 3:	/* Member list */
13419370Spst										cp = p;
13519370Spst										sep = ",\n";
13619370Spst										break;
13719370Spst									default:	/* Individual members */
13819370Spst										if (*p) {
13919370Spst											if (extendarray(&mems, &memlen, mno + 2) == -1) {
14019370Spst												goto mem_abort;
14119370Spst											}
14219370Spst											mems[mno++] = p;
14319370Spst										}
14419370Spst										break;
14519370Spst									}
14619370Spst								}
14719370Spst								if (i < 2)	/* Bail out - insufficient fields */
14819370Spst									continue;
14919370Spst
15019370Spst								grp.gr_mem = mems;
15119370Spst								for (i = mno; i < memlen; i++)
15219370Spst									mems[i] = NULL;
15319370Spst
15419370Spst								/*
15519370Spst								 * Delete from group, or add to group?
15619370Spst								 */
15719370Spst								if (groups == NULL || isingroup(grp.gr_name, groups) == -1) {	/* Delete */
15819370Spst									int             idx;
15919370Spst
16019370Spst									while ((idx = isingroup(name, mems)) != -1) {
16119370Spst										for (i = idx; i < (memlen - 1); i++)
16219370Spst											mems[i] = mems[i + 1];
16319370Spst										mems[i] = NULL;
16419370Spst										--mno;
16519370Spst									}
16619370Spst									/*
16719370Spst									 * Special case - deleting user and group may be user's own
16819370Spst									 */
16919370Spst									if (groups == NULL && mems[0] == NULL && strcmp(name, grp.gr_name) == 0) {
17019370Spst										/*
17119370Spst										 * First, make _sure_ we don't have other members
17219370Spst										 */
17319370Spst										struct passwd  *pwd;
17419370Spst
17519370Spst										setpwent();
17619370Spst										while ((pwd = getpwent()) != NULL && pwd->pw_gid != grp.gr_gid);
17719370Spst										endpwent();
17819370Spst										if (pwd == NULL)	/* No members at all */
17919370Spst											continue;	/* Drop the group */
18019370Spst									}
18119370Spst								} else if (isingroup(name, mems) == -1) {
18219370Spst									if (extendarray(&mems, &memlen, mno + 2) == -1) {
18319370Spst										goto mem_abort;
18419370Spst									}
18519370Spst									grp.gr_mem = mems;    /* May have realloced() */
18619370Spst									mems[mno++] = name;
18719370Spst									mems[mno  ] = NULL;
18819370Spst								}
18919370Spst								fmtgrentry(&outl, &outlen, &grp, PWF_GROUP);
19019370Spst							}
19119370Spst							fputs(outl, outfp);
19219370Spst						}
19319370Spst						if (fflush(outfp) != EOF) {
19419370Spst							rc = 1;
19519370Spst
19619370Spst							/*
19719370Spst							 * Copy data back into the original file and truncate
19819370Spst							 */
19919370Spst							rewind(infp);
20019370Spst							rewind(outfp);
20119370Spst							while (fgets(outl, outlen, outfp) != NULL)
20219370Spst								fputs(outl, infp);
20319370Spst
20419370Spst							/*
20519370Spst							 * This is a gross hack, but we may have corrupted the
20619370Spst							 * original file. Unfortunately, it will lose preservation
20719370Spst							 * of the inode.
20819370Spst							 */
20919370Spst							if (fflush(infp) == EOF || ferror(infp))
21019370Spst								rc = rename(grouptmp, groupfile) == 0;
21119370Spst							else
21219370Spst								ftruncate(infd, ftell(infp));
21319370Spst						}
21419370Spst					}
21519370Spst					free(mems);
21619370Spst					free(outl);
21719370Spst			    		free(line);
21819370Spst					fclose(outfp);
21919370Spst				}
22019370Spst				remove(grouptmp);
22119370Spst			}
22219370Spst			fclose(infp);
22319370Spst		}
22419370Spst	}
22519370Spst	return rc;
22619370Spst}
22719370Spst