diff --git a/pam-1.0.0-selinux-env-params.patch b/pam-1.0.0-selinux-env-params.patch new file mode 100644 index 0000000..0bf0613 --- /dev/null +++ b/pam-1.0.0-selinux-env-params.patch @@ -0,0 +1,561 @@ +Index: modules/pam_selinux/pam_selinux.8.xml +=================================================================== +RCS file: /cvsroot/pam/Linux-PAM/modules/pam_selinux/pam_selinux.8.xml,v +retrieving revision 1.2 +diff -u -p -r1.2 pam_selinux.8.xml +--- modules/pam_selinux/pam_selinux.8.xml 15 Jun 2007 10:17:22 -0000 1.2 ++++ modules/pam_selinux/pam_selinux.8.xml 19 May 2008 15:44:08 -0000 +@@ -37,6 +37,9 @@ + select_context + + ++ env_params ++ ++ + use_current_range + + +@@ -137,12 +140,30 @@ + + + ++ ++ ++ ++ ++ Attempt to obtain a custom security context role from PAM environment. ++ If MLS is on obtain also sensitivity level. This option and the ++ select_context option are mutually exclusive. The respective PAM ++ environment variables are SELINUX_ROLE_REQUESTED, ++ SELINUX_LEVEL_REQUESTED, and ++ SELINUX_USE_CURRENT_RANGE. The first two variables ++ are self describing and the last one if set to 1 makes the PAM module behave as ++ if the use_current_range was specified on the command line of the module. ++ ++ ++ ++ ++ + + + + +- Use the sensitivity range of the process for the user context. +- This option and the select_context option are mutually exclusive. ++ Use the sensitivity level of the current process for the user context ++ instead of the default level. Also supresses asking of the ++ sensitivity level from the user or obtaining it from PAM environment. + + + +Index: modules/pam_selinux/pam_selinux.c +=================================================================== +RCS file: /cvsroot/pam/Linux-PAM/modules/pam_selinux/pam_selinux.c,v +retrieving revision 1.16 +diff -u -p -r1.16 pam_selinux.c +--- modules/pam_selinux/pam_selinux.c 22 Apr 2008 19:21:37 -0000 1.16 ++++ modules/pam_selinux/pam_selinux.c 19 May 2008 15:44:08 -0000 +@@ -2,8 +2,9 @@ + * A module for Linux-PAM that will set the default security context after login + * via PAM. + * +- * Copyright (c) 2003 Red Hat, Inc. ++ * Copyright (c) 2003-2008 Red Hat, Inc. + * Written by Dan Walsh ++ * Additional improvements by Tomas Mraz + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +@@ -138,15 +139,22 @@ send_text (pam_handle_t *pamh, const cha + */ + static int + query_response (pam_handle_t *pamh, const char *text, const char *def, +- char **responses, int debug) ++ char **response, int debug) + { + int rc; + if (def) +- rc = pam_prompt (pamh, PAM_PROMPT_ECHO_ON, responses, "%s [%s] ", text, def); ++ rc = pam_prompt (pamh, PAM_PROMPT_ECHO_ON, response, "%s [%s] ", text, def); + else +- rc = pam_prompt (pamh, PAM_PROMPT_ECHO_ON, responses, "%s ", text); +- if (debug) +- pam_syslog(pamh, LOG_NOTICE, "%s %s", text, responses[0]); ++ rc = pam_prompt (pamh, PAM_PROMPT_ECHO_ON, response, "%s ", text); ++ ++ if (*response == NULL) { ++ rc = PAM_CONV_ERR; ++ } ++ ++ if (rc != PAM_SUCCESS) { ++ pam_syslog(pamh, LOG_WARNING, "No response to query: %s", text); ++ } else if (debug) ++ pam_syslog(pamh, LOG_NOTICE, "%s %s", text, *response); + return rc; + } + +@@ -157,13 +165,15 @@ manual_context (pam_handle_t *pamh, cons + context_t new_context; + int mls_enabled = is_selinux_mls_enabled(); + char *type=NULL; +- char *responses=NULL; ++ char *response=NULL; + + while (1) { +- query_response(pamh, +- _("Would you like to enter a security context? [N] "), NULL, +- &responses,debug); +- if ((responses[0] == 'y') || (responses[0] == 'Y')) ++ if (query_response(pamh, ++ _("Would you like to enter a security context? [N] "), NULL, ++ &response, debug) != PAM_SUCCESS) ++ return NULL; ++ ++ if ((response[0] == 'y') || (response[0] == 'Y')) + { + if (mls_enabled) + new_context = context_new ("user:role:type:level"); +@@ -176,26 +186,29 @@ manual_context (pam_handle_t *pamh, cons + if (context_user_set (new_context, user)) + goto fail_set; + +- _pam_drop(responses); ++ _pam_drop(response); + /* Allow the user to enter each field of the context individually */ +- query_response(pamh,_("role:"), NULL, &responses,debug); +- if (responses[0] != '\0') { +- if (context_role_set (new_context, responses)) ++ if (query_response(pamh, _("role:"), NULL, &response, debug) == PAM_SUCCESS && ++ response[0] != '\0') { ++ if (context_role_set (new_context, response)) + goto fail_set; +- if (get_default_type(responses, &type)) ++ if (get_default_type(response, &type)) + goto fail_set; + if (context_type_set (new_context, type)) + goto fail_set; + } +- _pam_drop(responses); ++ _pam_drop(response); ++ + if (mls_enabled) + { +- query_response(pamh,_("level:"), NULL, &responses,debug); +- if (responses[0] != '\0') { +- if (context_range_set (new_context, responses)) ++ if (query_response(pamh, _("level:"), NULL, &response, debug) == PAM_SUCCESS && ++ response[0] != '\0') { ++ if (context_range_set (new_context, response)) + goto fail_set; + } ++ _pam_drop(response); + } ++ + /* Get the string value of the context and see if it is valid. */ + if (!security_check_context(context_str(new_context))) { + newcon = strdup(context_str(new_context)); +@@ -204,16 +217,17 @@ manual_context (pam_handle_t *pamh, cons + } + else + send_text(pamh,_("Not a valid security context"),debug); +- context_free (new_context); ++ ++ context_free (new_context); + } + else { +- _pam_drop(responses); ++ _pam_drop(response); + return NULL; + } + } /* end while */ + fail_set: + free(type); +- _pam_drop(responses); ++ _pam_drop(response); + context_free (new_context); + return NULL; + } +@@ -239,69 +253,91 @@ static int mls_range_allowed(pam_handle_ + } + + static security_context_t +-config_context (pam_handle_t *pamh, security_context_t puser_context, int debug) ++config_context (pam_handle_t *pamh, security_context_t defaultcon, int use_current_range, int debug) + { + security_context_t newcon=NULL; + context_t new_context; + int mls_enabled = is_selinux_mls_enabled(); +- char *responses=NULL; ++ char *response=NULL; + char *type=NULL; + char resp_val = 0; + +- pam_prompt (pamh, PAM_TEXT_INFO, NULL, _("Default Security Context %s\n"), puser_context); ++ pam_prompt (pamh, PAM_TEXT_INFO, NULL, _("Default Security Context %s\n"), defaultcon); + + while (1) { +- query_response(pamh, ++ if (query_response(pamh, + _("Would you like to enter a different role or level?"), "n", +- &responses,debug); +- +- resp_val = responses[0]; +- _pam_drop(responses); ++ &response, debug) == PAM_SUCCESS) { ++ resp_val = response[0]; ++ _pam_drop(response); ++ } else { ++ resp_val = 'N'; ++ } + if ((resp_val == 'y') || (resp_val == 'Y')) + { +- new_context = context_new(puser_context); +- ++ if ((new_context = context_new(defaultcon)) == NULL) ++ goto fail_set; ++ + /* Allow the user to enter role and level individually */ +- query_response(pamh,_("role:"), context_role_get(new_context), +- &responses, debug); +- if (responses[0]) { +- if (get_default_type(responses, &type)) { +- pam_prompt (pamh, PAM_ERROR_MSG, NULL, _("No default type for role %s\n"), responses); +- _pam_drop(responses); ++ if (query_response(pamh, _("role:"), context_role_get(new_context), ++ &response, debug) == PAM_SUCCESS && response[0]) { ++ if (get_default_type(response, &type)) { ++ pam_prompt (pamh, PAM_ERROR_MSG, NULL, _("No default type for role %s\n"), response); ++ _pam_drop(response); + continue; + } else { +- if (context_role_set(new_context, responses)) ++ if (context_role_set(new_context, response)) + goto fail_set; + if (context_type_set (new_context, type)) + goto fail_set; + } + } +- _pam_drop(responses); ++ _pam_drop(response); ++ + if (mls_enabled) + { +- query_response(pamh,_("level:"), context_range_get(new_context), +- &responses, debug); +- if (responses[0]) { +- if (context_range_set(new_context, responses)) +- goto fail_set; ++ if (use_current_range) { ++ security_context_t mycon = NULL; ++ context_t my_context; ++ ++ if (getcon(&mycon) != 0) ++ goto fail_set; ++ my_context = context_new(mycon); ++ if (my_context == NULL) { ++ freecon(mycon); ++ goto fail_set; ++ } ++ freecon(mycon); ++ if (context_range_set(new_context, context_range_get(my_context))) { ++ context_free(my_context); ++ goto fail_set; ++ } ++ context_free(my_context); ++ } else if (query_response(pamh, _("level:"), context_range_get(new_context), ++ &response, debug) == PAM_SUCCESS && response[0]) { ++ if (context_range_set(new_context, response)) ++ goto fail_set; + } +- _pam_drop(responses); ++ _pam_drop(response); + } ++ + if (debug) + pam_syslog(pamh, LOG_NOTICE, "Selected Security Context %s", context_str(new_context)); + + /* Get the string value of the context and see if it is valid. */ + if (!security_check_context(context_str(new_context))) { + newcon = strdup(context_str(new_context)); +- context_free (new_context); ++ if (newcon == NULL) ++ goto fail_set; ++ context_free(new_context); + + /* we have to check that this user is allowed to go into the + range they have specified ... role is tied to an seuser, so that'll + be checked at setexeccon time */ +- if (mls_enabled && !mls_range_allowed(pamh, puser_context, newcon, debug)) { +- pam_syslog(pamh, LOG_NOTICE, "Security context %s is not allowed for %s", puser_context, newcon); ++ if (mls_enabled && !mls_range_allowed(pamh, defaultcon, newcon, debug)) { ++ pam_syslog(pamh, LOG_NOTICE, "Security context %s is not allowed for %s", defaultcon, newcon); + +- send_audit_message(pamh, 0, puser_context, newcon); ++ send_audit_message(pamh, 0, defaultcon, newcon); + + free(newcon); + goto fail_range; +@@ -309,26 +345,120 @@ config_context (pam_handle_t *pamh, secu + return newcon; + } + else { +- send_audit_message(pamh, 0, puser_context, context_str(new_context)); ++ send_audit_message(pamh, 0, defaultcon, context_str(new_context)); + send_text(pamh,_("Not a valid security context"),debug); + } + context_free(new_context); /* next time around allocates another */ + } + else +- return strdup(puser_context); ++ return strdup(defaultcon); + } /* end while */ + + return NULL; + + fail_set: + free(type); +- _pam_drop(responses); ++ _pam_drop(response); + context_free (new_context); +- send_audit_message(pamh, 0, puser_context, NULL); ++ send_audit_message(pamh, 0, defaultcon, NULL); + fail_range: + return NULL; + } + ++static security_context_t ++context_from_env (pam_handle_t *pamh, security_context_t defaultcon, int env_params, int use_current_range, int debug) ++{ ++ security_context_t newcon = NULL; ++ context_t new_context; ++ context_t my_context = NULL; ++ int mls_enabled = is_selinux_mls_enabled(); ++ const char *env = NULL; ++ char *type = NULL; ++ ++ if ((new_context = context_new(defaultcon)) == NULL) ++ goto fail_set; ++ ++ if (env_params && (env = pam_getenv(pamh, "SELINUX_ROLE_REQUESTED")) != NULL && env[0] != '\0') { ++ if (debug) ++ pam_syslog(pamh, LOG_NOTICE, "Requested role: %s", env); ++ ++ if (get_default_type(env, &type)) { ++ pam_syslog(pamh, LOG_NOTICE, "No default type for role %s", env); ++ goto fail_set; ++ } else { ++ if (context_role_set(new_context, env)) ++ goto fail_set; ++ if (context_type_set(new_context, type)) ++ goto fail_set; ++ } ++ } ++ ++ if (mls_enabled) { ++ if ((env = pam_getenv(pamh, "SELINUX_USE_CURRENT_RANGE")) != NULL && env[0] == '1') { ++ if (debug) ++ pam_syslog(pamh, LOG_NOTICE, "SELINUX_USE_CURRENT_RANGE is set"); ++ use_current_range = 1; ++ } ++ ++ if (use_current_range) { ++ security_context_t mycon = NULL; ++ ++ if (getcon(&mycon) != 0) ++ goto fail_set; ++ my_context = context_new(mycon); ++ if (my_context == NULL) { ++ freecon(mycon); ++ goto fail_set; ++ } ++ freecon(mycon); ++ env = context_range_get(my_context); ++ } else { ++ env = pam_getenv(pamh, "SELINUX_LEVEL_REQUESTED"); ++ } ++ ++ if (env != NULL && env[0] != '\0') { ++ if (debug) ++ pam_syslog(pamh, LOG_NOTICE, "Requested level: %s", env); ++ if (context_range_set(new_context, env)) ++ goto fail_set; ++ } ++ } ++ ++ newcon = strdup(context_str(new_context)); ++ if (newcon == NULL) ++ goto fail_set; ++ ++ if (debug) ++ pam_syslog(pamh, LOG_NOTICE, "Selected Security Context %s", newcon); ++ ++ /* Get the string value of the context and see if it is valid. */ ++ if (security_check_context(newcon)) { ++ pam_syslog(pamh, LOG_NOTICE, "Not a valid security context %s", newcon); ++ send_audit_message(pamh, 0, defaultcon, newcon); ++ freecon(newcon); ++ newcon = NULL; ++ ++ goto fail_set; ++ } ++ ++ /* we have to check that this user is allowed to go into the ++ range they have specified ... role is tied to an seuser, so that'll ++ be checked at setexeccon time */ ++ if (mls_enabled && !mls_range_allowed(pamh, defaultcon, newcon, debug)) { ++ pam_syslog(pamh, LOG_NOTICE, "Security context %s is not allowed for %s", defaultcon, newcon); ++ send_audit_message(pamh, 0, defaultcon, newcon); ++ freecon(newcon); ++ newcon = NULL; ++ } ++ ++ fail_set: ++ free(type); ++ context_free(my_context); ++ context_free(new_context); ++ send_audit_message(pamh, 0, defaultcon, NULL); ++ return newcon; ++} ++ + static void + security_restorelabel_tty(const pam_handle_t *pamh, + const char *tty, security_context_t context) +@@ -439,13 +569,14 @@ PAM_EXTERN int + pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, + int argc, const char **argv) + { +- int i, debug = 0, ttys=1, has_tty=isatty(0); ++ int i, debug = 0, ttys=1; + int verbose=0, close_session=0; + int select_context = 0; + int use_current_range = 0; + int ret = 0; + security_context_t* contextlist = NULL; + int num_contexts = 0; ++ int env_params = 0; + const char *username = NULL; + const void *tty = NULL; + char *seuser=NULL; +@@ -472,13 +603,16 @@ pam_sm_open_session(pam_handle_t *pamh, + if (strcmp(argv[i], "use_current_range") == 0) { + use_current_range = 1; + } ++ if (strcmp(argv[i], "env_params") == 0) { ++ env_params = 1; ++ } + } + + if (debug) + pam_syslog(pamh, LOG_NOTICE, "Open Session"); + +- if (select_context && use_current_range) { +- pam_syslog(pamh, LOG_ERR, "select_context cannot be used with use_current_range"); ++ if (select_context && env_params) { ++ pam_syslog(pamh, LOG_ERR, "select_context cannot be used with env_params"); + select_context = 0; + } + +@@ -510,12 +644,17 @@ pam_sm_open_session(pam_handle_t *pamh, + freeconary(contextlist); + if (default_user_context == NULL) { + pam_syslog(pamh, LOG_ERR, "Out of memory"); +- return PAM_AUTH_ERR; ++ return PAM_BUF_ERR; + } ++ + user_context = default_user_context; +- if (select_context && has_tty) { +- user_context = config_context(pamh, default_user_context, debug); +- if (user_context == NULL) { ++ if (select_context) { ++ user_context = config_context(pamh, default_user_context, use_current_range, debug); ++ } else if (env_params || use_current_range) { ++ user_context = context_from_env(pamh, default_user_context, env_params, use_current_range, debug); ++ } ++ ++ if (user_context == NULL) { + freecon(default_user_context); + pam_syslog(pamh, LOG_ERR, "Unable to get valid context for %s", + username); +@@ -524,11 +663,9 @@ pam_sm_open_session(pam_handle_t *pamh, + return PAM_AUTH_ERR; + else + return PAM_SUCCESS; +- } +- } ++ } + } + else { +- if (has_tty) { + user_context = manual_context(pamh,seuser,debug); + if (user_context == NULL) { + pam_syslog (pamh, LOG_ERR, "Unable to get valid context for %s", +@@ -538,59 +675,6 @@ pam_sm_open_session(pam_handle_t *pamh, + else + return PAM_SUCCESS; + } +- } else { +- pam_syslog (pamh, LOG_ERR, +- "Unable to get valid context for %s, No valid tty", +- username); +- if (security_getenforce() == 1) +- return PAM_AUTH_ERR; +- else +- return PAM_SUCCESS; +- } +- } +- +- if (use_current_range && is_selinux_mls_enabled()) { +- security_context_t process_context=NULL; +- if (getcon(&process_context) == 0) { +- context_t pcon, ucon; +- char *process_level=NULL; +- security_context_t orig_context; +- +- if (user_context) +- orig_context = user_context; +- else +- orig_context = default_user_context; +- +- pcon = context_new(process_context); +- freecon(process_context); +- process_level = strdup(context_range_get(pcon)); +- context_free(pcon); +- +- if (debug) +- pam_syslog (pamh, LOG_DEBUG, "process level=%s", process_level); +- +- ucon = context_new(orig_context); +- +- context_range_set(ucon, process_level); +- free(process_level); +- +- if (!mls_range_allowed(pamh, orig_context, context_str(ucon), debug)) { +- send_text(pamh, _("Requested MLS level not in permitted range"), debug); +- /* even if default_user_context is NULL audit that anyway */ +- send_audit_message(pamh, 0, default_user_context, context_str(ucon)); +- context_free(ucon); +- return PAM_AUTH_ERR; +- } +- +- if (debug) +- pam_syslog (pamh, LOG_DEBUG, "adjusted context=%s", context_str(ucon)); +- +- /* replace the user context with the level adjusted one */ +- freecon(user_context); +- user_context = strdup(context_str(ucon)); +- +- context_free(ucon); +- } + } + + if (getexeccon(&prev_user_context)<0) { +@@ -613,7 +697,7 @@ pam_sm_open_session(pam_handle_t *pamh, + } + } + } +- if(ttys && tty ) { ++ if (ttys && tty) { + ttyn=strdup(tty); + ttyn_context=security_label_tty(pamh,ttyn,user_context); + } diff --git a/pam.spec b/pam.spec index 85d471b..15c1414 100644 --- a/pam.spec +++ b/pam.spec @@ -5,7 +5,7 @@ Summary: A security tool which provides authentication for applications Name: pam Version: 1.0.1 -Release: 2%{?dist} +Release: 3%{?dist} # The library is BSD licensed with option to relicense as GPLv2+ - this option is redundant # as the BSD license allows that anyway. pam_timestamp and pam_console modules are GPLv2+, # pam_rhosts_auth module is BSD with advertising @@ -27,6 +27,7 @@ Patch2: db-4.6.18-glibc.patch Patch4: pam-0.99.8.1-dbpam.patch Patch10: pam-1.0.0-sepermit-screensaver.patch Patch11: pam-1.0.1-selinux-restore-execcon.patch +Patch12: pam-1.0.0-selinux-env-params.patch Patch21: pam-0.99.10.0-unix-audit-failed.patch Patch31: pam-0.99.3.0-cracklib-try-first-pass.patch Patch32: pam-0.99.3.0-tally-fail-close.patch @@ -104,6 +105,7 @@ popd %patch4 -p1 -b .dbpam %patch10 -p1 -b .screensaver %patch11 -p1 -b .restore-execcon +%patch12 -p0 -b .env-params %patch21 -p1 -b .audit-failed %patch31 -p1 -b .try-first-pass %patch32 -p1 -b .fail-close @@ -376,6 +378,9 @@ fi %doc doc/adg/*.txt doc/adg/html %changelog +* Mon May 19 2008 Tomas Mraz 1.0.1-3 +- pam_selinux: add env_params option which will be used by OpenSSH + * Tue Apr 22 2008 Tomas Mraz 1.0.1-2 - pam_selinux: restore execcon properly (#443667)