static struct group * vnextgrent(char const *nam, gid_t gid, int doclose) { struct group *gr; char *line; size_t linecap; ssize_t linelen; gr = NULL; line = NULL; linecap = 0; linelen = 0; if (grp_fp != NULL || (grp_fp = fopen(getgrpath(_GROUP), "r")) != NULL) { while ((linelen = getline(&line, &linecap, grp_fp)) > 0) { /* Skip comments and empty lines */ if (*line == '\n' || *line == '#') continue; /* trim latest \n */ if (line[linelen - 1 ] == '\n') line[linelen - 1] = '\0'; gr = gr_scan(line); if (gid != (gid_t)-1) { if (gid == gr->gr_gid) break; } else if (nam != NULL) { if (strcmp(nam, gr->gr_name) == 0) break; } else break; free(gr); gr = NULL; } if (doclose) vendgrent(); } free(line); return (gr); }
static struct group * vnextgrent(char const * nam, gid_t gid, int doclose) { struct group * gr = NULL; static char * grtmp = NULL; static int grlen = 0; static char ** mems = NULL; static int memlen = 0; extendline(&grtmp, &grlen, MAXPATHLEN); strlcpy(grtmp, getgrpath(_GROUP), MAXPATHLEN); if (grp_fp != NULL || (grp_fp = fopen(grtmp, "r")) != NULL) { int done = 0; static struct group grp; while (!done && fgets(grtmp, grlen, grp_fp) != NULL) { int i, quickout = 0; int mno = 0; char * q, * p; char * sep = ":\n"; if ((p = strchr(grtmp, '\n')) == NULL) { int l; extendline(&grtmp, &grlen, grlen + PWBUFSZ); l = strlen(grtmp); if (fgets(grtmp + l, grlen - l, grp_fp) == NULL) break; /* No newline terminator on last line */ } /* Skip comments and empty lines */ if (*grtmp == '\n' || *grtmp == '#') continue; i = 0; q = p = grtmp; bzero(&grp, sizeof grp); extendarray(&mems, &memlen, 200); while (!quickout && (p = strsep(&q, sep)) != NULL) { switch (i++) { case 0: /* groupname */ grp.gr_name = p; if (nam) { if (strcmp(nam, p) == 0) done = 1; else quickout = 1; } break; case 1: /* password */ grp.gr_passwd = p; break; case 2: /* gid */ grp.gr_gid = atoi(p); if (gid != (gid_t)-1) { if (gid == (gid_t)grp.gr_gid) done = 1; else quickout = 1; } else if (nam == NULL) done = 1; break; case 3: q = p; sep = ",\n"; break; default: if (*p) { extendarray(&mems, &memlen, mno + 2); mems[mno++] = p; } break; } } grp.gr_mem = mems; mems[mno] = NULL; } if (doclose) vendgrent(); if (done && grp.gr_name) { gr = &grp; CKNULL(grp.gr_passwd); } } return gr; }
int editgroups(char *name, char **groups) { int rc = 0; int infd; char groupfile[MAXPATHLEN]; char grouptmp[MAXPATHLEN]; strncpy(groupfile, getgrpath(_GROUP), MAXPATHLEN - 5); groupfile[MAXPATHLEN - 5] = '\0'; strcpy(grouptmp, groupfile); strcat(grouptmp, ".new"); if ((infd = open(groupfile, O_RDWR | O_CREAT | O_EXLOCK, 0644)) != -1) { FILE *infp; if ((infp = fdopen(infd, "r+")) == NULL) close(infd); else { int outfd; if ((outfd = open(grouptmp, O_RDWR | O_CREAT | O_TRUNC, 0644)) != -1) { FILE *outfp; if ((outfp = fdopen(outfd, "w+")) == NULL) close(outfd); else { int linelen = PWBUFSZ; int outlen = PWBUFSZ; int memlen = 200; /* Arbitrary */ char *line = malloc(linelen); char *outl = malloc(outlen); char **mems = malloc(memlen * sizeof(char *)); int namlen = strlen(name); if (line == NULL || outl == NULL || mems == NULL) { mem_abort: rc = 0; } else { while (fgets(line, linelen, infp) != NULL) { char *p; int l; while ((p = strchr(line, '\n')) == NULL) { if (extendline(&line, &linelen, linelen + PWBUFSZ) == -1) { goto mem_abort; } l = strlen(line); if (fgets(line + l, linelen - l, infp) == NULL) break; /* No newline terminator on last line */ } l = strlen(line) + namlen + 1; if (extendline(&outl, &outlen, l) == -1) { goto mem_abort; } if (*line == '#') strcpy(outl, line); else if (*line == '\n') *outl = '\0'; else { int i, mno = 0; char *cp = line; char const *sep = ":\n"; struct group grp; memset(&grp, 0, sizeof grp); for (i = 0; (p = strsep(&cp, sep)) != NULL; i++) { switch (i) { case 0: /* Group name */ grp.gr_name = p; break; case 1: /* Group password */ grp.gr_passwd = p; break; case 2: /* Group id */ grp.gr_gid = atoi(p); break; case 3: /* Member list */ cp = p; sep = ",\n"; break; default: /* Individual members */ if (*p) { if (extendarray(&mems, &memlen, mno + 2) == -1) { goto mem_abort; } mems[mno++] = p; } break; } } if (i < 2) /* Bail out - insufficient fields */ continue; grp.gr_mem = mems; for (i = mno; i < memlen; i++) mems[i] = NULL; /* * Delete from group, or add to group? */ if (groups == NULL || isingroup(grp.gr_name, groups) == -1) { /* Delete */ int idx; while ((idx = isingroup(name, mems)) != -1) { for (i = idx; i < (memlen - 1); i++) mems[i] = mems[i + 1]; mems[i] = NULL; --mno; } /* * Special case - deleting user and group may be user's own */ if (groups == NULL && mems[0] == NULL && strcmp(name, grp.gr_name) == 0) { /* * First, make _sure_ we don't have other members */ struct passwd *pwd; SETPWENT(); while ((pwd = GETPWENT()) != NULL && (gid_t)pwd->pw_gid != (gid_t)grp.gr_gid); ENDPWENT(); if (pwd == NULL) /* No members at all */ continue; /* Drop the group */ } } else if (isingroup(name, mems) == -1) { if (extendarray(&mems, &memlen, mno + 2) == -1) { goto mem_abort; } grp.gr_mem = mems; /* May have realloced() */ mems[mno++] = name; mems[mno ] = NULL; } fmtgrentry(&outl, &outlen, &grp, PWF_GROUP); } fputs(outl, outfp); } if (fflush(outfp) != EOF) { rc = 1; /* * Copy data back into the original file and truncate */ rewind(infp); rewind(outfp); while (fgets(outl, outlen, outfp) != NULL) fputs(outl, infp); /* * This is a gross hack, but we may have corrupted the * original file. */ if (fflush(infp) == EOF || ferror(infp)) rc = rename(grouptmp, groupfile) == 0; else ftruncate(infd, ftell(infp)); } } free(mems); free(outl); free(line); fclose(outfp); } remove(grouptmp); } fclose(infp); } } return rc; }