diff -up cronie-1.4.6/src/cron.c.old cronie-1.4.6/src/cron.c --- cronie-1.4.6/src/cron.c.old 2010-10-21 07:56:27.000000000 +0200 +++ cronie-1.4.6/src/cron.c 2010-12-16 13:44:44.000000000 +0100 @@ -198,6 +198,11 @@ int main(int argc, char *argv[]) { exit(1); } + if (cron_init_security() < 0) { + log_it("CRON", pid, "DEATH", "Critical security parameters not initialized", 0); + exit(1); + } + /* Get the default locale character set for the mail * "Content-Type: ...; charset=" header */ diff -up cronie-1.4.6/src/funcs.h.old cronie-1.4.6/src/funcs.h --- cronie-1.4.6/src/funcs.h.old 2010-10-04 16:07:25.000000000 +0200 +++ cronie-1.4.6/src/funcs.h 2010-12-16 09:59:02.000000000 +0100 @@ -85,6 +85,8 @@ long get_gmtoff(time_t *, struct tm *); /* Red Hat security stuff (security.c): */ +int cron_init_security( void ); + void cron_restore_default_security_context( void ); int cron_set_job_security_context( entry *e, user *u, char ***jobenvp ); diff -up cronie-1.4.6/src/security.c.old cronie-1.4.6/src/security.c --- cronie-1.4.6/src/security.c.old 2010-10-04 16:07:25.000000000 +0200 +++ cronie-1.4.6/src/security.c 2010-12-16 09:59:02.000000000 +0100 @@ -41,15 +41,14 @@ static int cron_conv(int num_msg, const struct pam_message **msgm, struct pam_response **response, void *appdata_ptr) { - struct pam_message**m = msgm; int i; for (i = 0; i < num_msg; i++) { - switch (m[i]->msg_style) { + switch (msgm[i]->msg_style) { case PAM_ERROR_MSG: case PAM_TEXT_INFO: - if (m[i]->msg != NULL) { - log_it("CRON", getpid(), "pam_message", m[i]->msg, 0); + if (msgm[i]->msg != NULL) { + log_it("CRON", getpid(), "pam_message", msgm[i]->msg, 0); } break; default: @@ -81,6 +80,11 @@ static char **build_env(char **cronenv); static int cron_change_selinux_range(user * u, security_context_t ucontext); static int cron_get_job_range(user * u, security_context_t * ucontextp, char **jobenv); + +static security_class_t file_class; +static security_class_t context_class; +static access_vector_t entrypoint_bit; +static access_vector_t contains_bit; #endif void cron_restore_default_security_context() { @@ -89,6 +93,40 @@ void cron_restore_default_security_conte #endif } +int cron_init_security() { +#ifdef WITH_SELINUX + int rv = -1; + + if (is_selinux_enabled() <= 0) + return 0; + + if (security_getenforce() <= 0) + rv = 0; + + file_class = string_to_security_class("file"); + if (!file_class) { + log_it("CRON", getpid(), "ERROR", "Failed to translate security class file", errno); + return rv; + } + context_class = string_to_security_class("context"); + if (!context_class) { + log_it("CRON", getpid(), "ERROR", "Failed to translate security class context", errno); + return rv; + } + entrypoint_bit = string_to_av_perm(file_class, "entrypoint"); + if (!entrypoint_bit) { + log_it("CRON", getpid(), "ERROR", "Failed to translate av perm entrypoint", errno); + return rv; + } + contains_bit = string_to_av_perm(context_class, "contains"); + if (!contains_bit) { + log_it("CRON", getpid(), "ERROR", "Failed to translate av perm contains", errno); + return rv; + } +#endif + return 0; +} + int cron_set_job_security_context(entry * e, user * u, char ***jobenv) { time_t minutely_time = 0; #ifdef WITH_PAM @@ -254,7 +292,7 @@ static int cron_authorize_context(securi #ifdef WITH_SELINUX struct av_decision avd; int retval; - unsigned int bit = FILE__ENTRYPOINT; + /* * Since crontab files are not directly executed, * crond must ensure that the crontab file has @@ -262,9 +300,11 @@ static int cron_authorize_context(securi * the user cron job. It performs an entrypoint * permission check for this purpose. */ + if (!file_class || !entrypoint_bit) + return 0; retval = security_compute_av(scontext, file_context, - SECCLASS_FILE, bit, &avd); - if (retval || ((bit & avd.allowed) != bit)) + file_class, entrypoint_bit, &avd); + if (retval || ((entrypoint_bit & avd.allowed) != entrypoint_bit)) return 0; #endif return 1; @@ -275,16 +315,17 @@ static int cron_authorize_range(security #ifdef WITH_SELINUX struct av_decision avd; int retval; - unsigned int bit = CONTEXT__CONTAINS; /* * Since crontab files are not directly executed, * so crond must ensure that any user specified range * falls within the seusers-specified range for that Linux user. */ + if (!context_class || !contains_bit) + return 0; retval = security_compute_av(scontext, ucontext, - SECCLASS_CONTEXT, bit, &avd); + context_class, contains_bit, &avd); - if (retval || ((bit & avd.allowed) != bit)) + if (retval || ((contains_bit & avd.allowed) != contains_bit)) return 0; #endif return 1; @@ -479,15 +520,22 @@ get_security_context(const char *name, i } if (!cron_authorize_context(scontext, file_context)) { + char *msg=NULL; + if (asprintf(&msg, + "Unauthorized SELinux context=%s file_context=%s", (char *) scontext, file_context) >= 0) { + log_it(name, getpid(), msg, tabname, 0); + free(msg); + } else { + log_it(name, getpid(), "Unauthorized SELinux context", tabname, 0); + } freecon(scontext); freecon(file_context); if (security_getenforce() > 0) { - log_it(name, getpid(), "Unauthorized SELinux context", tabname, 0); return -1; } else { log_it(name, getpid(), - "Unauthorized SELinux context, but SELinux in permissive mode, continuing", + "SELinux in permissive mode, continuing", tabname, 0); return 0; } @@ -515,22 +563,30 @@ int crontab_security_access(void) { security_context_t user_context; if (getprevcon_raw(&user_context) == 0) { security_class_t passwd_class; + access_vector_t crontab_bit; struct av_decision avd; - int retval; + int retval = 0; passwd_class = string_to_security_class("passwd"); if (passwd_class == 0) { - selinux_check_passwd_access = -1; fprintf(stderr, "Security class \"passwd\" is not defined in the SELinux policy.\n"); + retval = -1; + } + + if (retval == 0) { + crontab_bit = string_to_av_perm(passwd_class, "crontab"); + if (crontab_bit == 0) { + fprintf(stderr, "Security av permission \"crontab\" is not defined in the SELinux policy.\n"); + retval = -1; + } } - retval = security_compute_av_raw(user_context, - user_context, - passwd_class, - PASSWD__CRONTAB, - &avd); + if (retval == 0) + retval = security_compute_av_raw(user_context, + user_context, passwd_class, + crontab_bit, &avd); - if ((retval == 0) && ((PASSWD__CRONTAB & avd.allowed) == PASSWD__CRONTAB)) { + if ((retval == 0) && ((crontab_bit & avd.allowed) == crontab_bit)) { selinux_check_passwd_access = 0; } freecon(user_context);