120253Sjoerg/*- 220302Sjoerg * Copyright (C) 1996 320302Sjoerg * David L. Nugent. All rights reserved. 420253Sjoerg * 520253Sjoerg * Redistribution and use in source and binary forms, with or without 620253Sjoerg * modification, are permitted provided that the following conditions 720253Sjoerg * are met: 820253Sjoerg * 1. Redistributions of source code must retain the above copyright 920302Sjoerg * notice, this list of conditions and the following disclaimer. 1020253Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 1120253Sjoerg * notice, this list of conditions and the following disclaimer in the 1220253Sjoerg * documentation and/or other materials provided with the distribution. 1320253Sjoerg * 1420302Sjoerg * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND 1520253Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1620253Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1720302Sjoerg * ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE 1820253Sjoerg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1920253Sjoerg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2020253Sjoerg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2120253Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2220253Sjoerg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2320253Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2420253Sjoerg * SUCH DAMAGE. 2520253Sjoerg */ 2620253Sjoerg 2730259Scharnier#ifndef lint 2830259Scharnierstatic const char rcsid[] = 2950479Speter "$FreeBSD$"; 3030259Scharnier#endif /* not lint */ 3130259Scharnier 3220253Sjoerg#include <stdio.h> 3320253Sjoerg#include <stdlib.h> 3420253Sjoerg#include <string.h> 3520253Sjoerg#include <unistd.h> 3620253Sjoerg#include <stdarg.h> 3720253Sjoerg#include <sys/types.h> 3820253Sjoerg#include <sys/stat.h> 3920253Sjoerg#include <pwd.h> 4020253Sjoerg#include <grp.h> 4120253Sjoerg#include <fcntl.h> 4220253Sjoerg#include <sys/param.h> 4320253Sjoerg#include <ctype.h> 4420253Sjoerg 4520253Sjoerg#include "pwupd.h" 4620253Sjoerg 4720253Sjoergstatic int 4820253Sjoergisingroup(char const * name, char **mem) 4920253Sjoerg{ 5020253Sjoerg int i; 5120253Sjoerg 5220747Sdavidn for (i = 0; mem[i] != NULL; i++) 5320253Sjoerg if (strcmp(name, mem[i]) == 0) 5420253Sjoerg return i; 5520253Sjoerg return -1; 5620253Sjoerg} 5720253Sjoerg 5820253Sjoergint 5920253Sjoergeditgroups(char *name, char **groups) 6020253Sjoerg{ 6120253Sjoerg int rc = 0; 6220253Sjoerg int infd; 6344229Sdavidn char groupfile[MAXPATHLEN]; 6444229Sdavidn char grouptmp[MAXPATHLEN]; 6520253Sjoerg 6644229Sdavidn strncpy(groupfile, getgrpath(_GROUP), MAXPATHLEN - 5); 6744229Sdavidn groupfile[MAXPATHLEN - 5] = '\0'; 6844229Sdavidn strcpy(grouptmp, groupfile); 6944229Sdavidn strcat(grouptmp, ".new"); 7044229Sdavidn 71126753Skensmith if ((infd = open(groupfile, O_RDWR | O_CREAT | O_EXLOCK, 0644)) != -1) { 7220253Sjoerg FILE *infp; 7320253Sjoerg 7420253Sjoerg if ((infp = fdopen(infd, "r+")) == NULL) 7520253Sjoerg close(infd); 7620253Sjoerg else { 7720253Sjoerg int outfd; 7820253Sjoerg 79126753Skensmith if ((outfd = open(grouptmp, O_RDWR | O_CREAT | O_TRUNC, 0644)) != -1) { 8020253Sjoerg FILE *outfp; 8120253Sjoerg 8220253Sjoerg if ((outfp = fdopen(outfd, "w+")) == NULL) 8320253Sjoerg close(outfd); 8420253Sjoerg else { 8520747Sdavidn int linelen = PWBUFSZ; 8620747Sdavidn int outlen = PWBUFSZ; 8720747Sdavidn int memlen = 200; /* Arbitrary */ 8820747Sdavidn char *line = malloc(linelen); 8920747Sdavidn char *outl = malloc(outlen); 9020747Sdavidn char **mems = malloc(memlen * sizeof(char *)); 9120747Sdavidn int namlen = strlen(name); 9220253Sjoerg 9320747Sdavidn if (line == NULL || outl == NULL || mems == NULL) { 9420747Sdavidn mem_abort: 9520747Sdavidn rc = 0; 9620747Sdavidn } else { 9720747Sdavidn while (fgets(line, linelen, infp) != NULL) { 9820747Sdavidn char *p; 9920747Sdavidn int l; 10020253Sjoerg 10120747Sdavidn while ((p = strchr(line, '\n')) == NULL) 10220747Sdavidn { 10320747Sdavidn if (extendline(&line, &linelen, linelen + PWBUFSZ) == -1) { 10420747Sdavidn goto mem_abort; 10520747Sdavidn } 10620747Sdavidn l = strlen(line); 10720747Sdavidn if (fgets(line + l, linelen - l, infp) == NULL) 10820747Sdavidn break; /* No newline terminator on last line */ 10920253Sjoerg } 11020747Sdavidn l = strlen(line) + namlen + 1; 11120747Sdavidn if (extendline(&outl, &outlen, l) == -1) { 11220747Sdavidn goto mem_abort; 11320747Sdavidn } 11420747Sdavidn if (*line == '#') 11520747Sdavidn strcpy(outl, line); 11620747Sdavidn else if (*line == '\n') 11720747Sdavidn *outl = '\0'; 11820747Sdavidn else { 11920747Sdavidn int i, 12020747Sdavidn mno = 0; 12120747Sdavidn char *cp = line; 12220747Sdavidn char const *sep = ":\n"; 12320747Sdavidn struct group grp; 12420253Sjoerg 12520747Sdavidn memset(&grp, 0, sizeof grp); 12620747Sdavidn for (i = 0; (p = strsep(&cp, sep)) != NULL; i++) { 12720747Sdavidn switch (i) { 12820747Sdavidn case 0: /* Group name */ 12920747Sdavidn grp.gr_name = p; 13020747Sdavidn break; 13120747Sdavidn case 1: /* Group password */ 13220747Sdavidn grp.gr_passwd = p; 13320747Sdavidn break; 13420747Sdavidn case 2: /* Group id */ 13520747Sdavidn grp.gr_gid = atoi(p); 13620747Sdavidn break; 13720747Sdavidn case 3: /* Member list */ 13820747Sdavidn cp = p; 13920747Sdavidn sep = ",\n"; 14020747Sdavidn break; 14120747Sdavidn default: /* Individual members */ 14220747Sdavidn if (*p) { 14320747Sdavidn if (extendarray(&mems, &memlen, mno + 2) == -1) { 14420747Sdavidn goto mem_abort; 14520747Sdavidn } 14620747Sdavidn mems[mno++] = p; 14720747Sdavidn } 14820747Sdavidn break; 14920747Sdavidn } 15020253Sjoerg } 15120747Sdavidn if (i < 2) /* Bail out - insufficient fields */ 15220747Sdavidn continue; 15320253Sjoerg 15420747Sdavidn grp.gr_mem = mems; 15520747Sdavidn for (i = mno; i < memlen; i++) 15620253Sjoerg mems[i] = NULL; 15720253Sjoerg 15820253Sjoerg /* 15920747Sdavidn * Delete from group, or add to group? 16020253Sjoerg */ 16120747Sdavidn if (groups == NULL || isingroup(grp.gr_name, groups) == -1) { /* Delete */ 16220747Sdavidn int idx; 16320253Sjoerg 16420747Sdavidn while ((idx = isingroup(name, mems)) != -1) { 16520747Sdavidn for (i = idx; i < (memlen - 1); i++) 16620747Sdavidn mems[i] = mems[i + 1]; 16720747Sdavidn mems[i] = NULL; 16820747Sdavidn --mno; 16920747Sdavidn } 17020747Sdavidn /* 17120747Sdavidn * Special case - deleting user and group may be user's own 17220747Sdavidn */ 17320747Sdavidn if (groups == NULL && mems[0] == NULL && strcmp(name, grp.gr_name) == 0) { 17420747Sdavidn /* 17520747Sdavidn * First, make _sure_ we don't have other members 17620747Sdavidn */ 17720747Sdavidn struct passwd *pwd; 17820747Sdavidn 17944229Sdavidn SETPWENT(); 18044229Sdavidn while ((pwd = GETPWENT()) != NULL && (gid_t)pwd->pw_gid != (gid_t)grp.gr_gid); 18144229Sdavidn ENDPWENT(); 18220747Sdavidn if (pwd == NULL) /* No members at all */ 18320747Sdavidn continue; /* Drop the group */ 18420747Sdavidn } 18520747Sdavidn } else if (isingroup(name, mems) == -1) { 18620747Sdavidn if (extendarray(&mems, &memlen, mno + 2) == -1) { 18720747Sdavidn goto mem_abort; 18820747Sdavidn } 18920747Sdavidn grp.gr_mem = mems; /* May have realloced() */ 19020747Sdavidn mems[mno++] = name; 19120747Sdavidn mems[mno ] = NULL; 19220253Sjoerg } 19320747Sdavidn fmtgrentry(&outl, &outlen, &grp, PWF_GROUP); 19420747Sdavidn } 19520747Sdavidn fputs(outl, outfp); 19620253Sjoerg } 19720747Sdavidn if (fflush(outfp) != EOF) { 19820747Sdavidn rc = 1; 19920253Sjoerg 20020747Sdavidn /* 20120747Sdavidn * Copy data back into the original file and truncate 20220747Sdavidn */ 20320747Sdavidn rewind(infp); 20420747Sdavidn rewind(outfp); 20520747Sdavidn while (fgets(outl, outlen, outfp) != NULL) 20620747Sdavidn fputs(outl, infp); 20720253Sjoerg 20820747Sdavidn /* 20920747Sdavidn * This is a gross hack, but we may have corrupted the 210126753Skensmith * original file. 21120747Sdavidn */ 21220747Sdavidn if (fflush(infp) == EOF || ferror(infp)) 21320747Sdavidn rc = rename(grouptmp, groupfile) == 0; 21420747Sdavidn else 21520747Sdavidn ftruncate(infd, ftell(infp)); 21620747Sdavidn } 21720253Sjoerg } 21820747Sdavidn free(mems); 21920747Sdavidn free(outl); 22020747Sdavidn free(line); 22120253Sjoerg fclose(outfp); 22220253Sjoerg } 22320253Sjoerg remove(grouptmp); 22420253Sjoerg } 22520253Sjoerg fclose(infp); 22620253Sjoerg } 22720253Sjoerg } 22820253Sjoerg return rc; 22920253Sjoerg} 230