X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=miscutils%2Fcrontab.c;h=76c382e8fa35eb90aac528c3ed896c8aafd41cb0;hb=27f79ff03d2b4614d013948d95a5bc697ec41962;hp=1acacc6766ac113206c6bf74b50373f670b24dd9;hpb=64d7e93081141cb6f1668436a5629a2304047f38;p=oweals%2Fbusybox.git diff --git a/miscutils/crontab.c b/miscutils/crontab.c index 1acacc676..76c382e8f 100644 --- a/miscutils/crontab.c +++ b/miscutils/crontab.c @@ -10,7 +10,7 @@ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */ -#include "busybox.h" +#include "libbb.h" #ifndef CRONTABS #define CRONTABS "/var/spool/cron/crontabs" @@ -22,315 +22,322 @@ #define CRONUPDATE "cron.update" #endif #ifndef PATH_VI -#define PATH_VI "/bin/vi" /* location of vi */ +#define PATH_VI "/bin/vi" /* location of vi */ #endif -static const char *CDir = CRONTABS; +static const char *CDir = CRONTABS; static void EditFile(const char *user, const char *file); static int GetReplaceStream(const char *user, const char *file); -static int ChangeUser(const char *user, short dochdir); +static int ChangeUser(const char *user, short dochdir); +int crontab_main(int ac, char **av); int crontab_main(int ac, char **av) { - enum { NONE, EDIT, LIST, REPLACE, DELETE } option = NONE; - const struct passwd *pas; - const char *repFile = NULL; - int repFd = 0; - int i; - char caller[256]; /* user that ran program */ - int UserId; - - UserId = getuid(); - if ((pas = getpwuid(UserId)) == NULL) - bb_perror_msg_and_die("getpwuid"); - - safe_strncpy(caller, pas->pw_name, sizeof(caller)); - - i = 1; - if (ac > 1) { - if (av[1][0] == '-' && av[1][1] == 0) { - option = REPLACE; - ++i; - } else if (av[1][0] != '-') { - option = REPLACE; - ++i; - repFile = av[1]; - } - } - - for (; i < ac; ++i) { - char *ptr = av[i]; - - if (*ptr != '-') - break; - ptr += 2; - - switch(ptr[-1]) { - case 'l': - if (ptr[-1] == 'l') - option = LIST; - /* fall through */ - case 'e': - if (ptr[-1] == 'e') - option = EDIT; - /* fall through */ - case 'd': - if (ptr[-1] == 'd') - option = DELETE; - /* fall through */ - case 'u': - if (i + 1 < ac && av[i+1][0] != '-') { - ++i; - if (getuid() == geteuid()) { - pas = getpwnam(av[i]); - if (pas) { - UserId = pas->pw_uid; - } else { - bb_error_msg_and_die("user %s unknown", av[i]); - } - } else { - bb_error_msg_and_die("only the superuser may specify a user"); + enum { NONE, EDIT, LIST, REPLACE, DELETE } option = NONE; + const struct passwd *pas; + const char *repFile = NULL; + int repFd = 0; + int i; + char caller[256]; /* user that ran program */ + char buf[1024]; + int UserId; + + UserId = getuid(); + pas = getpwuid(UserId); + if (pas == NULL) + bb_perror_msg_and_die("getpwuid"); + + safe_strncpy(caller, pas->pw_name, sizeof(caller)); + + i = 1; + if (ac > 1) { + if (LONE_DASH(av[1])) { + option = REPLACE; + ++i; + } else if (av[1][0] != '-') { + option = REPLACE; + ++i; + repFile = av[1]; } - } - break; - case 'c': - if (getuid() == geteuid()) { - CDir = (*ptr) ? ptr : av[++i]; - } else { - bb_error_msg_and_die("-c option: superuser only"); - } - break; - default: - i = ac; - break; } - } - if (i != ac || option == NONE) - bb_show_usage(); - - /* - * Get password entry - */ - - if ((pas = getpwuid(UserId)) == NULL) - bb_perror_msg_and_die("getpwuid"); - - /* - * If there is a replacement file, obtain a secure descriptor to it. - */ - - if (repFile) { - repFd = GetReplaceStream(caller, repFile); - if (repFd < 0) - bb_error_msg_and_die("unable to read replacement file"); - } - - /* - * Change directory to our crontab directory - */ - - xchdir(CDir); - - /* - * Handle options as appropriate - */ - - switch(option) { - case LIST: - { - FILE *fi; - char buf[1024]; - - if ((fi = fopen(pas->pw_name, "r"))) { - while (fgets(buf, sizeof(buf), fi) != NULL) - fputs(buf, stdout); - fclose(fi); - } else { - bb_error_msg("no crontab for %s", pas->pw_name); - } + + for (; i < ac; ++i) { + char *ptr = av[i]; + + if (*ptr != '-') + break; + ptr += 2; + + switch (ptr[-1]) { + case 'l': + if (ptr[-1] == 'l') + option = LIST; + /* fall through */ + case 'e': + if (ptr[-1] == 'e') + option = EDIT; + /* fall through */ + case 'd': + if (ptr[-1] == 'd') + option = DELETE; + /* fall through */ + case 'u': + if (i + 1 < ac && av[i+1][0] != '-') { + ++i; + if (getuid() == geteuid()) { + pas = getpwnam(av[i]); + if (pas) { + UserId = pas->pw_uid; + } else { + bb_error_msg_and_die("user %s unknown", av[i]); + } + } else { + bb_error_msg_and_die("only the superuser may specify a user"); + } + } + break; + case 'c': + if (getuid() == geteuid()) { + CDir = (*ptr) ? ptr : av[++i]; + } else { + bb_error_msg_and_die("-c option: superuser only"); + } + break; + default: + i = ac; + break; + } } - break; - case EDIT: - { - FILE *fi; - int fd; - int n; - char tmp[128]; - char buf[1024]; - - snprintf(tmp, sizeof(tmp), TMPDIR "/crontab.%d", getpid()); - fd = xopen3(tmp, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0600); - chown(tmp, getuid(), getgid()); - if ((fi = fopen(pas->pw_name, "r"))) { - while ((n = fread(buf, 1, sizeof(buf), fi)) > 0) - write(fd, buf, n); - } - EditFile(caller, tmp); - remove(tmp); - lseek(fd, 0L, 0); - repFd = fd; + if (i != ac || option == NONE) + bb_show_usage(); + + /* + * Get password entry + */ + + pas = getpwuid(UserId); + if (pas == NULL) + bb_perror_msg_and_die("getpwuid"); + + /* + * If there is a replacement file, obtain a secure descriptor to it. + */ + + if (repFile) { + repFd = GetReplaceStream(caller, repFile); + if (repFd < 0) + bb_error_msg_and_die("cannot read replacement file"); } - option = REPLACE; - /* fall through */ - case REPLACE: - { - char buf[1024]; - char path[1024]; - int fd; - int n; - - snprintf(path, sizeof(path), "%s.new", pas->pw_name); - if ((fd = open(path, O_CREAT|O_TRUNC|O_APPEND|O_WRONLY, 0600)) >= 0) { - while ((n = read(repFd, buf, sizeof(buf))) > 0) { - write(fd, buf, n); + + /* + * Change directory to our crontab directory + */ + + xchdir(CDir); + + /* + * Handle options as appropriate + */ + + switch (option) { + case LIST: + { + FILE *fi; + + fi = fopen(pas->pw_name, "r"); + if (fi) { + while (fgets(buf, sizeof(buf), fi) != NULL) + fputs(buf, stdout); + fclose(fi); + } else { + bb_error_msg("no crontab for %s", pas->pw_name); + } } - close(fd); - rename(path, pas->pw_name); - } else { - bb_error_msg("unable to create %s/%s", CDir, path); - } - close(repFd); - } - break; - case DELETE: - remove(pas->pw_name); - break; - case NONE: - default: - break; - } - - /* - * Bump notification file. Handle window where crond picks file up - * before we can write our entry out. - */ - - if (option == REPLACE || option == DELETE) { - FILE *fo; - struct stat st; - - while ((fo = fopen(CRONUPDATE, "a"))) { - fprintf(fo, "%s\n", pas->pw_name); - fflush(fo); - if (fstat(fileno(fo), &st) != 0 || st.st_nlink != 0) { - fclose(fo); break; - } - fclose(fo); - /* loop */ + case EDIT: + { +/* FIXME: messy code here! we have file copying helpers for this! */ + FILE *fi; + int fd; + int n; + char tmp[128]; + + snprintf(tmp, sizeof(tmp), TMPDIR "/crontab.%d", getpid()); + fd = xopen3(tmp, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0600); +/* race, use fchown */ + chown(tmp, getuid(), getgid()); + fi = fopen(pas->pw_name, "r"); + if (fi) { + while ((n = fread(buf, 1, sizeof(buf), fi)) > 0) + full_write(fd, buf, n); + } + EditFile(caller, tmp); + remove(tmp); + lseek(fd, 0L, SEEK_SET); + repFd = fd; + } + option = REPLACE; + /* fall through */ + case REPLACE: + { +/* same here */ + char path[1024]; + int fd; + int n; + + snprintf(path, sizeof(path), "%s.new", pas->pw_name); + fd = open(path, O_CREAT|O_TRUNC|O_APPEND|O_WRONLY, 0600); + if (fd >= 0) { + while ((n = read(repFd, buf, sizeof(buf))) > 0) { + full_write(fd, buf, n); + } + close(fd); + rename(path, pas->pw_name); + } else { + bb_error_msg("cannot create %s/%s", CDir, path); + } + close(repFd); + } + break; + case DELETE: + remove(pas->pw_name); + break; + case NONE: + default: + break; } - if (fo == NULL) { - bb_error_msg("unable to append to %s/%s", CDir, CRONUPDATE); + + /* + * Bump notification file. Handle window where crond picks file up + * before we can write our entry out. + */ + + if (option == REPLACE || option == DELETE) { + FILE *fo; + struct stat st; + + while ((fo = fopen(CRONUPDATE, "a"))) { + fprintf(fo, "%s\n", pas->pw_name); + fflush(fo); + if (fstat(fileno(fo), &st) != 0 || st.st_nlink != 0) { + fclose(fo); + break; + } + fclose(fo); + /* loop */ + } + if (fo == NULL) { + bb_error_msg("cannot append to %s/%s", CDir, CRONUPDATE); + } } - } - return 0; + return 0; } static int GetReplaceStream(const char *user, const char *file) { - int filedes[2]; - int pid; - int fd; - int n; - char buf[1024]; - - if (pipe(filedes) < 0) { - perror("pipe"); - return(-1); - } - if ((pid = fork()) < 0) { - perror("fork"); - return(-1); - } - if (pid > 0) { + int filedes[2]; + int pid; + int fd; + int n; + char buf[1024]; + + if (pipe(filedes) < 0) { + perror("pipe"); + return -1; + } + pid = fork(); + if (pid < 0) { + perror("fork"); + return -1; + } + if (pid > 0) { + /* + * PARENT + */ + + close(filedes[1]); + if (read(filedes[0], buf, 1) != 1) { + close(filedes[0]); + filedes[0] = -1; + } + return filedes[0]; + } + /* - * PARENT + * CHILD */ - close(filedes[1]); - if (read(filedes[0], buf, 1) != 1) { - close(filedes[0]); - filedes[0] = -1; - } - return(filedes[0]); - } - - /* - * CHILD - */ + close(filedes[0]); - close(filedes[0]); + if (ChangeUser(user, 0) < 0) + exit(0); - if (ChangeUser(user, 0) < 0) + xfunc_error_retval = 0; + fd = xopen(file, O_RDONLY); + buf[0] = 0; + write(filedes[1], buf, 1); + while ((n = read(fd, buf, sizeof(buf))) > 0) { + write(filedes[1], buf, n); + } exit(0); - - bb_default_error_retval = 0; - fd = xopen(file, O_RDONLY); - buf[0] = 0; - write(filedes[1], buf, 1); - while ((n = read(fd, buf, sizeof(buf))) > 0) { - write(filedes[1], buf, n); - } - exit(0); } static void EditFile(const char *user, const char *file) { - int pid; + int pid = fork(); + + if (pid == 0) { + /* + * CHILD - change user and run editor + */ + const char *ptr; + + if (ChangeUser(user, 1) < 0) + exit(0); + ptr = getenv("VISUAL"); + if (ptr == NULL || strlen(ptr) > 256) + ptr = PATH_VI; + + ptr = xasprintf("%s %s", ptr, file); + execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", ptr, NULL); + bb_perror_msg_and_die("exec"); + } + if (pid < 0) { + /* + * PARENT - failure + */ + bb_perror_msg_and_die("fork"); + } + wait4(pid, NULL, 0, NULL); +} + +static int ChangeUser(const char *user, short dochdir) +{ + struct passwd *pas; - if ((pid = fork()) == 0) { /* - * CHILD - change user and run editor + * Obtain password entry and change privileges */ - char *ptr; - char visual[1024]; - if (ChangeUser(user, 1) < 0) - exit(0); - if ((ptr = getenv("VISUAL")) == NULL || strlen(ptr) > 256) - ptr = PATH_VI; + pas = getpwnam(user); + if (pas == NULL) { + bb_perror_msg_and_die("failed to get uid for %s", user); + } + setenv("USER", pas->pw_name, 1); + setenv("HOME", pas->pw_dir, 1); + setenv("SHELL", DEFAULT_SHELL, 1); - snprintf(visual, sizeof(visual), "%s %s", ptr, file); - execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", visual, NULL); - perror("exec"); - exit(0); - } - if (pid < 0) { /* - * PARENT - failure + * Change running state to the user in question */ - bb_perror_msg_and_die("fork"); - } - wait4(pid, NULL, 0, NULL); -} + change_identity(pas); -static int ChangeUser(const char *user, short dochdir) -{ - struct passwd *pas; - - /* - * Obtain password entry and change privileges - */ - - if ((pas = getpwnam(user)) == NULL) { - bb_perror_msg_and_die("failed to get uid for %s", user); - return(-1); - } - setenv("USER", pas->pw_name, 1); - setenv("HOME", pas->pw_dir, 1); - setenv("SHELL", DEFAULT_SHELL, 1); - - /* - * Change running state to the user in question - */ - change_identity(pas); - - if (dochdir) { - if (chdir(pas->pw_dir) < 0) { - bb_perror_msg("chdir failed: %s %s", user, pas->pw_dir); - xchdir(TMPDIR); + if (dochdir) { + if (chdir(pas->pw_dir) < 0) { + bb_perror_msg("chdir(%s) by %s failed", pas->pw_dir, user); + xchdir(TMPDIR); + } } - } - return(pas->pw_uid); + return pas->pw_uid; }