From d39e8e553683fa9816bf54679ee5b963493f46f2 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Tue, 19 Oct 2010 23:34:51 +0000 Subject: pam_selinux.c: rewrite using pam_get_data/pam_set_data * modules/pam_selinux/pam_selinux.c (security_restorelabel_tty, security_label_tty): Remove old functions. (module_data_t): New structure. (free_module_data, cleanup, get_module_data, get_item, set_exec_context, set_file_context, compute_exec_context, compute_tty_context, restore_context, set_context, create_context): New functions. (pam_sm_authenticate, pam_sm_setcred, pam_sm_open_session, pam_sm_close_session): Use them. --- modules/pam_selinux/pam_selinux.c | 602 +++++++++++++++++++++----------------- 1 file changed, 336 insertions(+), 266 deletions(-) diff --git a/modules/pam_selinux/pam_selinux.c b/modules/pam_selinux/pam_selinux.c index b777b01e..a8f540dd 100644 --- a/modules/pam_selinux/pam_selinux.c +++ b/modules/pam_selinux/pam_selinux.c @@ -480,139 +480,301 @@ context_from_env (pam_handle_t *pamh, security_context_t defaultcon, int env_par return newcon; } +#define DATANAME "pam_selinux_context" +typedef struct { + security_context_t exec_context; + security_context_t prev_exec_context; + security_context_t default_user_context; + security_context_t tty_context; + security_context_t prev_tty_context; + char *tty_path; +} module_data_t; + static void -security_restorelabel_tty(const pam_handle_t *pamh, - const char *tty, security_context_t context) +free_module_data(module_data_t *data) +{ + free(data->tty_path); + freecon(data->prev_tty_context); + freecon(data->tty_context); + freecon(data->default_user_context); + freecon(data->prev_exec_context); + if (data->exec_context != data->default_user_context) + freecon(data->exec_context); + memset(data, 0, sizeof(*data)); + free(data); +} + +static void +cleanup(pam_handle_t *pamh UNUSED, void *data, int err UNUSED) +{ + free_module_data(data); +} + +static const module_data_t * +get_module_data(const pam_handle_t *pamh) +{ + const void *data; + + return (pam_get_data(pamh, DATANAME, &data) == PAM_SUCCESS) ? data : NULL; +} + +static const char * +get_item(const pam_handle_t *pamh, int item_type) +{ + const void *item; + + return (pam_get_item(pamh, item_type, &item) == PAM_SUCCESS) ? item : NULL; +} + +static int +set_exec_context(const pam_handle_t *pamh, security_context_t context) +{ + if (setexeccon(context) == 0) + return 0; + pam_syslog(pamh, LOG_ERR, "Setting executable context \"%s\" failed: %m", + context ? context : ""); + return -1; +} + +static int +set_file_context(const pam_handle_t *pamh, security_context_t context, + const char *file) +{ + if (!file) + return 0; + if (setfilecon(file, context) == 0 || errno == ENOENT) + return 0; + pam_syslog(pamh, LOG_ERR, "Setting file context \"%s\" failed for %s: %m", + context ? context : "", file); + return -1; +} + +static int +compute_exec_context(pam_handle_t *pamh, module_data_t *data, + int select_context, int use_current_range, + int env_params, int debug) { - char ttybuf[PATH_MAX]; - const char *ptr; + const char *username; - if (context==NULL) - return; +#ifdef HAVE_GETSEUSER + const char *service; +#endif + char *seuser = NULL; + char *level = NULL; + security_context_t *contextlist = NULL; + int num_contexts = 0; - if(strncmp("/dev/", tty, 5)) { - snprintf(ttybuf,sizeof(ttybuf),"/dev/%s",tty); - ptr = ttybuf; + if (!(username = get_item(pamh, PAM_USER))) { + pam_syslog(pamh, LOG_ERR, "Cannot obtain the user name"); + return PAM_USER_UNKNOWN; } - else - ptr = tty; - if (setfilecon(ptr, context) && errno != ENOENT) - { - pam_syslog(pamh, LOG_NOTICE, - "Warning! Could not relabel %s with %s, not relabeling: %m", - ptr, context); + /* compute execute context */ +#ifdef HAVE_GETSEUSER + if (!(service = get_item(pamh, PAM_SERVICE))) { + pam_syslog(pamh, LOG_ERR, "Cannot obtain the service name"); + return PAM_SESSION_ERR; + } + if (getseuser(username, service, &seuser, &level) == 0) { +#else + if (getseuserbyname(username, &seuser, &level) == 0) { +#endif + num_contexts = get_ordered_context_list_with_level(seuser, level, NULL, + &contextlist); + if (debug) + pam_syslog(pamh, LOG_DEBUG, "Username= %s SELinux User= %s Level= %s", + username, seuser, level); + free(level); + } + if (num_contexts > 0) { + free(seuser); + data->default_user_context = strdup(contextlist[0]); + freeconary(contextlist); + if (!data->default_user_context) { + pam_syslog(pamh, LOG_ERR, "Out of memory"); + return PAM_BUF_ERR; + } + + data->exec_context = data->default_user_context; + if (select_context) + data->exec_context = config_context(pamh, data->default_user_context, + use_current_range, debug); + else if (env_params || use_current_range) + data->exec_context = context_from_env(pamh, data->default_user_context, + env_params, use_current_range, + debug); + } else { + if (seuser) { + data->exec_context = manual_context(pamh, seuser, debug); + free(seuser); + } } + + if (!data->exec_context) { + pam_syslog(pamh, LOG_ERR, "Unable to get valid context for %s", username); + pam_prompt(pamh, PAM_ERROR_MSG, NULL, + _("Unable to get valid context for %s"), username); + } + + if (getexeccon(&data->prev_exec_context) < 0) + data->prev_exec_context = NULL; + + return PAM_SUCCESS; } -static security_context_t -security_label_tty(pam_handle_t *pamh, char *tty, - security_context_t usercon) +static int +compute_tty_context(const pam_handle_t *pamh, module_data_t *data) { - char ttybuf[PATH_MAX]; - int status=0; - security_context_t newdev_context=NULL; /* The new context of a device */ - security_context_t prev_context=NULL; /* The new context of a device */ - const char *ptr; - - if(strncmp("/dev/", tty, 5)) - { - snprintf(ttybuf,sizeof(ttybuf),"/dev/%s",tty); - ptr = ttybuf; + const char *tty = get_item(pamh, PAM_TTY); + + if (!tty || !*tty || !strcmp(tty, "ssh") || !strncmp(tty, "NODEV", 5)) { + tty = ttyname(STDIN_FILENO); + if (!tty || !*tty) + tty = ttyname(STDOUT_FILENO); + if (!tty || !*tty) + tty = ttyname(STDERR_FILENO); + if (!tty || !*tty) + return PAM_SUCCESS; } - else - ptr = tty; - - if (getfilecon(ptr, &prev_context) < 0) - { - if(errno != ENOENT) - pam_syslog(pamh, LOG_NOTICE, - "Warning! Could not get current context for %s, not relabeling: %m", - ptr); - return NULL; + + if (strncmp("/dev/", tty, 5)) { + if (asprintf(&data->tty_path, "%s%s", "/dev/", tty) < 0) + data->tty_path = NULL; + } else { + data->tty_path = strdup(tty); } - if( security_compute_relabel(usercon,prev_context,SECCLASS_CHR_FILE, - &newdev_context)!=0) - { - pam_syslog(pamh, LOG_NOTICE, - "Warning! Could not get new context for %s, not relabeling: %m", - ptr); - pam_syslog(pamh, LOG_NOTICE, - "usercon=%s, prev_context=%s", usercon, prev_context); - freecon(prev_context); - return NULL; + + if (!data->tty_path) { + pam_syslog(pamh, LOG_ERR, "Out of memory"); + return PAM_BUF_ERR; } - status=setfilecon(ptr,newdev_context); - if (status) - { - pam_syslog(pamh, LOG_NOTICE, - "Warning! Could not relabel %s with %s, not relabeling: %m", - ptr,newdev_context); - freecon(prev_context); - prev_context=NULL; + + if (getfilecon(data->tty_path, &data->prev_tty_context) < 0) { + data->prev_tty_context = NULL; + if (errno == ENOENT) { + free(data->tty_path); + data->tty_path = NULL; + return PAM_SUCCESS; + } + pam_syslog(pamh, LOG_ERR, "Failed to get current context for %s: %m", + data->tty_path); + return (security_getenforce() == 1) ? PAM_SESSION_ERR : PAM_SUCCESS; } - freecon(newdev_context); - return prev_context; -} -static security_context_t user_context=NULL; -static security_context_t prev_user_context=NULL; -static security_context_t ttyn_context=NULL; /* The current context of ttyn device */ -static int selinux_enabled=0; -static char *ttyn=NULL; + if (security_compute_relabel(data->exec_context, data->prev_tty_context, + SECCLASS_CHR_FILE, &data->tty_context)) { + data->tty_context = NULL; + pam_syslog(pamh, LOG_ERR, "Failed to compute new context for %s: %m", + data->tty_path); + freecon(data->prev_tty_context); + data->prev_tty_context = NULL; + free(data->tty_path); + data->tty_path = NULL; + return (security_getenforce() == 1) ? PAM_SESSION_ERR : PAM_SUCCESS; + } -PAM_EXTERN int -pam_sm_authenticate(pam_handle_t *pamh UNUSED, int flags UNUSED, - int argc UNUSED, const char **argv UNUSED) + return PAM_SUCCESS; +} + +static int +restore_context(const pam_handle_t *pamh, const module_data_t *data, int debug) { - /* Fail by default. */ - return PAM_AUTH_ERR; + int err; + + if (!data) { + if (debug) + pam_syslog(pamh, LOG_NOTICE, "No context to restore"); + return PAM_SUCCESS; + } + + if (debug && data->tty_path) + pam_syslog(pamh, LOG_NOTICE, + "Restore file context of tty %s: [%s] -> [%s]", + data->tty_path, + data->tty_context ? data->tty_context : "", + data->prev_tty_context ? data->prev_tty_context : ""); + err = set_file_context(pamh, data->prev_tty_context, data->tty_path); + + if (debug) + pam_syslog(pamh, LOG_NOTICE, "Restore executable context: [%s] -> [%s]", + data->exec_context, + data->prev_exec_context ? data->prev_exec_context : ""); + err |= set_exec_context(pamh, data->prev_exec_context); + + if (err && security_getenforce() == 1) + return PAM_SESSION_ERR; + + return PAM_SUCCESS; } -PAM_EXTERN int -pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED, - int argc UNUSED, const char **argv UNUSED) +static int +set_context(pam_handle_t *pamh, const module_data_t *data, + int debug, int verbose) { - return PAM_SUCCESS; + int rc, err; + + if (debug && data->tty_path) + pam_syslog(pamh, LOG_NOTICE, "Set file context of tty %s: [%s] -> [%s]", + data->tty_path, + data->prev_tty_context ? data->prev_tty_context : "", + data->tty_context ? data->tty_context : ""); + err = set_file_context(pamh, data->tty_context, data->tty_path); + + if (debug) + pam_syslog(pamh, LOG_NOTICE, "Set executable context: [%s] -> [%s]", + data->prev_exec_context ? data->prev_exec_context : "", + data->exec_context); + rc = set_exec_context(pamh, data->exec_context); + err |= rc; + + send_audit_message(pamh, !rc, data->default_user_context, data->exec_context); + if (verbose && !rc) { + char msg[PATH_MAX]; + + snprintf(msg, sizeof(msg), + _("Security Context %s Assigned"), data->exec_context); + send_text(pamh, msg, debug); + } +#ifdef HAVE_SETKEYCREATECON + if (debug) + pam_syslog(pamh, LOG_NOTICE, "Set key creation context to %s", + data->exec_context ? data->exec_context : ""); + rc = setkeycreatecon(data->exec_context); + err |= rc; + if (rc) + pam_syslog(pamh, LOG_ERR, "Setting key creation context %s failed: %m", + data->exec_context ? data->exec_context : ""); + if (verbose && !rc) { + char msg[PATH_MAX]; + + snprintf(msg, sizeof(msg), + _("Key Creation Context %s Assigned"), data->exec_context); + send_text(pamh, msg, debug); + } +#endif + + if (err && security_getenforce() == 1) + return PAM_SESSION_ERR; + + return PAM_SUCCESS; } -PAM_EXTERN int -pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, - int argc, const char **argv) +static int +create_context(pam_handle_t *pamh, int argc, const char **argv, + int debug, int verbose) { - int i, debug = 0, ttys=1; - int verbose=0, close_session=0; + int i; + int ttys = 1; 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; - const void *void_username; - const void *tty = NULL; - char *seuser=NULL; - char *level=NULL; - security_context_t default_user_context=NULL; -#ifdef HAVE_GETSEUSER - const void *void_service; - const char *service; -#endif + module_data_t *data; /* Parse arguments. */ for (i = 0; i < argc; i++) { - if (strcmp(argv[i], "debug") == 0) { - debug = 1; - } if (strcmp(argv[i], "nottys") == 0) { ttys = 0; } - if (strcmp(argv[i], "verbose") == 0) { - verbose = 1; - } - if (strcmp(argv[i], "close") == 0) { - close_session = 1; - } if (strcmp(argv[i], "select_context") == 0) { select_context = 1; } @@ -624,171 +786,103 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, } } - if (debug) - pam_syslog(pamh, LOG_NOTICE, "Open Session"); + if (is_selinux_enabled() <= 0) { + if (debug) + pam_syslog(pamh, LOG_NOTICE, "SELinux is not enabled"); + return PAM_SUCCESS; + } if (select_context && env_params) { - pam_syslog(pamh, LOG_ERR, "select_context cannot be used with env_params"); + pam_syslog(pamh, LOG_ERR, + "select_context cannot be used with env_params"); select_context = 0; } - /* this module is only supposed to execute close_session */ - if (close_session) - return PAM_SUCCESS; + if (!(data = calloc(1, sizeof(*data)))) { + pam_syslog(pamh, LOG_ERR, "Out of memory"); + return PAM_BUF_ERR; + } - if (!(selinux_enabled = is_selinux_enabled()>0) ) - return PAM_SUCCESS; + i = compute_exec_context(pamh, data, select_context, use_current_range, + env_params, debug); + if (i != PAM_SUCCESS) { + free_module_data(data); + return i; + } - if (pam_get_item(pamh, PAM_USER, &void_username) != PAM_SUCCESS || - void_username == NULL) { - return PAM_USER_UNKNOWN; + if (!data->exec_context) { + free_module_data(data); + return (security_getenforce() == 1) ? PAM_SESSION_ERR : PAM_SUCCESS; } - username = void_username; -#ifdef HAVE_GETSEUSER - if (pam_get_item(pamh, PAM_SERVICE, (void *) &void_service) != PAM_SUCCESS || - void_service == NULL) { - return PAM_SESSION_ERR; + if (ttys && (i = compute_tty_context(pamh, data)) != PAM_SUCCESS) { + free_module_data(data); + return i; } - service = void_service; - if (getseuser(username, service, &seuser, &level) == 0) { -#else - if (getseuserbyname(username, &seuser, &level) == 0) { -#endif - num_contexts = get_ordered_context_list_with_level(seuser, - level, - NULL, - &contextlist); - if (debug) - pam_syslog(pamh, LOG_DEBUG, "Username= %s SELinux User = %s Level= %s", - username, seuser, level); - free(level); + if ((i = pam_set_data(pamh, DATANAME, data, cleanup)) != PAM_SUCCESS) { + pam_syslog(pamh, LOG_ERR, "Error saving context: %m"); + free_module_data(data); + return i; } - if (num_contexts > 0) { - free(seuser); - default_user_context=strdup(contextlist[0]); - freeconary(contextlist); - if (default_user_context == NULL) { - pam_syslog(pamh, LOG_ERR, "Out of memory"); - return PAM_BUF_ERR; - } - user_context = default_user_context; - 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); - } + return set_context(pamh, data, debug, verbose); +} - if (user_context == NULL) { - freecon(default_user_context); - pam_syslog(pamh, LOG_ERR, "Unable to get valid context for %s", - username); - pam_prompt (pamh, PAM_ERROR_MSG, NULL, _("Unable to get valid context for %s"), username); - if (security_getenforce() == 1) - return PAM_AUTH_ERR; - else - return PAM_SUCCESS; - } - } - else { - if (seuser != NULL) { - user_context = manual_context(pamh,seuser,debug); - free(seuser); - } - if (user_context == NULL) { - pam_syslog (pamh, LOG_ERR, "Unable to get valid context for %s", - username); - if (security_getenforce() == 1) - return PAM_AUTH_ERR; - else - return PAM_SUCCESS; - } - } +PAM_EXTERN int +pam_sm_authenticate(pam_handle_t *pamh UNUSED, int flags UNUSED, + int argc UNUSED, const char **argv UNUSED) +{ + /* Fail by default. */ + return PAM_AUTH_ERR; +} - if (getexeccon(&prev_user_context)<0) { - prev_user_context=NULL; - } - if (ttys) { - /* Get the name of the terminal. */ - if (pam_get_item(pamh, PAM_TTY, &tty) != PAM_SUCCESS) { - tty = NULL; - } +PAM_EXTERN int +pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED, + int argc UNUSED, const char **argv UNUSED) +{ + return PAM_SUCCESS; +} - if ((tty == NULL) || (strlen(tty) == 0) || - strcmp(tty, "ssh") == 0 || strncmp(tty, "NODEV", 5) == 0) { - tty = ttyname(STDIN_FILENO); - if ((tty == NULL) || (strlen(tty) == 0)) { - tty = ttyname(STDOUT_FILENO); - } - if ((tty == NULL) || (strlen(tty) == 0)) { - tty = ttyname(STDERR_FILENO); - } +PAM_EXTERN int +pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, + int argc, const char **argv) +{ + const module_data_t *data; + int i, debug = 0, verbose = 0, close_session = 0; + + /* Parse arguments. */ + for (i = 0; i < argc; i++) { + if (strcmp(argv[i], "debug") == 0) { + debug = 1; } - } - if (ttys && tty) { - ttyn=strdup(tty); - ttyn_context=security_label_tty(pamh,ttyn,user_context); - } - send_audit_message(pamh, 1, default_user_context, user_context); - if (default_user_context != user_context) { - freecon(default_user_context); - } - ret = setexeccon(user_context); - if (ret==0 && verbose) { - char msg[PATH_MAX]; - snprintf(msg, sizeof(msg), - _("Security Context %s Assigned"), user_context); - send_text(pamh, msg, debug); - } - if (ret) { - pam_syslog(pamh, LOG_ERR, - "Error! Unable to set %s executable context %s.", - username, user_context); - if (security_getenforce() == 1) { - freecon(user_context); - return PAM_AUTH_ERR; + if (strcmp(argv[i], "verbose") == 0) { + verbose = 1; } - } else { - if (debug) - pam_syslog(pamh, LOG_NOTICE, "set %s security context to %s", - username, user_context); - } -#ifdef HAVE_SETKEYCREATECON - ret = setkeycreatecon(user_context); - if (ret==0 && verbose) { - char msg[PATH_MAX]; - snprintf(msg, sizeof(msg), - _("Key Creation Context %s Assigned"), user_context); - send_text(pamh, msg, debug); - } - if (ret) { - pam_syslog(pamh, LOG_ERR, - "Error! Unable to set %s key creation context %s.", - username, user_context); - if (security_getenforce() == 1) { - freecon(user_context); - return PAM_AUTH_ERR; + if (strcmp(argv[i], "close") == 0) { + close_session = 1; } - } else { - if (debug) - pam_syslog(pamh, LOG_NOTICE, "set %s key creation context to %s", - username, user_context); } -#endif - freecon(user_context); - return PAM_SUCCESS; + if (debug) + pam_syslog(pamh, LOG_NOTICE, "Open Session"); + + /* Is this module supposed to execute close_session only? */ + if (close_session) + return PAM_SUCCESS; + + data = get_module_data(pamh); + + /* If there is a saved context, this module is supposed to set it again. */ + return data ? set_context(pamh, data, debug, verbose) : + create_context(pamh, argc, argv, debug, verbose); } PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED, int argc, const char **argv) { - int i, debug = 0, status = PAM_SUCCESS, open_session = 0; - if (! (selinux_enabled )) - return PAM_SUCCESS; + int i, debug = 0, open_session = 0; /* Parse arguments. */ for (i = 0; i < argc; i++) { @@ -803,34 +897,10 @@ pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED, if (debug) pam_syslog(pamh, LOG_NOTICE, "Close Session"); + /* Is this module supposed to execute open_session only? */ if (open_session) return PAM_SUCCESS; - if (ttyn) { - if (debug) - pam_syslog(pamh, LOG_NOTICE, "Restore tty %s -> %s", - ttyn,ttyn_context); - - security_restorelabel_tty(pamh,ttyn,ttyn_context); - freecon(ttyn_context); - free(ttyn); - ttyn=NULL; - } - - if (setexeccon(prev_user_context)) { - pam_syslog(pamh, LOG_ERR, "Unable to restore executable context %s.", - prev_user_context ? prev_user_context : ""); - if (security_getenforce() == 1) - status = PAM_AUTH_ERR; - else - status = PAM_SUCCESS; - } else if (debug) - pam_syslog(pamh, LOG_NOTICE, "Executable context back to original"); - - if (prev_user_context) { - freecon(prev_user_context); - prev_user_context = NULL; - } - - return status; + /* Restore original context. */ + return restore_context(pamh, get_module_data(pamh), debug); } -- cgit v1.2.3