int main(UNUSED(int argc), UNUSED(char *argv[])) { int n, i; gid_t *list; gid_t gid = MY_GID(); int gid_in_list = 0; #ifdef HAVE_GETGROUPS if ((n = getgroups(0, NULL)) < 0) { perror("getgroups"); return 1; } #else n = 0; #endif list = (gid_t*)malloc(sizeof (gid_t) * (n + 1)); if (!list) { fprintf(stderr, "out of memory!\n"); exit(1); } #ifdef HAVE_GETGROUPS if (n > 0) n = getgroups(n, list); #endif for (i = 0; i < n; i++) { printf("%lu ", (unsigned long)list[i]); if (list[i] == gid) gid_in_list = 1; } /* The default gid might not be in the list on some systems. */ if (!gid_in_list) printf("%lu", (unsigned long)gid); printf("\n"); return 0; }
static void edit_cmd(void) { char n[MAX_FNAME], q[MAX_TEMPSTR]; const char *editor; FILE *f; int ch, t, x; sig_t oint, oabrt, oquit, ohup; struct stat statbuf; struct utimbuf utimebuf; long mtimensec; WAIT_T waiter; PID_T pid, xpid; log_it(RealUser, Pid, "BEGIN EDIT", User); if (!glue_strings(n, sizeof n, SPOOL_DIR, User, '/')) { errx(ERROR_EXIT, "path too long"); } if (!(f = fopen(n, "r"))) { if (errno != ENOENT) { err(ERROR_EXIT, "cannot open `%s'", n); } warnx("no crontab for `%s' - using an empty one", User); if (!(f = fopen(_PATH_DEVNULL, "r"))) { err(ERROR_EXIT, "cannot open `%s'", _PATH_DEVNULL); } } if (fstat(fileno(f), &statbuf) < 0) { warn("cannot stat crontab file"); goto fatal; } utimebuf.actime = statbuf.st_atime; utimebuf.modtime = statbuf.st_mtime; mtimensec = statbuf.st_mtimensec; /* Turn off signals. */ ohup = signal(SIGHUP, SIG_IGN); oint = signal(SIGINT, SIG_IGN); oquit = signal(SIGQUIT, SIG_IGN); oabrt = signal(SIGABRT, SIG_IGN); if (!glue_strings(Filename, sizeof Filename, _PATH_TMP, "crontab.XXXXXXXXXX", '/')) { warnx("path too long"); goto fatal; } if (-1 == (t = mkstemp(Filename))) { warn("cannot create `%s'", Filename); goto fatal; } #ifdef HAS_FCHOWN x = fchown(t, MY_UID(pw), MY_GID(pw)); #else x = chown(Filename, MY_UID(pw), MY_GID(pw)); #endif if (x < 0) { warn("cannot chown `%s'", Filename); goto fatal; } if (!(NewCrontab = fdopen(t, "r+"))) { warn("cannot open fd"); goto fatal; } Set_LineNum(1); skip_header(&ch, f); /* copy the rest of the crontab (if any) to the temp file. */ for (; EOF != ch; ch = get_char(f)) (void)putc(ch, NewCrontab); (void)fclose(f); if (fflush(NewCrontab) < OK) { err(ERROR_EXIT, "cannot flush output for `%s'", Filename); } (void)utime(Filename, &utimebuf); again: rewind(NewCrontab); if (ferror(NewCrontab)) { warn("error while writing new crontab to `%s'", Filename); fatal: (void)unlink(Filename); exit(ERROR_EXIT); } if (((editor = getenv("VISUAL")) == NULL || *editor == '\0') && ((editor = getenv("EDITOR")) == NULL || *editor == '\0')) { editor = EDITOR; } /* we still have the file open. editors will generally rewrite the * original file rather than renaming/unlinking it and starting a * new one; even backup files are supposed to be made by copying * rather than by renaming. if some editor does not support this, * then don't use it. the security problems are more severe if we * close and reopen the file around the edit. */ switch (pid = fork()) { case -1: warn("cannot fork"); goto fatal; case 0: /* child */ if (setgid(MY_GID(pw)) < 0) { err(ERROR_EXIT, "cannot setgid(getgid())"); } if (setuid(MY_UID(pw)) < 0) { err(ERROR_EXIT, "cannot setuid(getuid())"); } if (chdir(_PATH_TMP) < 0) { err(ERROR_EXIT, "cannot chdir to `%s'", _PATH_TMP); } if (!glue_strings(q, sizeof q, editor, Filename, ' ')) { errx(ERROR_EXIT, "editor command line too long"); } (void)execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", q, (char *)0); err(ERROR_EXIT, "cannot start `%s'", editor); /*NOTREACHED*/ default: /* parent */ break; } /* parent */ for (;;) { xpid = waitpid(pid, &waiter, WUNTRACED); if (xpid == -1) { if (errno != EINTR) warn("waitpid() failed waiting for PID %ld " "from `%s'", (long)pid, editor); } else if (xpid != pid) { warnx("wrong PID (%ld != %ld) from `%s'", (long)xpid, (long)pid, editor); goto fatal; } else if (WIFSTOPPED(waiter)) { (void)kill(getpid(), WSTOPSIG(waiter)); } else if (WIFEXITED(waiter) && WEXITSTATUS(waiter)) { warnx("`%s' exited with status %d\n", editor, WEXITSTATUS(waiter)); goto fatal; } else if (WIFSIGNALED(waiter)) { warnx("`%s' killed; signal %d (%score dumped)", editor, WTERMSIG(waiter), WCOREDUMP(waiter) ? "" : "no "); goto fatal; } else break; } (void)signal(SIGHUP, ohup); (void)signal(SIGINT, oint); (void)signal(SIGQUIT, oquit); (void)signal(SIGABRT, oabrt); if (fstat(t, &statbuf) < 0) { warn("cannot stat `%s'", Filename); goto fatal; } if (utimebuf.modtime == statbuf.st_mtime && mtimensec == statbuf.st_mtimensec) { warnx("no changes made to crontab"); goto remove; } warnx("installing new crontab"); switch (replace_cmd()) { case 0: break; case -1: for (;;) { (void)fpurge(stdin); (void)printf("Do you want to retry the same edit? "); (void)fflush(stdout); q[0] = '\0'; (void) fgets(q, (int)sizeof(q), stdin); switch (q[0]) { case 'y': case 'Y': goto again; case 'n': case 'N': goto abandon; default: (void)printf("Enter Y or N\n"); } } /*NOTREACHED*/ case -2: abandon: warnx("edits left in `%s'", Filename); goto done; default: warnx("panic: bad switch() in replace_cmd()"); goto fatal; } remove: (void)unlink(Filename); done: log_it(RealUser, Pid, "END EDIT", User); }