Module Name: src Committed By: christos Date: Fri Jun 9 17:36:30 UTC 2017
Modified Files: src/external/bsd/cron/bin/cron: Makefile src/external/bsd/cron/bin/crontab: Makefile src/external/bsd/cron/dist: Makefile config.h cron.c crontab.c database.c do_command.c funcs.h misc.c popen.c Added Files: src/external/bsd/cron/dist: closeall.c pam_auth.c Log Message: Apply selected patches from OpenWall: http://cvsweb.openwall.com/cgi/cvsweb.cgi/Owl/packages/vixie-cron/ 1. Add PAM support. 2. Sanitize children process reaping 3. futimens when we have an fd 4. close_all for crontab(8) 5. use a table for spool dirs instead of duplicating code. 6. handle errors from process_exit() 7. Add ENABLE_FIX_DIRECTORIES ifdef and enable it by default for compat 8. Avoid using fd's < STDERR Not applied: 1. no xfork (no setresuid) 2. did not do the lstat before open. 3. did not enable cron group To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/external/bsd/cron/bin/cron/Makefile cvs rdiff -u -r1.2 -r1.3 src/external/bsd/cron/bin/crontab/Makefile cvs rdiff -u -r1.2 -r1.3 src/external/bsd/cron/dist/Makefile cvs rdiff -u -r0 -r1.1 src/external/bsd/cron/dist/closeall.c \ src/external/bsd/cron/dist/pam_auth.c cvs rdiff -u -r1.4 -r1.5 src/external/bsd/cron/dist/config.h \ src/external/bsd/cron/dist/popen.c cvs rdiff -u -r1.9 -r1.10 src/external/bsd/cron/dist/cron.c cvs rdiff -u -r1.13 -r1.14 src/external/bsd/cron/dist/crontab.c cvs rdiff -u -r1.8 -r1.9 src/external/bsd/cron/dist/database.c cvs rdiff -u -r1.7 -r1.8 src/external/bsd/cron/dist/do_command.c cvs rdiff -u -r1.3 -r1.4 src/external/bsd/cron/dist/funcs.h \ src/external/bsd/cron/dist/misc.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/external/bsd/cron/bin/cron/Makefile diff -u src/external/bsd/cron/bin/cron/Makefile:1.3 src/external/bsd/cron/bin/cron/Makefile:1.4 --- src/external/bsd/cron/bin/cron/Makefile:1.3 Fri Jun 22 16:32:34 2012 +++ src/external/bsd/cron/bin/cron/Makefile Fri Jun 9 13:36:29 2017 @@ -1,11 +1,12 @@ -# $NetBSD: Makefile,v 1.3 2012/06/22 20:32:34 abs Exp $ +# $NetBSD: Makefile,v 1.4 2017/06/09 17:36:29 christos Exp $ BINDIR= /usr/sbin PROG= cron SRCS= cron.c database.c do_command.c entry.c env.c job.c \ - misc.c popen.c pw_dup.c user.c -CPPFLAGS+=-I${.CURDIR} -DLOGIN_CAP -LDADD+=-lutil + misc.c pam_auth.c popen.c pw_dup.c user.c +CPPFLAGS+=-I${.CURDIR} -DLOGIN_CAP -DUSE_PAM +DPADD+=${LIBPAM} ${LIBUTIL} +LDADD+=-lpam -lutil MAN= cron.8 CWARNFLAGS.clang+= -Wno-string-plus-int Index: src/external/bsd/cron/bin/crontab/Makefile diff -u src/external/bsd/cron/bin/crontab/Makefile:1.2 src/external/bsd/cron/bin/crontab/Makefile:1.3 --- src/external/bsd/cron/bin/crontab/Makefile:1.2 Fri May 7 17:54:07 2010 +++ src/external/bsd/cron/bin/crontab/Makefile Fri Jun 9 13:36:29 2017 @@ -1,10 +1,10 @@ -# $NetBSD: Makefile,v 1.2 2010/05/07 21:54:07 christos Exp $ +# $NetBSD: Makefile,v 1.3 2017/06/09 17:36:29 christos Exp $ .include <bsd.own.mk> USE_FORT?= yes # setuid PROG= crontab -SRCS= crontab.c misc.c entry.c env.c pw_dup.c +SRCS= crontab.c misc.c entry.c env.c pw_dup.c closeall.c CPPFLAGS+=-I${.CURDIR} -DDEBUGGING=1 BINOWN =root BINMODE=4555 Index: src/external/bsd/cron/dist/Makefile diff -u src/external/bsd/cron/dist/Makefile:1.2 src/external/bsd/cron/dist/Makefile:1.3 --- src/external/bsd/cron/dist/Makefile:1.2 Thu May 6 14:53:17 2010 +++ src/external/bsd/cron/dist/Makefile Fri Jun 9 13:36:30 2017 @@ -86,14 +86,14 @@ MANPAGES = bitstring.3 crontab.5 crontab HEADERS = bitstring.h cron.h config.h pathnames.h externs.h \ macros.h structs.h funcs.h globals.h SOURCES = cron.c crontab.c database.c do_command.c entry.c \ - env.c job.c user.c popen.c misc.c pw_dup.c + env.c job.c user.c popen.c misc.c pam_auth.c pw_dup.c SHAR_SOURCE = $(INFOS) $(MANPAGES) Makefile $(HEADERS) $(SOURCES) LINT_CRON = cron.c database.c user.c entry.c \ misc.c job.c do_command.c env.c popen.c pw_dup.c LINT_CRONTAB = crontab.c misc.c entry.c env.c CRON_OBJ = cron.o database.o user.o entry.o job.o do_command.o \ misc.o env.o popen.o pw_dup.o -CRONTAB_OBJ = crontab.o misc.o entry.o env.o pw_dup.o +CRONTAB_OBJ = crontab.o misc.o entry.o env.o pw_dup.o closeall.o all : cron crontab Index: src/external/bsd/cron/dist/config.h diff -u src/external/bsd/cron/dist/config.h:1.4 src/external/bsd/cron/dist/config.h:1.5 --- src/external/bsd/cron/dist/config.h:1.4 Sat Nov 3 11:39:23 2012 +++ src/external/bsd/cron/dist/config.h Fri Jun 9 13:36:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: config.h,v 1.4 2012/11/03 15:39:23 christos Exp $ */ +/* $NetBSD: config.h,v 1.5 2017/06/09 17:36:30 christos Exp $ */ /* Copyright 1988,1990,1993,1994 by Paul Vixie * All rights reserved @@ -94,6 +94,7 @@ #define HAVE_FCHOWN /*-*/ #define HAVE_UTIMES /*-*/ #define HAVE_UTIMENSAT +#define HAVE_FUTIMENS #define _INCOMPLETE_XOPEN_C063 /* if your OS supports a BSD-style login.conf file */ @@ -108,6 +109,11 @@ * If this is not defined then crontab and at * must be setuid root. */ + /* if your os supports PAM authentication */ +/*#define USE_PAM */ + /*#define CRON_GROUP "crontab" */ +#define ENABLE_FIX_DIRECTORIES + #define MAXTABSIZE_DEFAULT (1024*256) Index: src/external/bsd/cron/dist/popen.c diff -u src/external/bsd/cron/dist/popen.c:1.4 src/external/bsd/cron/dist/popen.c:1.5 --- src/external/bsd/cron/dist/popen.c:1.4 Fri Sep 5 17:32:37 2014 +++ src/external/bsd/cron/dist/popen.c Fri Jun 9 13:36:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: popen.c,v 1.4 2014/09/05 21:32:37 christos Exp $ */ +/* $NetBSD: popen.c,v 1.5 2017/06/09 17:36:30 christos Exp $ */ /* * Copyright (c) 1988, 1993, 1994 @@ -44,7 +44,7 @@ static sccsid[] = "@(#)popen.c 8.3 (Berkeley) 4/6/94"; static char rcsid[] = "Id: popen.c,v 1.6 2003/02/16 04:40:01 vixie Exp"; #else -__RCSID("$NetBSD: popen.c,v 1.4 2014/09/05 21:32:37 christos Exp $"); +__RCSID("$NetBSD: popen.c,v 1.5 2017/06/09 17:36:30 christos Exp $"); #endif #endif /* not lint */ @@ -121,6 +121,11 @@ cron_popen(char *program, const char *ty _exit(ERROR_EXIT); } #endif /* BSD */ +#ifdef USE_PAM + if (!cron_pam_setcred()) + _exit(1); + cron_pam_child_close(); +#endif if (setuid(pw->pw_uid)) { warn("unable to set uid for %s", pw->pw_name); _exit(ERROR_EXIT); Index: src/external/bsd/cron/dist/cron.c diff -u src/external/bsd/cron/dist/cron.c:1.9 src/external/bsd/cron/dist/cron.c:1.10 --- src/external/bsd/cron/dist/cron.c:1.9 Sun Sep 7 09:34:12 2014 +++ src/external/bsd/cron/dist/cron.c Fri Jun 9 13:36:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: cron.c,v 1.9 2014/09/07 13:34:12 joerg Exp $ */ +/* $NetBSD: cron.c,v 1.10 2017/06/09 17:36:30 christos Exp $ */ /* Copyright 1988,1990,1993,1994 by Paul Vixie * All rights reserved @@ -25,7 +25,7 @@ #if 0 static char rcsid[] = "Id: cron.c,v 1.12 2004/01/23 18:56:42 vixie Exp"; #else -__RCSID("$NetBSD: cron.c,v 1.9 2014/09/07 13:34:12 joerg Exp $"); +__RCSID("$NetBSD: cron.c,v 1.10 2017/06/09 17:36:30 christos Exp $"); #endif #endif @@ -511,11 +511,10 @@ quit(int x __unused) { static void sigchld_reaper(void) { - WAIT_T waiter; - PID_T pid; + for (;;) { + WAIT_T waiter; + PID_T pid = waitpid(-1, &waiter, WNOHANG); - do { - pid = waitpid(-1, &waiter, WNOHANG); switch (pid) { case -1: if (errno == EINTR) @@ -523,19 +522,19 @@ sigchld_reaper(void) { Debug(DPROC, ("[%ld] sigchld...no children\n", (long)getpid())); - break; + return; case 0: Debug(DPROC, ("[%ld] sigchld...no dead kids\n", (long)getpid())); - break; + return; default: Debug(DPROC, ("[%ld] sigchld...pid #%ld died, stat=%d\n", (long)getpid(), (long)pid, WEXITSTATUS(waiter))); break; } - } while (pid > 0); + } } static void Index: src/external/bsd/cron/dist/crontab.c diff -u src/external/bsd/cron/dist/crontab.c:1.13 src/external/bsd/cron/dist/crontab.c:1.14 --- src/external/bsd/cron/dist/crontab.c:1.13 Sun Jan 4 13:45:17 2015 +++ src/external/bsd/cron/dist/crontab.c Fri Jun 9 13:36:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: crontab.c,v 1.13 2015/01/04 18:45:17 joerg Exp $ */ +/* $NetBSD: crontab.c,v 1.14 2017/06/09 17:36:30 christos Exp $ */ /* Copyright 1988,1990,1993,1994 by Paul Vixie * All rights reserved @@ -25,7 +25,7 @@ #if 0 static char rcsid[] = "Id: crontab.c,v 1.12 2004/01/23 18:56:42 vixie Exp"; #else -__RCSID("$NetBSD: crontab.c,v 1.13 2015/01/04 18:45:17 joerg Exp $"); +__RCSID("$NetBSD: crontab.c,v 1.14 2017/06/09 17:36:30 christos Exp $"); #endif #endif @@ -429,7 +429,11 @@ edit_cmd(void) { if (fflush(NewCrontab) < OK) { err(ERROR_EXIT, "cannot flush output for `%s'", Filename); } +#ifdef HAVE_FUTIMENS + if (futimens(t, ts) == -1) +#else if (change_time(Filename, ts) == -1) +#endif err(ERROR_EXIT, "cannot set time info for `%s'", Filename); again: rewind(NewCrontab); @@ -465,6 +469,9 @@ edit_cmd(void) { if (setuid(MY_UID(pw)) < 0) { err(ERROR_EXIT, "cannot setuid(getuid())"); } + if (close_all(3)) { + err(ERROR_EXIT, "cannot close files"); + } if (chdir(_PATH_TMP) < 0) { err(ERROR_EXIT, "cannot chdir to `%s'", _PATH_TMP); } @@ -682,7 +689,7 @@ replace_cmd(void) { "# (%s installed on %-24.24s)\n", Filename, ctime(&now)); (void)fprintf(tmp, "# (Cron version %s -- %s)\n", CRON_VERSION, - "$NetBSD: crontab.c,v 1.13 2015/01/04 18:45:17 joerg Exp $"); + "$NetBSD: crontab.c,v 1.14 2017/06/09 17:36:30 christos Exp $"); /* copy the crontab to the tmp */ Index: src/external/bsd/cron/dist/database.c diff -u src/external/bsd/cron/dist/database.c:1.8 src/external/bsd/cron/dist/database.c:1.9 --- src/external/bsd/cron/dist/database.c:1.8 Mon Dec 24 14:30:46 2012 +++ src/external/bsd/cron/dist/database.c Fri Jun 9 13:36:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: database.c,v 1.8 2012/12/24 19:30:46 christos Exp $ */ +/* $NetBSD: database.c,v 1.9 2017/06/09 17:36:30 christos Exp $ */ /* Copyright 1988,1990,1993,1994 by Paul Vixie * All rights reserved @@ -25,7 +25,7 @@ #if 0 static char rcsid[] = "Id: database.c,v 1.7 2004/01/23 18:56:42 vixie Exp"; #else -__RCSID("$NetBSD: database.c,v 1.8 2012/12/24 19:30:46 christos Exp $"); +__RCSID("$NetBSD: database.c,v 1.9 2017/06/09 17:36:30 christos Exp $"); #endif #endif @@ -36,16 +36,33 @@ __RCSID("$NetBSD: database.c,v 1.8 2012/ #define TMAX(a,b) ((a)>(b)?(a):(b)) +struct spooldir { + const char *path; + const char *uname; + const char *fname; + struct stat st; +}; + +static struct spooldir spools[] = { + { .path = SPOOL_DIR, }, + { .path = CROND_DIR, .uname = "root", .fname = "*system*", }, + { .path = NULL, } +}; + static void process_crontab(const char *, const char *, const char *, struct stat *, cron_db *, cron_db *); static void -process_dir(const char *dname, struct stat *st, int sys, cron_db *new_db, - cron_db *old_db) +process_dir(struct spooldir *sp, cron_db *new_db, cron_db *old_db) { DIR *dir; DIR_T *dp; + const char *dname = sp->path; + struct stat *st = &sp->st; + + if (st->st_mtime == 0) + return; /* we used to keep this dir open all the time, for the sake of * efficiency. however, we need to close it in every fork, and @@ -109,40 +126,41 @@ process_dir(const char *dname, struct st continue; } - process_crontab(sys ? "root" : fname, sys ? "*system*" : - fname, tabname, st, new_db, old_db); + process_crontab(sp->uname ? sp->uname : fname, + sp->fname ? sp->fname : fname, + tabname, st, new_db, old_db); } (void)closedir(dir); } void load_database(cron_db *old_db) { - struct stat spool_stat, syscron_stat, crond_stat; + struct stat syscron_stat; cron_db new_db; user *u, *nu; - time_t new_mtime; + time_t maxtime; Debug(DLOAD, ("[%ld] load_database()\n", (long)getpid())); - /* before we start loading any data, do a stat on SPOOL_DIR - * so that if anything changes as of this moment (i.e., before we've - * cached any of the database), we'll see the changes next time. - */ - if (stat(SPOOL_DIR, &spool_stat) < OK) { - log_it("CRON", getpid(), "STAT FAILED", SPOOL_DIR); - (void) exit(ERROR_EXIT); - } - - /* track system crontab directory - */ - if (stat(CROND_DIR, &crond_stat) < OK) - crond_stat.st_mtime = 0; - /* track system crontab file */ if (stat(SYSCRONTAB, &syscron_stat) < OK) syscron_stat.st_mtime = 0; + maxtime = syscron_stat.st_mtime; + for (struct spooldir *p = spools; p->path; p++) { + if (stat(p->path, &p->st) < OK) { + if (errno == ENOENT) { + p->st.st_mtime = 0; + continue; + } + log_it("CRON", getpid(), "STAT FAILED", p->path); + (void) exit(ERROR_EXIT); + } + if (p->st.st_mtime > maxtime) + maxtime = p->st.st_mtime; + } + /* if spooldir's mtime has not changed, we don't need to fiddle with * the database. * @@ -150,9 +168,7 @@ load_database(cron_db *old_db) { * so is guaranteed to be different than the stat() mtime the first * time this function is called. */ - new_mtime = TMAX(crond_stat.st_mtime, TMAX(spool_stat.st_mtime, - syscron_stat.st_mtime)); - if (old_db->mtime == new_mtime) { + if (old_db->mtime == maxtime) { Debug(DLOAD, ("[%ld] spool dir mtime unch, no load needed.\n", (long)getpid())); return; @@ -163,17 +179,15 @@ load_database(cron_db *old_db) { * actually changed. Whatever is left in the old database when * we're done is chaff -- crontabs that disappeared. */ - new_db.mtime = new_mtime; + new_db.mtime = maxtime; new_db.head = new_db.tail = NULL; if (syscron_stat.st_mtime) - process_crontab("root", NULL, SYSCRONTAB, &syscron_stat, - &new_db, old_db); - - if (crond_stat.st_mtime) - process_dir(CROND_DIR, &crond_stat, 1, &new_db, old_db); + process_crontab("root", "*system*", SYSCRONTAB, + &syscron_stat, &new_db, old_db); - process_dir(SPOOL_DIR, &spool_stat, 0, &new_db, old_db); + for (struct spooldir *p = spools; p->path; p++) + process_dir(p, &new_db, old_db); /* if we don't do this, then when our children eventually call * getpwnam() in do_command.c's child_process to verify MAILTO=, @@ -240,14 +254,12 @@ process_crontab(const char *uname, const mode_t eqmode = 0400, badmode = 0; user *u; - if (fname == NULL) { + if (strcmp(fname, "*system*") == 0) { /* * SYSCRONTAB: - * set fname to something for logging purposes. * Allow it to become readable by group and others, but * not writable. */ - fname = "*system*"; eqmode = 0; badmode = 022; } else if ((pw = getpwnam(uname)) == NULL) { Index: src/external/bsd/cron/dist/do_command.c diff -u src/external/bsd/cron/dist/do_command.c:1.7 src/external/bsd/cron/dist/do_command.c:1.8 --- src/external/bsd/cron/dist/do_command.c:1.7 Thu Dec 17 17:36:48 2015 +++ src/external/bsd/cron/dist/do_command.c Fri Jun 9 13:36:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: do_command.c,v 1.7 2015/12/17 22:36:48 christos Exp $ */ +/* $NetBSD: do_command.c,v 1.8 2017/06/09 17:36:30 christos Exp $ */ /* Copyright 1988,1990,1993,1994 by Paul Vixie * All rights reserved @@ -25,18 +25,20 @@ #if 0 static char rcsid[] = "Id: do_command.c,v 1.9 2004/01/23 18:56:42 vixie Exp"; #else -__RCSID("$NetBSD: do_command.c,v 1.7 2015/12/17 22:36:48 christos Exp $"); +__RCSID("$NetBSD: do_command.c,v 1.8 2017/06/09 17:36:30 christos Exp $"); #endif #endif #include "cron.h" #include <unistd.h> -static void child_process(entry *); +static int child_process(entry *); static int safe_p(const char *, const char *); void do_command(entry *e, user *u) { + int retval; + Debug(DPROC, ("[%ld] do_command(%s, (%s,%ld,%ld))\n", (long)getpid(), e->cmd, u->name, (long)e->pwd->pw_uid, (long)e->pwd->pw_gid)); @@ -55,10 +57,10 @@ do_command(entry *e, user *u) { case 0: /* child process */ acquire_daemonlock(1); - child_process(e); - Debug(DPROC, ("[%ld] child process done, exiting\n", - (long)getpid())); - _exit(OK_EXIT); + retval = child_process(e); + Debug(DPROC, ("[%ld] child process done (rc=%d), exiting\n", + (long)getpid(), retval)); + _exit(retval); break; default: /* parent process */ @@ -68,11 +70,32 @@ do_command(entry *e, user *u) { } static void +sigchld_handler(int signo) { + for (;;) { + WAIT_T waiter; + PID_T pid = waitpid(-1, &waiter, WNOHANG); + + switch (pid) { + case -1: + if (errno == EINTR) + continue; + case 0: + return; + default: + break; + } + } +} + +extern char **environ; +static int child_process(entry *e) { int stdin_pipe[2], stdout_pipe[2]; char * volatile input_data; char *homedir, *usernm, * volatile mailto; - int children = 0; + struct sigaction sact; + char **envp = e->envp; + int retval = OK_EXIT; Debug(DPROC, ("[%ld] child_process('%s')\n", (long)getpid(), e->cmd)); @@ -81,14 +104,16 @@ child_process(entry *e) { /* discover some useful and important environment settings */ usernm = e->pwd->pw_name; - mailto = env_get("MAILTO", e->envp); + mailto = env_get("MAILTO", envp); - /* our parent is watching for our death by catching SIGCHLD. we - * do not care to watch for our children's deaths this way -- we - * use wait() explicitly. so we have to reset the signal (which - * was inherited from the parent). - */ - (void) signal(SIGCHLD, SIG_DFL); + memset(&sact, 0, sizeof(sact)); + sigemptyset(&sact.sa_mask); + sact.sa_flags = 0; +#ifdef SA_RESTART + sact.sa_flags |= SA_RESTART; +#endif + sact.sa_handler = sigchld_handler; + (void) sigaction(SIGCHLD, &sact, NULL); /* create some pipes to talk to our future child */ @@ -142,12 +167,22 @@ child_process(entry *e) { *p = '\0'; } +#ifdef USE_PAM + if (!cron_pam_start(usernm)) + return ERROR_EXIT; + + if (!(envp = cron_pam_getenvlist(envp))) { + retval = ERROR_EXIT; + goto child_process_end; + } +#endif + /* fork again, this time so we can exec the user's command. */ switch (vfork()) { case -1: - log_it("CRON", getpid(), "error", "can't vfork"); - exit(ERROR_EXIT); + retval = ERROR_EXIT; + goto child_process_end; /*NOTREACHED*/ case 0: Debug(DPROC, ("[%ld] grandchild process vfork()'ed\n", @@ -236,9 +271,9 @@ child_process(entry *e) { * we just added one via login.conf, add it to * the crontab environment. */ - if (env_get("PATH", e->envp) == NULL) { + if (env_get("PATH", envp) == NULL && environ != NULL) { if ((p = getenv("PATH")) != NULL) - e->envp = env_set(e->envp, p); + envp = env_set(envp, p); } } #else @@ -259,6 +294,11 @@ child_process(entry *e) { _exit(ERROR_EXIT); } #endif /* BSD */ +#ifdef USE_PAM + if (!cron_pam_setcred()) + _exit(ERROR_EXIT); + cron_pam_child_close(); +#endif if (setuid(e->pwd->pw_uid) != 0) { syslog(LOG_ERR, "setuid(%d) failed for %s: %m", e->pwd->pw_uid, e->pwd->pw_name); @@ -266,7 +306,7 @@ child_process(entry *e) { } /* we aren't root after this... */ #endif /* LOGIN_CAP */ - homedir = env_get("HOME", e->envp); + homedir = env_get("HOME", envp); if (chdir(homedir) != 0) { syslog(LOG_ERR, "chdir(%s) $HOME failed for %s: %m", homedir, e->pwd->pw_name); @@ -280,13 +320,15 @@ child_process(entry *e) { */ (void) signal(SIGCHLD, SIG_DFL); #endif + (void) signal(SIGPIPE, SIG_DFL); + (void) signal(SIGUSR1, SIG_DFL); (void) signal(SIGHUP, SIG_DFL); /* * Exec the command. */ { - char *shell = env_get("SHELL", e->envp); + char *shell = env_get("SHELL", envp); # if DEBUGGING if (DebugFlags & DTEST) { @@ -297,7 +339,7 @@ child_process(entry *e) { _exit(OK_EXIT); } # endif /*DEBUGGING*/ - (void)execle(shell, shell, "-c", e->cmd, NULL, e->envp); + (void)execle(shell, shell, "-c", e->cmd, NULL, envp); warn("execl: couldn't exec `%s'", shell); _exit(ERROR_EXIT); } @@ -307,8 +349,6 @@ child_process(entry *e) { break; } - children++; - /* middle process, child of original cron, parent of process running * the user's command. */ @@ -341,6 +381,12 @@ child_process(entry *e) { Debug(DPROC, ("[%ld] child2 sending data to grandchild\n", (long)getpid())); +#ifdef USE_PAM + cron_pam_child_close(); +#else + log_close(); +#endif + /* close the pipe we don't use, since we inherited it and * are part of its reference count now. */ @@ -385,8 +431,6 @@ child_process(entry *e) { */ (void)close(stdin_pipe[WRITE_PIPE]); - children++; - /* * read output from the grandchild. it's stderr has been redirected to * it's stdout, which has been redirected to our pipe. if there is any @@ -441,13 +485,15 @@ child_process(entry *e) { if (strlens(MAILFMT, MAILARG, NULL) + 1 >= sizeof mailcmd) { warnx("mailcmd too long"); - (void) _exit(ERROR_EXIT); + retval = ERROR_EXIT; + goto child_process_end; } (void)snprintf(mailcmd, sizeof(mailcmd), MAILFMT, MAILARG); if (!(mail = cron_popen(mailcmd, "w", e->pwd))) { warn("cannot run `%s'", mailcmd); - (void) _exit(ERROR_EXIT); + retval = ERROR_EXIT; + goto child_process_end; } (void)fprintf(mail, "From: root (Cron Daemon)\n"); @@ -461,7 +507,7 @@ child_process(entry *e) { (void)fprintf(mail, "Date: %s\n", arpadate(&StartTime)); #endif /*MAIL_DATE*/ - for (env = e->envp; *env; env++) + for (env = envp; *env; env++) (void)fprintf(mail, "X-Cron-Env: <%s>\n", *env); (void)fprintf(mail, "\n"); @@ -522,26 +568,7 @@ child_process(entry *e) { /* wait for children to die. */ - for (; children > 0; children--) { - WAIT_T waiter; - PID_T pid; - - Debug(DPROC, ("[%ld] waiting for grandchild #%d to finish\n", - (long)getpid(), children)); - while ((pid = wait(&waiter)) < OK && errno == EINTR) - ; - if (pid < OK) { - Debug(DPROC, - ("[%ld] no more grandchildren--mail written?\n", - (long)getpid())); - break; - } - Debug(DPROC, ("[%ld] grandchild #%ld finished, status=%04x", - (long)getpid(), (long)pid, WEXITSTATUS(waiter))); - if (WIFSIGNALED(waiter) && WCOREDUMP(waiter)) - Debug(DPROC, (", dumped core")); - Debug(DPROC, ("\n")); - } + sigchld_handler(0); /* Log the time when we finished deadling with the job */ /*local*/{ @@ -550,6 +577,12 @@ child_process(entry *e) { log_it(usernm, getpid(), "CMD FINISH", x); free(x); } + +child_process_end: +#ifdef USE_PAM + cron_pam_finish(); +#endif + return retval; } static int Index: src/external/bsd/cron/dist/funcs.h diff -u src/external/bsd/cron/dist/funcs.h:1.3 src/external/bsd/cron/dist/funcs.h:1.4 --- src/external/bsd/cron/dist/funcs.h:1.3 Thu Dec 17 17:36:48 2015 +++ src/external/bsd/cron/dist/funcs.h Fri Jun 9 13:36:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: funcs.h,v 1.3 2015/12/17 22:36:48 christos Exp $ */ +/* $NetBSD: funcs.h,v 1.4 2017/06/09 17:36:30 christos Exp $ */ /* * Id: funcs.h,v 1.9 2004/01/23 18:56:42 vixie Exp @@ -75,3 +75,12 @@ struct passwd *pw_dup(const struct passw #ifndef HAVE_TM_GMTOFF long get_gmtoff(time_t *, struct tm *); #endif + +extern int close_all(int); +#ifdef USE_PAM +extern int cron_pam_start (const char *user); +extern int cron_pam_setcred (void); +extern void cron_pam_finish (void); +extern void cron_pam_child_close (void); +extern char **cron_pam_getenvlist (char **envp); +#endif Index: src/external/bsd/cron/dist/misc.c diff -u src/external/bsd/cron/dist/misc.c:1.3 src/external/bsd/cron/dist/misc.c:1.4 --- src/external/bsd/cron/dist/misc.c:1.3 Thu Dec 17 17:36:48 2015 +++ src/external/bsd/cron/dist/misc.c Fri Jun 9 13:36:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: misc.c,v 1.3 2015/12/17 22:36:48 christos Exp $ */ +/* $NetBSD: misc.c,v 1.4 2017/06/09 17:36:30 christos Exp $ */ /* Copyright 1988,1990,1993,1994 by Paul Vixie * All rights reserved @@ -25,7 +25,7 @@ #if 0 static char rcsid[] = "Id: misc.c,v 1.16 2004/01/23 18:56:43 vixie Exp"; #else -__RCSID("$NetBSD: misc.c,v 1.3 2015/12/17 22:36:48 christos Exp $"); +__RCSID("$NetBSD: misc.c,v 1.4 2017/06/09 17:36:30 christos Exp $"); #endif #endif @@ -220,6 +220,7 @@ set_cron_cwd(void) { #endif /* first check for CRONDIR ("/var/cron" or some such) */ +#ifdef ENABLE_FIX_DIRECTORIES if (stat(CRONDIR, &sb) < OK && errno == ENOENT) { warn("Cannot stat `%s'", CRONDIR); if (OK == mkdir(CRONDIR, 0710)) { @@ -234,12 +235,14 @@ set_cron_cwd(void) { errx(ERROR_EXIT, "`%s' is not a directory, bailing out.", CRONDIR); } +#endif /* ENABLE_FIX_DIRECTORIES */ if (chdir(CRONDIR) < OK) { err(ERROR_EXIT, "cannot chdir `%s', bailing out.\n", CRONDIR); } /* CRONDIR okay (now==CWD), now look at SPOOL_DIR ("tabs" or some such) */ +#ifdef ENABLE_FIX_DIRECTORIES if (stat(SPOOL_DIR, &sb) < OK && errno == ENOENT) { warn("cannot stat `%s'", SPOOL_DIR); if (OK == mkdir(SPOOL_DIR, 0700)) { @@ -250,17 +253,33 @@ set_cron_cwd(void) { err(ERROR_EXIT, "cannot create `%s'", SPOOL_DIR); } } +#else + if (stat(SPOOL_DIR, &sb)) { + err(ERROR_EXIT, "cannot stat `%s'", SPOOL_DIR); + } +#endif /* ENABLE_FIX_DIRECTORIES */ if (!S_ISDIR(sb.st_mode)) { errx(ERROR_EXIT, "`%s' is not a directory, bailing out.", SPOOL_DIR); } if (grp != NULL) { - if (sb.st_gid != grp->gr_gid) + if (sb.st_gid != grp->gr_gid) { +#ifdef ENABLE_FIX_DIRECTORIES + errx(ERROR_EXIT, "Bad group %d != %d for `%s'", + (int)sb.st_gid, (int)grp->gr_gid, SPOOL_DIR); +#else if (chown(SPOOL_DIR, (uid_t)-1, grp->gr_gid) == -1) err(ERROR_EXIT, "cannot chown `%s'", SPOOL_DIR); +#endif + } if (sb.st_mode != 01730) +#ifdef ENABLE_FIX_DIRECTORIES + errx(ERROR_EXIT, "Bad mode %#o != %#o for `%s'", + (int)sb.st_mode, 01730, SPOOL_DIR); +#else if (chmod(SPOOL_DIR, 01730) == -1) err(ERROR_EXIT, "cannot chmod `%s'", SPOOL_DIR); +#endif } } @@ -299,6 +318,17 @@ acquire_daemonlock(int closeflag) { log_it("CRON", getpid(), "DEATH", buf); errx(ERROR_EXIT, "%s", buf); } + /* fd must be > STDERR since we dup fd 0-2 to /dev/null */ + if (fd <= STDERR) { + if (dup2(fd, STDERR + 1) < 0) { + snprintf(buf, sizeof buf, + "can't dup pid fd: %s", strerror(errno)); + log_it("CRON", getpid(), "DEATH", buf); + exit(ERROR_EXIT); + } + close(fd); + fd = STDERR + 1; + } if (flock(fd, LOCK_EX|LOCK_NB) < OK) { int save_errno = errno; Added files: Index: src/external/bsd/cron/dist/closeall.c diff -u /dev/null src/external/bsd/cron/dist/closeall.c:1.1 --- /dev/null Fri Jun 9 13:36:30 2017 +++ src/external/bsd/cron/dist/closeall.c Fri Jun 9 13:36:30 2017 @@ -0,0 +1,34 @@ +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> + +#ifdef __linux__ +#include <linux/limits.h> +#endif + +#include "cron.h" + +int close_all(int start) +{ +#ifdef F_CLOSEM + return fcntl(start, F_CLOSEM); +#else + int fd, max; + + max = sysconf(_SC_OPEN_MAX); + if (max <= 0) + return -1; + +#ifdef __linux__ + if (max < NR_OPEN) + max = NR_OPEN; +#endif + + for (fd = start; fd < max; fd++) { + if (close(fd) && errno != EBADF) + return -1; + } + + return 0; +#endif +} Index: src/external/bsd/cron/dist/pam_auth.c diff -u /dev/null src/external/bsd/cron/dist/pam_auth.c:1.1 --- /dev/null Fri Jun 9 13:36:30 2017 +++ src/external/bsd/cron/dist/pam_auth.c Fri Jun 9 13:36:30 2017 @@ -0,0 +1,121 @@ +#include "cron.h" + +#ifdef USE_PAM + +#include <security/pam_appl.h> + +static pam_handle_t *pamh = NULL; +static const struct pam_conv cron_conv = { 0 }; + +int +cron_pam_start (const char *username) +{ + int retval; + + if (pamh) + return 0; + + retval = pam_start ("cron", username, &cron_conv, &pamh); + log_close (); + if (retval != PAM_SUCCESS) + { + pamh = NULL; + log_it ("CRON", getpid (), "pam_start failed", + pam_strerror (pamh, retval)); + return 0; + } + retval = pam_authenticate (pamh, PAM_SILENT); + log_close (); + if (retval != PAM_SUCCESS) + { + log_it ("CRON", getpid (), "pam_authenticate failed", + pam_strerror (pamh, retval)); + pam_end (pamh, retval); + pamh = NULL; + return 0; + } + retval = pam_acct_mgmt (pamh, PAM_SILENT); + log_close (); + if (retval != PAM_SUCCESS) + { + log_it ("CRON", getpid (), "pam_acct_mgmt failed", + pam_strerror (pamh, retval)); + pam_end (pamh, retval); + pamh = NULL; + return 0; + } + retval = pam_open_session (pamh, PAM_SILENT); + log_close (); + if (retval != PAM_SUCCESS) + { + log_it ("CRON", getpid (), "pam_open_session failed", + pam_strerror (pamh, retval)); + pam_end (pamh, retval); + pamh = NULL; + return 0; + } + + return 1; +} + +int +cron_pam_setcred (void) +{ + int retval; + + if (!pamh) + return 0; + + retval = pam_setcred (pamh, PAM_ESTABLISH_CRED | PAM_SILENT); + log_close (); + if (retval != PAM_SUCCESS) + { + log_it ("CRON", getpid (), "pam_setcred failed", + pam_strerror (pamh, retval)); + pam_end (pamh, retval); + pamh = NULL; + log_close (); + return 0; + } + + return 1; +} + +void +cron_pam_finish (void) +{ + if (!pamh) + return; + + pam_close_session (pamh, 0); + pam_end (pamh, 0); + pamh = NULL; + log_close (); +} + +#ifndef PAM_DATA_SILENT +#define PAM_DATA_SILENT 0 +#endif + +void +cron_pam_child_close (void) +{ + pam_end (pamh, PAM_DATA_SILENT); + pamh = NULL; + log_close (); +} + +char ** +cron_pam_getenvlist (char **envp) +{ + if (!pamh || !envp) + return 0; + + for (; *envp; ++envp) + if (pam_putenv (pamh, *envp) != PAM_SUCCESS) + return 0; + + return pam_getenvlist (pamh); +} + +#endif /* USE_PAM */