summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/pam.d/Makefile1
-rw-r--r--etc/pam.d/cron9
-rw-r--r--usr.sbin/cron/cron/Makefile6
-rw-r--r--usr.sbin/cron/cron/cron.827
-rw-r--r--usr.sbin/cron/cron/cron.h1
-rw-r--r--usr.sbin/cron/cron/database.c4
-rw-r--r--usr.sbin/cron/cron/do_command.c46
-rw-r--r--usr.sbin/cron/lib/Makefile2
-rw-r--r--usr.sbin/cron/lib/entry.c2
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;
OpenPOWER on IntegriCloud