diff options
-rw-r--r-- | etc/pam.d/Makefile | 1 | ||||
-rw-r--r-- | etc/pam.d/cron | 9 | ||||
-rw-r--r-- | usr.sbin/cron/cron/Makefile | 6 | ||||
-rw-r--r-- | usr.sbin/cron/cron/cron.8 | 27 | ||||
-rw-r--r-- | usr.sbin/cron/cron/cron.h | 1 | ||||
-rw-r--r-- | usr.sbin/cron/cron/database.c | 4 | ||||
-rw-r--r-- | usr.sbin/cron/cron/do_command.c | 46 | ||||
-rw-r--r-- | usr.sbin/cron/lib/Makefile | 2 | ||||
-rw-r--r-- | usr.sbin/cron/lib/entry.c | 2 |
9 files changed, 90 insertions, 8 deletions
diff --git a/etc/pam.d/Makefile b/etc/pam.d/Makefile index 9e5746c..2686cdf 100644 --- a/etc/pam.d/Makefile +++ b/etc/pam.d/Makefile @@ -4,6 +4,7 @@ NO_OBJ= FILES= README \ atrun \ + cron \ ftpd \ gdm \ imap \ diff --git a/etc/pam.d/cron b/etc/pam.d/cron new file mode 100644 index 0000000..55a3d10 --- /dev/null +++ b/etc/pam.d/cron @@ -0,0 +1,9 @@ +# +# $FreeBSD$ +# +# PAM configuration for the "cron" service +# + +# account +account required pam_nologin.so +account required pam_unix.so diff --git a/usr.sbin/cron/cron/Makefile b/usr.sbin/cron/cron/Makefile index d578da7..92d3ee4 100644 --- a/usr.sbin/cron/cron/Makefile +++ b/usr.sbin/cron/cron/Makefile @@ -4,9 +4,9 @@ PROG= cron MAN= cron.8 SRCS= cron.c database.c do_command.c job.c user.c popen.c -CFLAGS+= -DLOGIN_CAP +CFLAGS+= -DLOGIN_CAP -DPAM -DPADD= ${LIBCRON} ${LIBUTIL} -LDADD= ${LIBCRON} -lutil +DPADD= ${LIBCRON} ${LIBPAM} ${LIBUTIL} +LDADD= ${LIBCRON} -lpam -lutil .include <bsd.prog.mk> diff --git a/usr.sbin/cron/cron/cron.8 b/usr.sbin/cron/cron/cron.8 index eba639d..b0d1a91 100644 --- a/usr.sbin/cron/cron/cron.8 +++ b/usr.sbin/cron/cron/cron.8 @@ -17,7 +17,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 20, 1993 +.Dd June 17, 2007 .Dt CRON 8 .Os .Sh NAME @@ -53,11 +53,21 @@ utility also searches for .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. +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 @@ -173,8 +183,21 @@ be verbose when iterating through the scheduling algorithms 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 diff --git a/usr.sbin/cron/cron/cron.h b/usr.sbin/cron/cron/cron.h index 249bec9..6277719 100644 --- a/usr.sbin/cron/cron/cron.h +++ b/usr.sbin/cron/cron/cron.h @@ -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. diff --git a/usr.sbin/cron/cron/database.c b/usr.sbin/cron/cron/database.c index 9ebf75d..6c364c9 100644 --- a/usr.sbin/cron/cron/database.c +++ b/usr.sbin/cron/cron/database.c @@ -87,7 +87,7 @@ load_database(old_db) 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); } @@ -205,7 +205,7 @@ process_crontab(uname, fname, tabname, statbuf, new_db, old_db) 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"); diff --git a/usr.sbin/cron/cron/do_command.c b/usr.sbin/cron/cron/do_command.c index cb0bf02..afc8317 100644 --- a/usr.sbin/cron/cron/do_command.c +++ b/usr.sbin/cron/cron/do_command.c @@ -32,6 +32,10 @@ static const char rcsid[] = #if defined(LOGIN_CAP) # include <login_cap.h> #endif +#ifdef PAM +# include <security/pam_appl.h> +# include <security/openpam.h> +#endif static void child_process __P((entry *, user *)), @@ -98,6 +102,48 @@ child_process(e, u) 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 diff --git a/usr.sbin/cron/lib/Makefile b/usr.sbin/cron/lib/Makefile index d11c511..296ebd0 100644 --- a/usr.sbin/cron/lib/Makefile +++ b/usr.sbin/cron/lib/Makefile @@ -5,6 +5,6 @@ INTERNALLIB= SRCS= entry.c env.c misc.c CFLAGS+= -I${.CURDIR}/../cron -CFLAGS+= -DLOGIN_CAP +CFLAGS+= -DLOGIN_CAP -DPAM .include <bsd.lib.mk> diff --git a/usr.sbin/cron/lib/entry.c b/usr.sbin/cron/lib/entry.c index 7269152..33ace49 100644 --- a/usr.sbin/cron/lib/entry.c +++ b/usr.sbin/cron/lib/entry.c @@ -323,10 +323,12 @@ load_entry(file, error_func, pw, envp) #endif } +#ifndef PAM /* PAM takes care of account expiration by itself */ if (pw->pw_expire && time(NULL) >= pw->pw_expire) { ecode = e_username; goto eof; } +#endif /* !PAM */ e->uid = pw->pw_uid; e->gid = pw->pw_gid; |