diff options
Diffstat (limited to 'Linux-PAM/modules/pam_selinux/pam_selinux.c')
-rw-r--r-- | Linux-PAM/modules/pam_selinux/pam_selinux.c | 720 |
1 files changed, 0 insertions, 720 deletions
diff --git a/Linux-PAM/modules/pam_selinux/pam_selinux.c b/Linux-PAM/modules/pam_selinux/pam_selinux.c deleted file mode 100644 index f0935896..00000000 --- a/Linux-PAM/modules/pam_selinux/pam_selinux.c +++ /dev/null @@ -1,720 +0,0 @@ -/****************************************************************************** - * A module for Linux-PAM that will set the default security context after login - * via PAM. - * - * Copyright (c) 2003 Red Hat, Inc. - * Written by Dan Walsh <dwalsh@redhat.com> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "config.h" - -#include <errno.h> -#include <limits.h> -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <syslog.h> - -#define PAM_SM_AUTH -#define PAM_SM_SESSION - -#include <security/pam_modules.h> -#include <security/_pam_macros.h> -#include <security/pam_modutil.h> -#include <security/pam_ext.h> - -#include <selinux/selinux.h> -#include <selinux/get_context_list.h> -#include <selinux/flask.h> -#include <selinux/av_permissions.h> -#include <selinux/selinux.h> -#include <selinux/context.h> -#include <selinux/get_default_type.h> - -#ifdef HAVE_LIBAUDIT -#include <libaudit.h> -#include <sys/select.h> -#include <errno.h> -#endif - -/* Send audit message */ -static - -int send_audit_message(pam_handle_t *pamh, int success, security_context_t default_context, - security_context_t selected_context) -{ - int rc=0; -#ifdef HAVE_LIBAUDIT - char *msg = NULL; - int audit_fd = audit_open(); - security_context_t default_raw=NULL; - security_context_t selected_raw=NULL; - rc = -1; - if (audit_fd < 0) { - if (errno == EINVAL || errno == EPROTONOSUPPORT || - errno == EAFNOSUPPORT) - return 0; /* No audit support in kernel */ - pam_syslog(pamh, LOG_ERR, _("Error connecting to audit system.")); - return rc; - } - if (selinux_trans_to_raw_context(default_context, &default_raw) < 0) { - pam_syslog(pamh, LOG_ERR, _("Error translating default context.")); - default_raw = NULL; - } - if (selinux_trans_to_raw_context(selected_context, &selected_raw) < 0) { - pam_syslog(pamh, LOG_ERR, _("Error translating selected context.")); - selected_raw = NULL; - } - if (asprintf(&msg, "pam: default-context=%s selected-context=%s", - default_raw ? default_raw : (default_context ? default_context : "?"), - selected_raw ? selected_raw : (selected_context ? selected_context : "?")) < 0) { - pam_syslog(pamh, LOG_ERR, ("Error allocating memory.")); - goto out; - } - if (audit_log_user_message(audit_fd, AUDIT_USER_ROLE_CHANGE, - msg, NULL, NULL, NULL, success) <= 0) { - pam_syslog(pamh, LOG_ERR, _("Error sending audit message.")); - goto out; - } - rc = 0; - out: - free(msg); - freecon(default_raw); - freecon(selected_raw); - close(audit_fd); -#else - pam_syslog(pamh, LOG_NOTICE, "pam: default-context=%s selected-context=%s success %d", default_context, selected_context, success); -#endif - return rc; -} -static int -send_text (pam_handle_t *pamh, const char *text, int debug) -{ - if (debug) - pam_syslog(pamh, LOG_NOTICE, "%s", text); - return pam_info (pamh, "%s", text); -} - -/* - * This function sends a message to the user and gets the response. The caller - * is responsible for freeing the responses. - */ -static int -query_response (pam_handle_t *pamh, const char *text, const char *def, - char **responses, int debug) -{ - int rc; - if (def) - rc = pam_prompt (pamh, PAM_PROMPT_ECHO_ON, responses, "%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]); - return rc; -} - -static security_context_t -manual_context (pam_handle_t *pamh, const char *user, int debug) -{ - security_context_t newcon=NULL; - context_t new_context; - int mls_enabled = is_selinux_mls_enabled(); - char *type=NULL; - char *responses=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 (mls_enabled) - new_context = context_new ("user:role:type:level"); - else - new_context = context_new ("user:role:type"); - - if (!new_context) - goto fail_set; - - if (context_user_set (new_context, user)) - goto fail_set; - - _pam_drop(responses); - /* 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)) - goto fail_set; - if (get_default_type(responses, &type)) - goto fail_set; - if (context_type_set (new_context, type)) - goto fail_set; - } - _pam_drop(responses); - if (mls_enabled) - { - query_response(pamh,_("level:"), NULL, &responses,debug); - if (responses[0] != '\0') { - if (context_range_set (new_context, responses)) - goto fail_set; - } - } - /* 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); - return newcon; - } - else - send_text(pamh,_("Not a valid security context"),debug); - context_free (new_context); - } - else { - _pam_drop(responses); - return NULL; - } - } /* end while */ - fail_set: - free(type); - _pam_drop(responses); - context_free (new_context); - return NULL; -} - -static int mls_range_allowed(pam_handle_t *pamh, security_context_t src, security_context_t dst, int debug) -{ - struct av_decision avd; - int retval; - unsigned int bit = CONTEXT__CONTAINS; - context_t src_context = context_new (src); - context_t dst_context = context_new (dst); - context_range_set(dst_context, context_range_get(src_context)); - if (debug) - pam_syslog(pamh, LOG_NOTICE, "Checking if %s mls range valid for %s", dst, context_str(dst_context)); - - retval = security_compute_av(context_str(dst_context), dst, SECCLASS_CONTEXT, bit, &avd); - context_free(src_context); - context_free(dst_context); - if (retval || ((bit & avd.allowed) != bit)) - return 0; - - return 1; -} - -static security_context_t -config_context (pam_handle_t *pamh, security_context_t puser_context, int debug) -{ - security_context_t newcon=NULL; - context_t new_context; - int mls_enabled = is_selinux_mls_enabled(); - char *responses=NULL; - char *type=NULL; - char resp_val = 0; - - pam_prompt (pamh, PAM_TEXT_INFO, NULL, _("Default Security Context %s\n"), puser_context); - - while (1) { - query_response(pamh, - _("Would you like to enter a different role or level?"), "n", - &responses,debug); - - resp_val = responses[0]; - _pam_drop(responses); - if ((resp_val == 'y') || (resp_val == 'Y')) - { - new_context = context_new(puser_context); - - /* 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); - continue; - } else { - if (context_role_set(new_context, responses)) - goto fail_set; - if (context_type_set (new_context, type)) - goto fail_set; - } - } - _pam_drop(responses); - 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; - } - _pam_drop(responses); - } - 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); - - /* 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); - - send_audit_message(pamh, 0, puser_context, newcon); - - free(newcon); - goto fail_range; - } - return newcon; - } - else { - send_audit_message(pamh, 0, puser_context, 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); - } /* end while */ - - return NULL; - - fail_set: - free(type); - _pam_drop(responses); - context_free (new_context); - send_audit_message(pamh, 0, puser_context, NULL); - fail_range: - return NULL; -} - -static void -security_restorelabel_tty(const pam_handle_t *pamh, - const char *tty, security_context_t context) -{ - char ttybuf[PATH_MAX]; - const char *ptr; - - if (context==NULL) - return; - - if(strncmp("/dev/", tty, 5)) { - snprintf(ttybuf,sizeof(ttybuf),"/dev/%s",tty); - ptr = ttybuf; - } - 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); - } -} - -static security_context_t -security_label_tty(pam_handle_t *pamh, char *tty, - security_context_t usercon) -{ - 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; - } - 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( 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; - } - 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; - } - 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; - -/* Tell the user that access has been granted. */ -static void -verbose_message(pam_handle_t *pamh, char *msg, int debug) -{ - if (debug) - pam_syslog(pamh, LOG_NOTICE, msg); - - pam_info (pamh, "%s", msg); -} - -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; -} - -PAM_EXTERN int -pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED, - int argc UNUSED, const char **argv UNUSED) -{ - return PAM_SUCCESS; -} - -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 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; - const char *username = NULL; - const void *tty = NULL; - char *seuser=NULL; - char *level=NULL; - security_context_t default_user_context=NULL; - - /* 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; - } - if (strcmp(argv[i], "use_current_range") == 0) { - use_current_range = 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"); - select_context = 0; - } - - /* this module is only supposed to execute close_session */ - if (close_session) - return PAM_SUCCESS; - - if (!(selinux_enabled = is_selinux_enabled()>0) ) - return PAM_SUCCESS; - - if (pam_get_item(pamh, PAM_USER, (void *) &username) != PAM_SUCCESS || - username == NULL) { - return PAM_USER_UNKNOWN; - } - - if (getseuserbyname(username, &seuser, &level)==0) { - 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(seuser); - free(level); - } - if (num_contexts > 0) { - default_user_context=strdup(contextlist[0]); - freeconary(contextlist); - if (default_user_context == NULL) { - pam_syslog(pamh, LOG_ERR, _("Out of memory")); - return PAM_AUTH_ERR; - } - user_context = default_user_context; - if (select_context && has_tty) { - user_context = config_context(pamh, default_user_context, debug); - 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 (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", - username); - if (security_getenforce() == 1) - return PAM_AUTH_ERR; - 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) { - prev_user_context=NULL; - } - if (ttys) { - /* Get the name of the terminal. */ - if (pam_get_item(pamh, PAM_TTY, &tty) != PAM_SUCCESS) { - tty = NULL; - } - - 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); - } - } - } - 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); - verbose_message(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; - } - } 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); - verbose_message(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; - } - } 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; -} - -PAM_EXTERN int -pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED, - int argc, const char **argv) -{ - int i, debug = 0,status=0, open_session=0; - if (! (selinux_enabled )) - return PAM_SUCCESS; - - /* Parse arguments. */ - for (i = 0; i < argc; i++) { - if (strcmp(argv[i], "debug") == 0) { - debug = 1; - } - if (strcmp(argv[i], "open") == 0) { - open_session = 1; - } - } - - if (debug) - pam_syslog(pamh, LOG_NOTICE, "Close Session"); - - 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; - } - status=setexeccon(prev_user_context); - freecon(prev_user_context); - if (status) { - pam_syslog(pamh, LOG_ERR, "Error! Unable to set executable context %s.", - prev_user_context); - if (security_getenforce() == 1) - return PAM_AUTH_ERR; - else - return PAM_SUCCESS; - } - - if (debug) - pam_syslog(pamh, LOG_NOTICE, "setcontext back to orginal"); - - return PAM_SUCCESS; -} |