]> granicus.if.org Git - linux-pam/commitdiff
Relevant BUGIDs:
authorTomas Mraz <tm@t8m.info>
Fri, 11 Jul 2008 15:37:28 +0000 (15:37 +0000)
committerTomas Mraz <tm@t8m.info>
Fri, 11 Jul 2008 15:37:28 +0000 (15:37 +0000)
Purpose of commit: new feature

Commit summary:
---------------
2008-07-11  Tomas Mraz <t8m@centrum.cz>

        * modules/pam_selinux/pam_selinux.c (config_context): Do not
        ask for the level if use_current_range is set.
        (context_from_env): New function to obtain the context from
        PAM environment variables.
        (pam_sm_open_session): Call context_from_env() if env_params option
        is present. use_current_range now modifies behavior of the
        context_from_env and config_context options.
        * modules/pam_selinux/pam_selinux.8.xml: Describe the env_params
        option. Adjust description of use_current_range option.

ChangeLog
modules/pam_selinux/pam_selinux.8.xml
modules/pam_selinux/pam_selinux.c

index 0301b5816bafe8aef14737a502305e427bfeca20..e493494f1f3066d2ceacc38d8ff292b2ae413d25 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -8,6 +8,16 @@
        * modules/pam_unix/support.h: Define upper limit of fds we will
        attempt to close.
 
+       * modules/pam_selinux/pam_selinux.c (config_context): Do not
+       ask for the level if use_current_range is set.
+       (context_from_env): New function to obtain the context from
+       PAM environment variables.
+       (pam_sm_open_session): Call context_from_env() if env_params option
+       is present. use_current_range now modifies behavior of the
+       context_from_env and config_context options.
+       * modules/pam_selinux/pam_selinux.8.xml: Describe the env_params
+       option. Adjust description of use_current_range option.
+
 2008-07-09  Thorsten Kukuk  <kukuk@thkukuk.de>
 
        * modules/pam_exec/pam_exec.c (call_exec): Move all variable
index 3acd1322f7938fd847b2abc90cf1f8193572955f..ab368a872440b345e401ae0a28b506c37a9f2470 100644 (file)
@@ -36,6 +36,9 @@
       <arg choice="opt">
        select_context
       </arg>
+      <arg choice="opt">
+       env_params
+      </arg>
       <arg choice="opt">
        use_current_range
       </arg>
           </para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term>
+          <option>env_params</option>
+        </term>
+        <listitem>
+          <para>
+            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 <emphasis>SELINUX_ROLE_REQUESTED</emphasis>,
+            <emphasis>SELINUX_LEVEL_REQUESTED</emphasis>, and
+            <emphasis>SELINUX_USE_CURRENT_RANGE</emphasis>. 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.
+          </para>
+        </listitem>
+      </varlistentry>
       <varlistentry>
         <term>
           <option>use_current_range</option>
         </term>
         <listitem>
           <para>
-            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.
           </para>
         </listitem>
       </varlistentry>
index da1290f01e52351cbe0faa030985b78d91556317..e45d6f991684b0b0865157ca364e3efc376a7c8d 100644 (file)
@@ -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 <dwalsh@redhat.com>
+ * Additional improvements by Tomas Mraz <tmraz@redhat.com>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -252,7 +253,7 @@ static int mls_range_allowed(pam_handle_t *pamh, security_context_t src, securit
 }
 
 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;
@@ -261,7 +262,7 @@ config_context (pam_handle_t *pamh, security_context_t puser_context, int debug)
   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) {
     if (query_response(pamh,
@@ -274,7 +275,7 @@ config_context (pam_handle_t *pamh, security_context_t puser_context, int debug)
     }
     if ((resp_val == 'y') || (resp_val == 'Y'))
       {
-        if ((new_context = context_new(puser_context)) == NULL)
+        if ((new_context = context_new(defaultcon)) == NULL)
            goto fail_set;
 
        /* Allow the user to enter role and level individually */
@@ -295,10 +296,27 @@ config_context (pam_handle_t *pamh, security_context_t puser_context, int debug)
 
        if (mls_enabled)
          {
-           if (query_response(pamh, _("level:"), context_range_get(new_context), 
+           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;
+               if (context_range_set(new_context, response))
+                   goto fail_set;
            } 
            _pam_drop(response);
          }
@@ -309,15 +327,17 @@ config_context (pam_handle_t *pamh, security_context_t puser_context, int debug)
         /* 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;
@@ -325,13 +345,13 @@ config_context (pam_handle_t *pamh, security_context_t puser_context, int debug)
          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;
@@ -340,11 +360,105 @@ config_context (pam_handle_t *pamh, security_context_t puser_context, int debug)
   free(type);
   _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)
@@ -462,6 +576,7 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
   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;
@@ -488,13 +603,16 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
     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;
   }
 
@@ -526,12 +644,17 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
     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) {
-      user_context = config_context(pamh, default_user_context, debug);
-      if (user_context == NULL) {
+        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);
@@ -540,8 +663,7 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
           return PAM_AUTH_ERR;
         else
           return PAM_SUCCESS;
-      }
-    } 
+    }
   }
   else { 
       user_context = manual_context(pamh,seuser,debug);
@@ -555,50 +677,6 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
       }
   }
 
-  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;
   }