From: Thibault Godouet Date: Sat, 25 Sep 2010 12:39:14 +0000 (+0100) Subject: Added Content-Type and Content-Transfer-Encoding to output emails X-Git-Tag: ver3_1_0~32 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=53bb396c16663a17ccccc7f3826be71b3819470f;p=fcron Added Content-Type and Content-Transfer-Encoding to output emails --- diff --git a/database.c b/database.c index c48687e..4639ed6 100644 --- a/database.c +++ b/database.c @@ -1360,7 +1360,7 @@ mail_notrun(cl_t *line, char context, struct tm *since) memcpy(&time, time2, sizeof(time)); /* create a temp file, and write in it the message to send */ - mailf = create_mail(line, "Non-execution of fcron job", NULL); + mailf = create_mail(line, "Non-execution of fcron job", NULL, NULL, NULL); switch ( context ) { case SYSDOWN: @@ -1400,7 +1400,7 @@ mail_notrun(cl_t *line, char context, struct tm *since) } /* become user (for security reasons) */ - change_user_setup_env(line, &sendmailenv, NULL, NULL, NULL); + change_user_setup_env(line, &sendmailenv, NULL, NULL, NULL, NULL, NULL); /* then, send mail */ launch_mailer(line, mailf, sendmailenv); diff --git a/doc/en/fcrontab.5.sgml b/doc/en/fcrontab.5.sgml index 8f1f57a..89c93f9 100644 --- a/doc/en/fcrontab.5.sgml +++ b/doc/en/fcrontab.5.sgml @@ -72,6 +72,7 @@ command is extracted. TZ is also defined to the value of the option timezone whe overridden by settings in the &fcrontabf;, but USER may not. Every other environment assignments defined in the user &fcrontabf; are then made, and the command is executed. + By default, fcron will send emails using the email "Content-Type:" header of "text/plain" with the "charset=" parameter set to the charmap / codeset of the locale in which &fcron;(8) is started up - i.e. either the default system locale, if no LC_* environment variables are set, or the locale specified by the LC_* environment variables (see locale(7)). You can use different character encodings for emailed fcron job output by setting the CONTENT_TYPE and CONTENT_TRANSFER_ENCODING variables in fcrontabs, to the correct values of the mail headers of those names. Plus, the special variable MAILTO allows you to tell &fcron; to whom it has to mail the command's output. Note that MAILTO is in fact equivalent to a global declaration of the diff --git a/doc/en/todo.sgml b/doc/en/todo.sgml index 28ff393..d336187 100644 --- a/doc/en/todo.sgml +++ b/doc/en/todo.sgml @@ -25,13 +25,19 @@ A copy of the license is included in gfdl.sgml. High priority - could be worth checking fcron for memory leaks using specialized library (just in case...) + add audit (libaudit) - option to put a maximum limit on the execution time of a task + terminate it if not finished yet + send email to let the user know + Use directory notifications (FAM) / inotify, and support a fcrontab + and a cron.d as Vixie cron does (directly included in fcron itself, not thanks to a script as now). + However the parsing work is done by fcrontab, and should probably keep on being done by fcrontab for + security and stability reasons: have fcron call fcrontab to do that job? - jitter feature: if 100 jobs to be started at the same minute, then make them start at a random second of that minute to limit load spikes (see BSD cron jitter feature) + could be worth checking fcron for memory leaks using specialized library (just in case...) + + + option to put a maximum limit on the execution time of a task + terminate it if not finished yet + send email to let the user know setting to limit the number of jobs of a single user in the serialq/lavgq to X jobs + make sure root always has Y slots that it can use in those queues (i.e. number of slots used by root + number of free slots >= Y) @@ -47,6 +53,9 @@ A copy of the license is included in gfdl.sgml. Low priority + + use readline (if available) for fcrondyn. + add logging to a file (instead of syslog) with configuration in fcron.conf @@ -67,10 +76,6 @@ A copy of the license is included in gfdl.sgml. add a return code for jobs which would mean that they should not be run again (in case of an error, etc...). - - Use directory notifications (FAM), and support a fcrontab - and a cron.d as Vixie cron does (directly included in fcron itself, not thanks to a script as now). - PAM support (included in fcron, but needs more tests by people using PAM - not implemented in fcrondyn: is it needed @@ -79,9 +84,6 @@ A copy of the license is included in gfdl.sgml. support for per user serial queue (especially for root) - - use readline (if available) for fcrondyn. - add a mailsubject option, for custom mail subjects (for instance, in case of a job containing something secret -- password, etc -- in the command line). diff --git a/fcron.c b/fcron.c index 7363063..380020e 100644 --- a/fcron.c +++ b/fcron.c @@ -65,6 +65,10 @@ char once = 0; /* set to 1 if fcron shall return immediately after running * all jobs that are due at the time when fcron is started */ char dosyslog = 1; /* set to 1 when we log messages to syslog, else 0 */ +/* Get the default locale character set for the mail + * "Content-Type: ...; charset=" header */ +char default_mail_charset[TERM_LEN] = ""; + /* used in temp_file() : create it in current dir (normally spool dir) */ char *tmp_path = ""; @@ -505,6 +509,7 @@ sigusr2_handler(int x) int main(int argc, char **argv) { + char *codeset = NULL; rootuid = get_user_uid_safe(ROOTNAME); rootgid = get_group_gid_safe(ROOTGROUP); @@ -541,6 +546,17 @@ main(int argc, char **argv) if (chdir(fcrontabs) != 0) die_e("Could not change dir to %s", fcrontabs); + /* Get the default locale character set for the mail + * "Content-Type: ...; charset=" header */ + setlocale(LC_ALL,""); /* set locale to system defaults or to + that specified by any LC_* env vars */ + /* Except that "US-ASCII" is preferred to "ANSI_x3.4-1968" in MIME, + * even though "ANSI_x3.4-1968" is the official charset name. */ + if ( (codeset = nl_langinfo(CODESET)) != 0L && + strcmp(codeset, "ANSI_x3.4-1968") != 0 ) + strncpy(default_mail_charset, codeset, sizeof(default_mail_charset)); + else + strcpy(default_mail_charset, "US-ASCII"); if ( freopen("/dev/null", "r", stdin) == NULL ) error_e("Could not open /dev/null as stdin"); diff --git a/fcron.h b/fcron.h index d2abe88..00527f4 100644 --- a/fcron.h +++ b/fcron.h @@ -65,6 +65,7 @@ extern time_t now; extern char foreground; extern char dosyslog; +extern char default_mail_charset[TERM_LEN]; extern time_t first_sleep; extern char *cdir; extern pid_t daemon_pid; diff --git a/global.h b/global.h index 25e6316..3c2491f 100644 --- a/global.h +++ b/global.h @@ -62,6 +62,9 @@ #include #endif +#include +#include +#include #include #include diff --git a/job.c b/job.c index e7f1b8f..1e7e496 100644 --- a/job.c +++ b/job.c @@ -56,7 +56,7 @@ die_mail_pame(cl_t *cl, int pamerrno, struct passwd *pas, char *str, env_list_t if (is_mail(cl->cl_option)) { char **envp = env_list_export_envp(env); - FILE *mailf = create_mail(cl, "Could not run fcron job", envp); + FILE *mailf = create_mail(cl, "Could not run fcron job", NULL, NULL, envp); /* print the error in both syslog and a file, in order to mail it to user */ if (dup2(fileno(mailf), 1) != 1 || dup2(1, 2) != 2) @@ -111,7 +111,8 @@ become_user(struct cl_t *cl, struct passwd *pas, char *home) void setup_user_and_env(struct cl_t *cl, struct passwd *pas, - char ***sendmailenv, char ***jobenv, char **curshell, char **curhome) + char ***sendmailenv, char ***jobenv, char **curshell, + char **curhome, char **content_type, char **encoding) /* Check PAM authorization, and setup the environment variables * to run sendmail and to run the job itself. Change dir to HOME and check if SHELL is ok */ /* (*curshell) and (*curhome) will be allocated and should thus be freed @@ -223,18 +224,25 @@ setup_user_and_env(struct cl_t *cl, struct passwd *pas, if ( curshell != NULL ) *curshell = strdup2(myshell); - if (jobenv != NULL) - *jobenv = env_list_export_envp(env_list); + *jobenv = env_list_export_envp(env_list); - env_list_destroy(env_list); + } + if ( content_type != NULL ) { + (*content_type) = strdup2(env_list_getenv(env_list, "CONTENT_TYPE")); + } + if ( encoding != NULL ) { + (*encoding) = strdup2(env_list_getenv(env_list, "CONTENT_TRANSFER_ENCODING")); } + env_list_destroy(env_list); + } void change_user_setup_env(struct cl_t *cl, - char ***sendmailenv, char ***jobenv, char **curshell, char **curhome) + char ***sendmailenv, char ***jobenv, char **curshell, + char **curhome, char **content_type, char **encoding) /* call setup_user_and_env() and become_user(). * As a result, *curshell and *curhome will be allocated and should thus be freed * if curshell and curhome are not NULL. */ @@ -246,7 +254,8 @@ change_user_setup_env(struct cl_t *cl, if ( pas == NULL ) die_e("failed to get passwd fields for user \"%s\"", cl->cl_runas); - setup_user_and_env(cl, pas, sendmailenv, jobenv, curshell, curhome); + setup_user_and_env(cl, pas, sendmailenv, jobenv, curshell, curhome, + content_type, encoding); become_user(cl, pas, *curhome); free_safe(*curhome); } @@ -265,7 +274,8 @@ sig_dfl(void) FILE * -create_mail(cl_t *line, char *subject, char **env) +create_mail(cl_t *line, char *subject, char *content_type, char *encoding, + char **env) /* create a temp file and write in it a mail header */ { /* create temporary file for stdout and stderr of the job */ @@ -308,6 +318,35 @@ create_mail(cl_t *line, char *subject, char **env) fprintf(mailf, "Subject: fcron <%s@%s> %s\n", line->cl_file->cf_user, ( hostname[0] != '\0')? hostname:"?" , line->cl_shell); + if (content_type == NULL) { + fprintf(mailf, "Content-Type: text/plain; charset=%s\n", + default_mail_charset); + } + else { + /* user specified Content-Type header. */ + char *c = NULL; + + /* Remove new-lines or users could specify arbitrary mail headers! + * (fcrontab should already prevent that, but better safe than sorry) */ + for (c=content_type; *c != '\0'; c++) { + if (*c == '\n') + *c = ' '; + } + fprintf(mailf, "Content-Type: %s\n", content_type); + } + + if (encoding != NULL) { + char *c = NULL; + + /* Remove new-lines or users could specify arbitrary mail headers! + * (fcrontab should already prevent that, but better safe than sorry) */ + for (c=encoding; *c != '\0'; c++) { + if (*c == '\n') + *c = ' '; + } + fprintf(mailf, "Content-Transfer-Encoding: %s\n", encoding); + } + /* Add headers so as automated systems can identify that this message * is an automated one sent by fcron. * That's useful for example for vacation auto-reply systems: no need @@ -489,6 +528,8 @@ run_job(struct exe_t *exeent) char **sendmailenv = NULL; char *curshell = NULL; char *curhome = NULL; + char *content_type = NULL; + char *encoding = NULL; FILE *mailf = NULL; int status = 0; int to_stdout = foreground && is_stdout(line->cl_option); @@ -511,7 +552,8 @@ run_job(struct exe_t *exeent) if ( pas == NULL ) die_e("failed to get passwd fields for user \"%s\"", line->cl_runas); - setup_user_and_env(line, pas, &sendmailenv, &jobenv, &curshell, &curhome); + setup_user_and_env(line, pas, &sendmailenv, &jobenv, &curshell, + &curhome, &content_type, &encoding); /* close unneeded READ fd */ if ( close(pipe_pid_fd[0]) < 0 ) @@ -523,7 +565,7 @@ run_job(struct exe_t *exeent) * as temp_file() needs root privileges */ /* if we run in foreground, stdout and stderr point to the console. * Otherwise, stdout and stderr point to /dev/null . */ - mailf = create_mail(line, NULL, jobenv); + mailf = create_mail(line, NULL, content_type, encoding, jobenv); mailpos = ftell(mailf); if (pipe(pipe_fd) != 0) die_e("could not pipe() (job not executed)"); diff --git a/job.h b/job.h index ff90a19..3ed051b 100644 --- a/job.h +++ b/job.h @@ -28,9 +28,11 @@ /* functions prototypes */ extern void change_user_setup_env(struct cl_t *cl, char ***sendmailenv, - char ***jobenv, char **curshell, char **curhome); + char ***jobenv, char **curshell, char **curhome, + char **content_type, char **encoding); extern int run_job(struct exe_t *exeent); -extern FILE *create_mail(struct cl_t *line, char *subject, char **env); +extern FILE *create_mail(struct cl_t *line, char *subject, char *content_type, + char *encoding, char **env); extern void launch_mailer(struct cl_t *line, FILE *mailf, char **env); #endif /* __JOB_H__ */