From: Christian Kastner <ckk@kvr.at>
Date: Thu, 7 Jan 2016 23:14:49 +0100
Subject: PAM pam_env support for jobs

Add support for pam_env for job execution.

Contributed by Steve Greenland <stevegr@debian.org>.

IMPORTANT NOTE: This currently only (or mostly) affects commands launched by
crontab entries. Other commands run (such as mail notification via MAILTO) do
not use this code. This is not really that big of an issue (eg. why would
anyone force MAILTO via /etc/environment), but it should be documented
somewhere.

Bug-Debian: https://bugs.debian.org/203737
Bug-Debian: https://bugs.debian.org/511684
Forwarded: no
Last-Update: 2016-01-07
---
 crontab.5    | 14 ++++++++++++++
 do_command.c | 31 ++++++++++++++++++++++++++++---
 2 files changed, 42 insertions(+), 3 deletions(-)

diff --git a/crontab.5 b/crontab.5
index f4405f2..0f72f28 100644
--- a/crontab.5
+++ b/crontab.5
@@ -107,6 +107,20 @@ recipients by separating recipient users with a comma.  If MAILTO is defined
 but empty (MAILTO=""), no mail will be sent.  Otherwise mail is sent to the
 owner of the crontab.
 .PP
+On the Debian GNU/Linux system, cron supports the
+.B pam_env
+module, and loads the environment specified by
+.I /etc/environment
+and
+.IR /etc/security/pam_env.conf .
+It also reads locale information from
+.IR /etc/default/locale .
+However, the PAM settings do
+.B NOT
+override the settings described above nor any settings in the
+.I crontab
+file itself.  Note in particular that if you want a PATH other than
+"/usr/bin:/bin", you will need to set it in the crontab file.
 The format of a cron command is very much the V7 standard, with a number of
 upward-compatible extensions.  Each line has five time and date fields,
 followed by a command, followed by a newline character ('\en').
diff --git a/do_command.c b/do_command.c
index 1a75ed4..dec189e 100644
--- a/do_command.c
+++ b/do_command.c
@@ -46,6 +46,31 @@ static const struct pam_conv conv = {
 static void		child_process __P((entry *, user *)),
 			do_univ __P((user *));
 
+/* Build up the job environment from the PAM environment plus the
+   crontab environment */
+static char **build_env(char **cronenv)
+{
+	char **jobenv = cronenv;
+#if defined(USE_PAM)
+	char **pamenv = pam_getenvlist(pamh);
+	char *cronvar;
+	int count = 0;
+
+	jobenv = env_copy(pamenv);
+
+	/* Now add the cron environment variables. Since env_set()
+	   overwrites existing variables, this will let cron's
+	   environment settings override pam's */
+
+	while ((cronvar = cronenv[count++])) {
+		if (!(jobenv = env_set(jobenv, cronvar))) {
+			syslog(LOG_ERR, "Setting Cron environment variable %s failed", cronvar);
+			return NULL;
+		}
+	}
+#endif
+    return jobenv;
+}
 
 void
 do_command(e, u)
@@ -277,8 +302,8 @@ child_process(e, u)
 		/* exec the command.
 		 */
 		{
-			char	*shell = env_get("SHELL", e->envp);
-
+			char	**jobenv = build_env(e->envp);
+			char	*shell = env_get("SHELL", jobenv);
 # if DEBUGGING
 			if (DebugFlags & DTEST) {
 				fprintf(stderr,
@@ -288,7 +313,7 @@ child_process(e, u)
 				_exit(OK_EXIT);
 			}
 # endif /*DEBUGGING*/
-			execle(shell, shell, "-c", e->cmd, (char *)0, e->envp);
+			execle(shell, shell, "-c", e->cmd, (char *)0, jobenv);
 			fprintf(stderr, "%s: execle: %s\n", shell, strerror(errno));
 			_exit(ERROR_EXIT);
 		}
