crond: implement support for setting PATH in crontab files

It's very inconvenient for a cron user not to be able to set a
"personal" PATH for their cron jobs, as is possible with other crons

function                                             old     new   delta
load_crontab                                         868     942     +74
.rodata                                           104878  104884      +6
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 80/0)               Total: 80 bytes

Signed-off-by: Paul Fox <pgf@foxharp.boston.ma.us>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Paul Fox 2022-03-07 11:35:28 -05:00 committed by Denys Vlasenko
parent 9b6f44e040
commit 52a7bf6fa6

View File

@ -125,6 +125,7 @@ typedef struct CronLine {
char *cl_mailto; /* whom to mail results, may be NULL */
#endif
char *cl_shell;
char *cl_path;
/* ordered by size, not in natural order. makes code smaller: */
char cl_Dow[7]; /* 0-6, beginning sunday */
char cl_Mons[12]; /* 0-11 */
@ -421,6 +422,7 @@ static void load_crontab(const char *fileName)
char *mailTo = NULL;
#endif
char *shell = NULL;
char *path = NULL;
delete_cronfile(fileName);
@ -470,7 +472,12 @@ static void load_crontab(const char *fileName)
shell = xstrdup(&tokens[0][6]);
continue;
}
//TODO: handle HOME= too? "man crontab" says:
if (is_prefixed_with(tokens[0], "PATH=")) {
free(path);
path = xstrdup(&tokens[0][5]);
continue;
}
//TODO: handle HOME= too? Better yet, handle arbitrary ENVVARs? "man crontab" says:
//name = value
//
//where the spaces around the equal-sign (=) are optional, and any subsequent
@ -480,8 +487,8 @@ static void load_crontab(const char *fileName)
//
//Several environment variables are set up automatically by the cron(8) daemon.
//SHELL is set to /bin/sh, and LOGNAME and HOME are set from the /etc/passwd
//line of the crontab's owner. HOME and SHELL may be overridden by settings
//in the crontab; LOGNAME may not.
//line of the crontab's owner. HOME, SHELL, and PATH may be overridden by
//settings in the crontab; LOGNAME may not.
#if ENABLE_FEATURE_CROND_SPECIAL_TIMES
if (tokens[0][0] == '@') {
@ -567,6 +574,7 @@ static void load_crontab(const char *fileName)
line->cl_mailto = xstrdup(mailTo);
#endif
line->cl_shell = xstrdup(shell);
line->cl_path = xstrdup(path);
/* copy command */
line->cl_cmd = xstrdup(tokens[5]);
pline = &line->cl_next;
@ -653,21 +661,22 @@ static void safe_setenv(char **pvar_val, const char *var, const char *val)
}
#endif
static void set_env_vars(struct passwd *pas, const char *shell)
static void set_env_vars(struct passwd *pas, const char *shell, const char *path)
{
/* POSIX requires crond to set up at least HOME, LOGNAME, PATH, SHELL.
* We assume crond inherited suitable PATH.
*/
#if SETENV_LEAKS
safe_setenv(&G.env_var_logname, "LOGNAME", pas->pw_name);
safe_setenv(&G.env_var_user, "USER", pas->pw_name);
safe_setenv(&G.env_var_home, "HOME", pas->pw_dir);
safe_setenv(&G.env_var_shell, "SHELL", shell);
if (path) safe_setenv(&G.env_var_shell, "PATH", path);
#else
xsetenv("LOGNAME", pas->pw_name);
xsetenv("USER", pas->pw_name);
xsetenv("HOME", pas->pw_dir);
xsetenv("SHELL", shell);
if (path) xsetenv("PATH", path);
#endif
}
@ -701,7 +710,7 @@ fork_job(const char *user, int mailFd, CronLine *line, bool run_sendmail)
shell = line->cl_shell ? line->cl_shell : G.default_shell;
prog = run_sendmail ? SENDMAIL : shell;
set_env_vars(pas, shell);
set_env_vars(pas, shell, NULL); /* don't use crontab's PATH for sendmail */
sv_logmode = logmode;
pid = vfork();
@ -845,7 +854,7 @@ static pid_t start_one_job(const char *user, CronLine *line)
/* Prepare things before vfork */
shell = line->cl_shell ? line->cl_shell : G.default_shell;
set_env_vars(pas, shell);
set_env_vars(pas, shell, line->cl_path);
/* Fork as the user in question and run program */
pid = vfork();