static int route_adddel(struct main_server_st* s, proc_st *proc, const char* pattern, const char* route, const char* dev) { int ret; char *cmd = NULL; if (pattern == 0) { mslog(s, NULL, LOG_WARNING, "route-add-cmd or route-del-cmd are not set."); return 0; } ret = replace_cmd(s, proc, &cmd, pattern, route, dev); if (ret < 0) return ret; ret = call_script(s, proc, cmd); if (ret < 0) { int e = errno; mslog(s, NULL, LOG_INFO, "failed to spawn cmd: %s: %s", cmd, strerror(e)); ret = ERR_EXEC; goto fail; } ret = 0; fail: talloc_free(cmd); return ret; }
int main(int argc, char *argv[]) { int exitstatus; setprogname(argv[0]); Pid = getpid(); (void)setlocale(LC_ALL, ""); euid = geteuid(); egid = getegid(); ruid = getuid(); rgid = getgid(); if (euid == ruid && ruid != 0) errx(ERROR_EXIT, "Not installed setuid root"); (void)setvbuf(stderr, NULL, _IOLBF, 0); parse_args(argc, argv); /* sets many globals, opens a file */ set_cron_cwd(); if (!allowed(RealUser, CRON_ALLOW, CRON_DENY)) { (void)fprintf(stderr, "You `%s' are not allowed to use this program `%s'\n", User, getprogname()); (void)fprintf(stderr, "See crontab(1) for more information\n"); log_it(RealUser, Pid, "AUTH", "crontab command not allowed"); exit(ERROR_EXIT); } exitstatus = OK_EXIT; switch (Option) { case opt_unknown: usage("unrecognized option"); exitstatus = ERROR_EXIT; break; case opt_list: list_cmd(); break; case opt_delete: delete_cmd(); break; case opt_edit: edit_cmd(); break; case opt_replace: if (replace_cmd() < 0) exitstatus = ERROR_EXIT; break; default: abort(); } exit(exitstatus); /*NOTREACHED*/ }
int main (int argc, char *argv[]) { int exitstatus; char *config_file; /* Name of our configuration file; NULL if none */ Pid = getpid (); ProgramName = argv[0]; #if defined(POSIX) setlocale (LC_ALL, ""); #endif #if HAVE_SETLINEBUF setlinebuf (stderr); #endif /*HAVE_SETLINEBUF */ parse_args (argc, argv, &config_file); /* sets many globals, opens a file */ read_config (config_file, &allow_only_root, &log_syslog, &allow_file, &deny_file, &crondir, &spool_dir, &log_file, &syscrontab, &lastrun_file, &pidfile, &mailprog, &mailargs); set_cron_cwd (); if (!allowed (User)) { fprintf (stderr, "You (%s) are not allowed to use this program (%s)\n", User, ProgramName); fprintf (stderr, "See crontab(1) for more information\n"); log_it (RealUser, Pid, "AUTH", "crontab command not allowed"); exit (ERROR_EXIT); } exitstatus = OK_EXIT; switch (Option) { case opt_list: list_cmd (); break; case opt_delete: delete_cmd (); break; case opt_edit: edit_cmd (); break; case opt_replace: if (replace_cmd () < 0) exitstatus = ERROR_EXIT; break; } exit (0); /*NOTREACHED*/}
int main(int argc, char *argv[]) { int exitstatus; Pid = getpid(); ProgramName = argv[0]; #if defined(POSIX) setlocale(LC_ALL, ""); #endif #if defined(BSD) setlinebuf(stderr); #endif parse_args(argc, argv); /* sets many globals, opens a file */ set_cron_uid(); set_cron_cwd(); if (!allowed(User)) { warnx("you (%s) are not allowed to use this program", User); log_it(RealUser, Pid, "AUTH", "crontab command not allowed"); exit(ERROR_EXIT); } exitstatus = OK_EXIT; switch (Option) { case opt_list: list_cmd(); break; case opt_delete: delete_cmd(); break; case opt_edit: edit_cmd(); break; case opt_replace: if (replace_cmd() < 0) exitstatus = ERROR_EXIT; break; case opt_unknown: break; } exit(exitstatus); /*NOTREACHED*/ }
static void edit_cmd (void) { char n[MAX_FNAME], q[MAX_TEMPSTR], *editor; FILE *f; int t; struct stat statbuf; time_t mtime; WAIT_T waiter; pid_t pid, xpid; log_it (RealUser, Pid, "BEGIN EDIT", User); (void) snprintf (n, MAX_FNAME, CRON_TAB (User)); if (!(f = fopen (n, "r"))) { if (errno != ENOENT) { perror (n); exit (ERROR_EXIT); } fprintf (stderr, "no crontab for %s - using an empty one\n", User); if (!(f = fopen ("/dev/null", "r"))) { perror ("/dev/null"); exit (ERROR_EXIT); } } /* swap uids for the open so that the temporary file we create to edit will be properly owned so that our unprivileged child can edit it. */ if (swap_uids () < OK) { perror ("swapping uids"); exit (ERROR_EXIT); } (void) snprintf (Filename, MAX_FNAME, "/tmp/crontab.%d", Pid); if (-1 == (t = open (Filename, O_CREAT | O_EXCL | O_RDWR, 0600))) { perror (Filename); goto fatal; } if (swap_uids () < OK) { perror ("swapping uids back"); exit (ERROR_EXIT); } if (!(NewCrontab = fdopen (t, "r+"))) { perror ("fdopen"); goto fatal; } while (!feof (f) && !ferror (f)) { char line[80 + 1]; char *retval; retval = fgets (line, sizeof (line), f); if (retval != NULL) { if (strncmp (line, "#CRONTAB", sizeof ("#CRONTAB") - 1) == 0) { /* We have a comment generated by this program, so ignore the entire line. */ while (!feof (f) && !ferror (f) && line[strlen (line) - 1] != '\n') fgets (line, sizeof (line), f); } else { /* It's a regular line; copy it over */ fputs (line, NewCrontab); } } } fclose (f); if (fflush (NewCrontab) < OK) { perror (Filename); exit (ERROR_EXIT); } again: rewind (NewCrontab); if (ferror (NewCrontab)) { fprintf (stderr, "%s: error while writing new crontab to %s\n", ProgramName, Filename); fatal:remove_editor_file (Filename); exit (ERROR_EXIT); } if (fstat (t, &statbuf) < 0) { perror ("fstat"); goto fatal; } mtime = statbuf.st_mtime; if ((!(editor = getenv ("VISUAL"))) && (!(editor = getenv ("EDITOR")))) { 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: perror ("fork"); goto fatal; case 0: /* child */ if (setuid (getuid ()) < 0) { perror ("setuid(getuid())"); exit (ERROR_EXIT); } if (chdir ("/tmp") < 0) { perror ("chdir(/tmp)"); exit (ERROR_EXIT); } if (strlen (editor) + strlen (Filename) + 2 >= MAX_TEMPSTR) { fprintf (stderr, "%s: editor or filename too long\n", ProgramName); exit (ERROR_EXIT); } snprintf (q, MAX_TEMPSTR, "%s %s", editor, Filename); execlp (_PATH_BSHELL, _PATH_BSHELL, "-c", q, NULL); perror (editor); exit (ERROR_EXIT); /*NOTREACHED*/ default: /* parent */ break; } /* parent */ xpid = wait (&waiter); if (xpid != pid) { fprintf (stderr, "%s: wrong PID (%d != %d) from \"%s\"\n", ProgramName, xpid, pid, editor); goto fatal; } if (WIFEXITED (waiter) && WEXITSTATUS (waiter)) { fprintf (stderr, "%s: \"%s\" exited with status %d\n", ProgramName, editor, WEXITSTATUS (waiter)); goto fatal; } if (WIFSIGNALED (waiter)) { fprintf (stderr, "%s: \"%s\" killed; signal %d (%score dumped)\n", ProgramName, editor, WTERMSIG (waiter), WCOREDUMP (waiter) ? "" : "no "); goto fatal; } if (fstat (t, &statbuf) < 0) { perror ("fstat"); goto fatal; } if (mtime == statbuf.st_mtime) { fprintf (stderr, "%s: no changes made to crontab\n", ProgramName); } else { fprintf (stderr, "%s: installing new crontab\n", ProgramName); switch (replace_cmd ()) { case 0: break; case -1: for (;;) { printf ("Do you want to retry the same edit? "); fflush (stdout); q[0] = '\0'; (void) fgets (q, sizeof q, stdin); switch (islower (q[0]) ? q[0] : tolower (q[0])) { case 'y': goto again; case 'n': goto abandon; default: fprintf (stderr, "Enter Y or N\n"); } } /*NOTREACHED*/ case -2: abandon: fprintf (stderr, "%s: edits left in %s\n", ProgramName, Filename); goto done; default: fprintf (stderr, "%s: panic: bad switch() in replace_cmd()\n", ProgramName); goto fatal; } } remove_editor_file (Filename); done: log_it (RealUser, Pid, "END EDIT", User); }
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); }
struct list *complete(const char *cmd, const char *input) { /* resouces that must be released */ char *line = NULL; struct list *list = NULL; FILE *fh = NULL; int fds[2]; if (pipe(fds)) return NULL; pid_t pid = fork(); if (pid < -1) goto error; /* child */ if (pid == 0) { dup2(fds[1], 1); close(fds[0]); execl("/bin/sh", "sh", "-c", replace_cmd(cmd, "%s", input), NULL); exit(1); } /* parent */ close(fds[1]); list = malloc(sizeof(struct list)); if (list == NULL) goto error; list->head = list->tail = list->cur = NULL; fh = fdopen(fds[0], "r"); if (fh == NULL) goto error; ssize_t len; size_t size = 0; while ((len = getline(&line, &size, fh)) > 0) { struct node *node = malloc(sizeof(struct node)); if (node == NULL) goto error; if (isspace(line[len - 1])) line[len - 1] = 0; node->name = strdup(line); node->next = NULL; if (list->head == NULL) { list->head = list->tail = node; } else { list->tail->next = node; list->tail = node; } } int status = 0; waitpid(pid, &status, 0); if (WEXITSTATUS(status)) { free_list(list); list = NULL; } exit: if (fh) fclose(fh); close(fds[0]); free(line); return list; error: printf("Error\n"); free_list(list); list = NULL; goto exit; }