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 */