1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
From: Laurent Combe <laurent.combe@free.fr>
Date: Tue, 16 Feb 2021 12:09:37 +0100
Subject: Add support for MAILFROM variable
This patch lets cron use the MAILFROM variable to set the sender as which it
will send emails. MAILFROM has the same semantics as the same environment
variable in cronie.
Contributed by Georges Khaznadar <georgesk@debian.org> : a test in
debian/tests/check_mailfrom_mailto
Origin: https://github.com/cronie-crond/cronie/blob/master/src/do_command.c
Bug-Debian: https://bugs.debian.org/898177
Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/cron/+bug/1750051
Last-Update: 2021-02-16
---
cron.8 | 4 +++-
crontab.5 | 16 ++++++++++------
do_command.c | 34 ++++++++++++++++++++++++++++------
3 files changed, 41 insertions(+), 13 deletions(-)
diff --git a/cron.8 b/cron.8
index e1d6736..fb0f5fe 100644
--- a/cron.8
+++ b/cron.8
@@ -124,7 +124,9 @@ 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 commands, any output is mailed to the owner of the crontab
(or to the user named in the MAILTO environment variable in the
-crontab, if such exists). The children copies of cron running these
+crontab, if such exists) from the owner of the crontab (or from the email
+address given in the MAILFROM environment variable in the crontab, if
+such exists). The children copies of cron running these
processes have their name coerced to uppercase, as will be seen in the
syslog and ps output.
.PP
diff --git a/crontab.5 b/crontab.5
index c0863b3..e60228a 100644
--- a/crontab.5
+++ b/crontab.5
@@ -100,12 +100,16 @@ on these systems, USER will be set also.)
.PP
In addition to LOGNAME, HOME, and SHELL,
.IR cron (8)
-will look at MAILTO if it has any reason to send mail as a result of running
-commands in ``this'' crontab. If MAILTO is defined (and non-empty), mail is
-sent to the user so named. MAILTO may also be used to direct mail to multiple
-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.
+will look at MAILTO and MAILFROM if it has any reason to send mail as a result
+of running commands in ``this'' crontab.
+.PP
+If MAILTO is defined (and non-empty), mail is sent to the user so named.
+MAILTO may also be used to direct mail to multiple 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
+If MAILFROM is defined, the sender email address is set to MAILFROM. Otherwise
+mail is sent as "root (Cron Daemon)".
.PP
On the Debian GNU/Linux system, cron supports the
.B pam_env
diff --git a/do_command.c b/do_command.c
index a469347..78eaa33 100644
--- a/do_command.c
+++ b/do_command.c
@@ -52,6 +52,7 @@ static const struct pam_conv conv = {
static void child_process __P((entry *, user *)),
do_univ __P((user *));
+static int safe_p(const char *, const char *);
/* Build up the job environment from the PAM environment plus the
crontab environment */
@@ -129,7 +130,7 @@ child_process(e, u)
int stdin_pipe[2];
FILE *tmpout;
register char *input_data;
- char *usernm, *mailto;
+ char *usernm, *mailto, *mailfrom;
int children = 0;
pid_t job_pid;
#if defined(USE_PAM)
@@ -150,8 +151,9 @@ child_process(e, u)
/* discover some useful and important environment settings
*/
- usernm = env_get("LOGNAME", e->envp);
- mailto = env_get("MAILTO", e->envp);
+ usernm = env_get("LOGNAME", e->envp);
+ mailto = env_get("MAILTO", e->envp);
+ mailfrom = env_get("MAILFROM", e->envp);
#ifdef USE_SIGCHLD
/* our parent is watching for our death by catching SIGCHLD. we
@@ -503,8 +505,13 @@ child_process(e, u)
// get name of recipient.
if (mailto == NULL)
mailto = usernm;
- else if (!*mailto)
- goto mail_finished;
+ else if (!*mailto || !safe_p(usernm, mailto))
+ goto mail_finished;
+
+ // get sender address
+ if (mailfrom == NULL || !*mailfrom || !safe_p(usernm, mailfrom)) {
+ mailfrom = "root (Cron Daemon)";
+ }
/* Don't send mail if MAILCMD is not available */
if (stat(MAILCMD, &mcsb) != 0) {
@@ -534,7 +541,7 @@ child_process(e, u)
perror(MAILCMD);
(void) _exit(ERROR_EXIT);
}
- fprintf(mail, "From: root (Cron Daemon)\n");
+ fprintf(mail, "From: %s\n", mailfrom);
fprintf(mail, "To: %s\n", mailto);
fprintf(mail, "Subject: Cron <%s@%s> %s%s\n",
usernm,
@@ -685,3 +692,18 @@ do_univ(u)
(void) universe(U_ATT);
#endif
}
+
+static int safe_p(const char *usernm, const char *s) {
+ static const char safe_delim[] = "@!:%-.,_+=/"; /* conservative! */
+ const char *t;
+ int ch, first;
+
+ for (t = s, first = 1; (ch = *t++) != '\0'; first = 0) {
+ if (isascii(ch) && isprint(ch) &&
+ (isalnum(ch) || (!first && strchr(safe_delim, ch))))
+ continue;
+ log_it(usernm, getpid(), "UNSAFE MAIL", s);
+ return (FALSE);
+ }
+ return (TRUE);
+}
|