Index: Makefile =================================================================== RCS file: /usr/dcvs/src/usr.sbin/cron/cron/Makefile,v retrieving revision 1.2 diff -u -r1.2 Makefile --- Makefile 17 Jun 2003 04:29:53 -0000 1.2 +++ Makefile 12 Dec 2007 11:39:16 -0000 @@ -1,11 +1,11 @@ -# $FreeBSD: src/usr.sbin/cron/cron/Makefile,v 1.12.2.1 2001/04/25 12:09:23 ru Exp $ +# $FreeBSD: src/usr.sbin/cron/cron/Makefile,v 1.16 2007/06/17 17:25:53 yar Exp $ # $DragonFly: src/usr.sbin/cron/cron/Makefile,v 1.2 2003/06/17 04:29:53 dillon Exp $ PROG= cron SRCS= cron.c database.c do_command.c job.c user.c popen.c -CFLAGS+=-DLOGIN_CAP -DPADD= ${LIBCRON} ${LIBUTIL} -LDADD= ${LIBCRON} -lutil +CFLAGS+=-DLOGIN_CAP -DPAM +DPADD= ${LIBCRON} ${LIBPAM} ${LIBUTIL} +LDADD= ${LIBCRON} -lpam -lutil MAN= cron.8 .include Index: cron.8 =================================================================== RCS file: /usr/dcvs/src/usr.sbin/cron/cron/cron.8,v retrieving revision 1.3 diff -u -r1.3 cron.8 --- cron.8 18 Mar 2006 20:29:50 -0000 1.3 +++ cron.8 12 Dec 2007 11:39:16 -0000 @@ -15,10 +15,10 @@ .\" * Paul Vixie uunet!decwrl!vixie!paul .\" */ .\" -.\" $FreeBSD: src/usr.sbin/cron/cron/cron.8,v 1.7.2.9 2003/03/11 21:13:48 trhodes Exp $ +.\" $FreeBSD: src/usr.sbin/cron/cron/cron.8,v 1.25 2007/06/17 17:25:53 yar Exp $ .\" $DragonFly: src/usr.sbin/cron/cron/cron.8,v 1.3 2006/03/18 20:29:50 dillon Exp $ .\" -.Dd December 20, 1993 +.Dd June 17, 2007 .Dt CRON 8 .Os .Sh NAME @@ -54,11 +54,22 @@ .Pa /etc/crontab which is in a different format (see .Xr crontab 5 ) . +.Pp The .Nm utility then wakes up every minute, examining all stored crontabs, checking each -command to see if it should be run in the current minute. When executing +command to see if it should be run in the current minute. +Before running a command from a per-account crontab file, +.Nm +checks the status of the account with +.Xr pam 3 +and skips the command if the account is unavailable, +e.g., locked out or expired. +Commands from +.Pa /etc/crontab +bypass this check. +When executing commands, any output is mailed to the owner of the crontab (or to the user named in the .Ev MAILTO @@ -171,8 +182,21 @@ trace through the execution, but do not perform any actions .El .El +.Sh FILES +.Bl -tag -width /etc/pam.d/cron -compact +.It Pa /etc/crontab +System crontab file +.It Pa /etc/pam.d/cron +.Xr pam.conf 5 +configuration file for +.Nm +.It Pa /var/cron/tabs +Directory for personal crontab files +.El .Sh SEE ALSO .Xr crontab 1 , -.Xr crontab 5 +.Xr pam 3 , +.Xr crontab 5 , +.Xr pam.conf 5 .Sh AUTHORS .An Paul Vixie Aq paul@vix.com Index: cron.h =================================================================== RCS file: /usr/dcvs/src/usr.sbin/cron/cron/cron.h,v retrieving revision 1.5 diff -u -r1.5 cron.h --- cron.h 18 Mar 2006 20:29:50 -0000 1.5 +++ cron.h 12 Dec 2007 11:39:16 -0000 @@ -17,7 +17,7 @@ /* cron.h - header for vixie's cron * - * $FreeBSD: src/usr.sbin/cron/cron/cron.h,v 1.9.2.3 2001/05/28 23:37:26 babkin Exp $ + * $FreeBSD: src/usr.sbin/cron/cron/cron.h,v 1.17 2007/06/17 17:25:53 yar Exp $ * $DragonFly: src/usr.sbin/cron/cron/cron.h,v 1.5 2006/03/18 20:29:50 dillon Exp $ * * vix 14nov88 [rest of log is in RCS] @@ -76,6 +76,7 @@ #define MAX_UNAME 20 /* max length of username, should be overkill */ #define ROOT_UID 0 /* don't change this, it really must be root */ #define ROOT_USER "root" /* ditto */ +#define SYS_NAME "*system*" /* magic owner name for system crontab */ /* NOTE: these correspond to DebugFlagNames, * defined below. Index: database.c =================================================================== RCS file: /usr/dcvs/src/usr.sbin/cron/cron/database.c,v retrieving revision 1.6 diff -u -r1.6 database.c --- database.c 8 Aug 2005 18:36:28 -0000 1.6 +++ database.c 12 Dec 2007 11:39:16 -0000 @@ -84,7 +84,7 @@ new_db.head = new_db.tail = NULL; if (syscron_stat.st_mtime) { - process_crontab("root", "*system*", + process_crontab("root", SYS_NAME, SYSCRONTAB, &syscron_stat, &new_db, old_db); } @@ -189,7 +189,7 @@ int crontab_fd = OK - 1; user *u; - if (strcmp(fname, "*system*") && !(pw = getpwnam(uname))) { + if (strcmp(fname, SYS_NAME) && !(pw = getpwnam(uname))) { /* file doesn't have a user in passwd file. */ log_it(fname, getpid(), "ORPHAN", "no passwd entry"); Index: do_command.c =================================================================== RCS file: /usr/dcvs/src/usr.sbin/cron/cron/do_command.c,v retrieving revision 1.7 diff -u -r1.7 do_command.c --- do_command.c 18 Mar 2006 20:29:50 -0000 1.7 +++ do_command.c 12 Dec 2007 11:54:06 -0000 @@ -14,7 +14,7 @@ * I'll try to keep a version up to date. I can be reached as follows: * Paul Vixie uunet!decwrl!vixie!paul * - * $FreeBSD: src/usr.sbin/cron/cron/do_command.c,v 1.15.2.5 2001/05/04 00:59:40 peter Exp $ + * $FreeBSD: src/usr.sbin/cron/cron/do_command.c,v 1.27 2007/06/17 17:25:53 yar Exp $ * $DragonFly: src/usr.sbin/cron/cron/do_command.c,v 1.7 2006/03/18 20:29:50 dillon Exp $ */ @@ -29,7 +29,10 @@ #if defined(LOGIN_CAP) # include #endif - +#ifdef PAM +# include +# include +#endif static void child_process(entry *, user *), do_univ(user *); @@ -92,6 +95,48 @@ usernm = env_get("LOGNAME", e->envp); mailto = env_get("MAILTO", e->envp); +#ifdef PAM + /* use PAM to see if the user's account is available, + * i.e., not locked or expired or whatever. skip this + * for system tasks from /etc/crontab -- they can run + * as any user. + */ + if (strcmp(u->name, SYS_NAME)) { /* not equal */ + pam_handle_t *pamh = NULL; + int pam_err; + struct pam_conv pamc = { + .conv = openpam_nullconv, + .appdata_ptr = NULL + }; + + Debug(DPROC, ("[%d] checking account with PAM\n", getpid())) + + /* u->name keeps crontab owner name while LOGNAME is the name + * of user to run command on behalf of. they should be the + * same for a task from a per-user crontab. + */ + if (strcmp(u->name, usernm)) { + log_it(usernm, getpid(), "username ambiguity", u->name); + exit(ERROR_EXIT); + } + + pam_err = pam_start("cron", usernm, &pamc, &pamh); + if (pam_err != PAM_SUCCESS) { + log_it("CRON", getpid(), "error", "can't start PAM"); + exit(ERROR_EXIT); + } + + pam_err = pam_acct_mgmt(pamh, PAM_SILENT); + /* Expired password shouldn't prevent the job from running. */ + if (pam_err != PAM_SUCCESS && pam_err != PAM_NEW_AUTHTOK_REQD) { + log_it(usernm, getpid(), "USER", "account unavailable"); + exit(ERROR_EXIT); + } + + pam_end(pamh, pam_err); + } +#endif + #ifdef USE_SIGCHLD /* our parent is watching for our death by catching SIGCHLD. we * do not care to watch for our children's deaths this way -- we