(root)/
Linux-PAM-1.5.3/
modules/
pam_selinux/
pam_selinux.c
       1  /******************************************************************************
       2   * A module for Linux-PAM that will set the default security context after login
       3   * via PAM.
       4   *
       5   * Copyright (c) 2003-2008 Red Hat, Inc.
       6   * Written by Dan Walsh <dwalsh@redhat.com>
       7   * Additional improvements by Tomas Mraz <tmraz@redhat.com>
       8   *
       9   * Redistribution and use in source and binary forms, with or without
      10   * modification, are permitted provided that the following conditions
      11   * are met:
      12   * 1. Redistributions of source code must retain the above copyright
      13   *    notice, and the entire permission notice in its entirety,
      14   *    including the disclaimer of warranties.
      15   * 2. Redistributions in binary form must reproduce the above copyright
      16   *    notice, this list of conditions and the following disclaimer in the
      17   *    documentation and/or other materials provided with the distribution.
      18   * 3. The name of the author may not be used to endorse or promote
      19   *    products derived from this software without specific prior
      20   *    written permission.
      21   *
      22   * ALTERNATIVELY, this product may be distributed under the terms of
      23   * the GNU Public License, in which case the provisions of the GPL are
      24   * required INSTEAD OF the above restrictions.  (This clause is
      25   * necessary due to a potential bad interaction between the GPL and
      26   * the restrictions contained in a BSD-style copyright.)
      27   *
      28   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
      29   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      30   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      31   * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
      32   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      33   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      34   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      35   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
      36   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      37   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
      38   * OF THE POSSIBILITY OF SUCH DAMAGE.
      39   */
      40  
      41  #include "config.h"
      42  
      43  #include <errno.h>
      44  #include <limits.h>
      45  #include <pwd.h>
      46  #include <stdio.h>
      47  #include <stdlib.h>
      48  #include <string.h>
      49  #include <unistd.h>
      50  #include <sys/types.h>
      51  #include <sys/stat.h>
      52  #include <fcntl.h>
      53  #include <syslog.h>
      54  
      55  #include <security/pam_modules.h>
      56  #include <security/_pam_macros.h>
      57  #include <security/pam_modutil.h>
      58  #include <security/pam_ext.h>
      59  #include "pam_inline.h"
      60  
      61  #include <selinux/selinux.h>
      62  #include <selinux/get_context_list.h>
      63  #include <selinux/context.h>
      64  #include <selinux/get_default_type.h>
      65  
      66  #ifdef HAVE_LIBAUDIT
      67  #include <libaudit.h>
      68  #include <sys/select.h>
      69  #endif
      70  
      71  /* Send audit message */
      72  static void
      73  send_audit_message(const pam_handle_t *pamh, int success, const char *default_context,
      74  		   const char *selected_context)
      75  {
      76  #ifdef HAVE_LIBAUDIT
      77  	char *msg = NULL;
      78  	int audit_fd = audit_open();
      79  	char *default_raw = NULL;
      80  	char *selected_raw = NULL;
      81  	const void *tty = NULL, *rhost = NULL;
      82  	if (audit_fd < 0) {
      83  		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
      84                                          errno == EAFNOSUPPORT) {
      85  			goto fallback; /* No audit support in kernel */
      86  		}
      87  		pam_syslog(pamh, LOG_ERR, "Error connecting to audit system: %m");
      88  		goto fallback;
      89  	}
      90  	(void)pam_get_item(pamh, PAM_TTY, &tty);
      91  	(void)pam_get_item(pamh, PAM_RHOST, &rhost);
      92  	if (selinux_trans_to_raw_context(default_context, &default_raw) < 0) {
      93  		pam_syslog(pamh, LOG_ERR, "Error translating default context '%s'.", default_context);
      94  		default_raw = NULL;
      95  	}
      96  	if (selinux_trans_to_raw_context(selected_context, &selected_raw) < 0) {
      97  		pam_syslog(pamh, LOG_ERR, "Error translating selected context '%s'.", selected_context);
      98  		selected_raw = NULL;
      99  	}
     100  	if (asprintf(&msg, "pam: default-context=%s selected-context=%s",
     101  		     default_raw ? default_raw : (default_context ? default_context : "?"),
     102  		     selected_raw ? selected_raw : (selected_context ? selected_context : "?")) < 0) {
     103  		msg = NULL; /* asprintf leaves msg in undefined state on failure */
     104  		pam_syslog(pamh, LOG_ERR, "Error allocating memory.");
     105  		goto fallback;
     106  	}
     107  	if (audit_log_user_message(audit_fd, AUDIT_USER_ROLE_CHANGE,
     108  				   msg, rhost, NULL, tty, success) <= 0) {
     109  		pam_syslog(pamh, LOG_ERR, "Error sending audit message: %m");
     110  		goto fallback;
     111  	}
     112  	goto cleanup;
     113  
     114        fallback:
     115  #endif /* HAVE_LIBAUDIT */
     116          pam_syslog(pamh, LOG_NOTICE, "pam: default-context=%s selected-context=%s success %d",
     117  		   default_context, selected_context, success);
     118  
     119  #ifdef HAVE_LIBAUDIT
     120        cleanup:
     121  	free(msg);
     122  	freecon(default_raw);
     123  	freecon(selected_raw);
     124  	if (audit_fd >= 0)
     125  		close(audit_fd);
     126  #endif /* HAVE_LIBAUDIT */
     127  }
     128  
     129  static int
     130  send_text (pam_handle_t *pamh, const char *text, int debug)
     131  {
     132    if (debug)
     133      pam_syslog(pamh, LOG_NOTICE, "%s", text);
     134    return pam_info (pamh, "%s", text);
     135  }
     136  
     137  /*
     138   * This function sends a message to the user and gets the response. The caller
     139   * is responsible for freeing the responses.
     140   */
     141  static int
     142  query_response (pam_handle_t *pamh, const char *text, const char *def,
     143  		char **response, int debug)
     144  {
     145    int rc;
     146    if (def)
     147      rc = pam_prompt (pamh, PAM_PROMPT_ECHO_ON, response, "%s [%s] ", text, def);
     148    else
     149      rc = pam_prompt (pamh, PAM_PROMPT_ECHO_ON, response, "%s ", text);
     150  
     151    if (*response == NULL) {
     152      rc = PAM_CONV_ERR;
     153    }
     154  
     155    if (rc != PAM_SUCCESS) {
     156      pam_syslog(pamh, LOG_WARNING, "No response to query: %s", text);
     157    } else  if (debug)
     158      pam_syslog(pamh, LOG_NOTICE, "%s %s", text, *response);
     159    return rc;
     160  }
     161  
     162  static char *
     163  config_context (pam_handle_t *pamh, const char *defaultcon, int use_current_range, int debug)
     164  {
     165    char *newcon = NULL;
     166    context_t new_context;
     167    int mls_enabled = is_selinux_mls_enabled();
     168    char *response=NULL;
     169    char *type=NULL;
     170    char resp_val = 0;
     171  
     172    pam_prompt (pamh, PAM_TEXT_INFO, NULL, _("The default security context is %s."), defaultcon);
     173  
     174    while (1) {
     175      if (query_response(pamh,
     176  		   _("Would you like to enter a different role or level?"), "n",
     177  		   &response, debug) == PAM_SUCCESS) {
     178  	resp_val = response[0];
     179  	_pam_drop(response);
     180      } else {
     181  	resp_val = 'N';
     182      }
     183      if ((resp_val == 'y') || (resp_val == 'Y'))
     184        {
     185          if ((new_context = context_new(defaultcon)) == NULL)
     186  	    goto fail_set;
     187  
     188  	/* Allow the user to enter role and level individually */
     189  	if (query_response(pamh, _("role:"), context_role_get(new_context),
     190  		       &response, debug) == PAM_SUCCESS && response[0]) {
     191  	  if (get_default_type(response, &type)) {
     192  	    pam_prompt(pamh, PAM_ERROR_MSG, NULL,
     193  		       _("There is no default type for role %s."), response);
     194  	    _pam_drop(response);
     195  	    continue;
     196  	  } else {
     197  	    if (context_role_set(new_context, response))
     198  	      goto fail_set;
     199  	    if (context_type_set (new_context, type))
     200  	      goto fail_set;
     201  	    _pam_drop(type);
     202  	  }
     203  	}
     204  	_pam_drop(response);
     205  
     206  	if (mls_enabled)
     207  	  {
     208  	    if (use_current_range) {
     209  	        char *mycon = NULL;
     210  	        context_t my_context;
     211  
     212  		if (getcon(&mycon) != 0)
     213  		    goto fail_set;
     214  		my_context = context_new(mycon);
     215  	        if (my_context == NULL) {
     216  		    freecon(mycon);
     217  		    goto fail_set;
     218  		}
     219  		freecon(mycon);
     220  		if (context_range_set(new_context, context_range_get(my_context))) {
     221  		    context_free(my_context);
     222  		    goto fail_set;
     223  		}
     224  		context_free(my_context);
     225  	    } else if (query_response(pamh, _("level:"), context_range_get(new_context),
     226  			   &response, debug) == PAM_SUCCESS && response[0]) {
     227  		if (context_range_set(new_context, response))
     228  		    goto fail_set;
     229  	    }
     230  	    _pam_drop(response);
     231  	  }
     232  
     233  	if (debug)
     234  	  pam_syslog(pamh, LOG_NOTICE, "Selected Security Context %s", context_str(new_context));
     235  
     236          /* Get the string value of the context and see if it is valid. */
     237          if (!security_check_context(context_str(new_context))) {
     238  	  newcon = strdup(context_str(new_context));
     239  	  if (newcon == NULL)
     240  	    goto fail_set;
     241  	  context_free(new_context);
     242  
     243  	  /* we have to check that this user is allowed to go into the
     244  	     range they have specified ... role is tied to an seuser, so that'll
     245  	     be checked at setexeccon time */
     246  	  if (mls_enabled &&
     247  	      selinux_check_access(defaultcon, newcon, "context", "contains", NULL) != 0) {
     248  	    pam_syslog(pamh, LOG_NOTICE, "Security context %s is not allowed for %s", defaultcon, newcon);
     249  
     250  	    send_audit_message(pamh, 0, defaultcon, newcon);
     251  
     252  	    free(newcon);
     253  	    goto fail_range;
     254  	  }
     255  	  return newcon;
     256  	}
     257  	else {
     258  	  send_audit_message(pamh, 0, defaultcon, context_str(new_context));
     259  	  send_text(pamh,_("This is not a valid security context."),debug);
     260  	}
     261          context_free(new_context); /* next time around allocates another */
     262        }
     263      else
     264        return strdup(defaultcon);
     265    } /* end while */
     266  
     267    return NULL;
     268  
     269   fail_set:
     270    free(type);
     271    _pam_drop(response);
     272    context_free (new_context);
     273    send_audit_message(pamh, 0, defaultcon, NULL);
     274   fail_range:
     275    return NULL;
     276  }
     277  
     278  static char *
     279  context_from_env (pam_handle_t *pamh, const char *defaultcon, int env_params, int use_current_range, int debug)
     280  {
     281    char *newcon = NULL;
     282    context_t new_context;
     283    context_t my_context = NULL;
     284    int mls_enabled = is_selinux_mls_enabled();
     285    const char *env = NULL;
     286    char *type = NULL;
     287    int fail = 1;
     288  
     289    if ((new_context = context_new(defaultcon)) == NULL)
     290      goto fail_set;
     291  
     292    if (env_params && (env = pam_getenv(pamh, "SELINUX_ROLE_REQUESTED")) != NULL && env[0] != '\0') {
     293      if (debug)
     294  	pam_syslog(pamh, LOG_NOTICE, "Requested role: %s", env);
     295  
     296      if (get_default_type(env, &type)) {
     297  	pam_syslog(pamh, LOG_NOTICE, "No default type for role %s", env);
     298  	goto fail_set;
     299      } else {
     300  	if (context_role_set(new_context, env))
     301  	    goto fail_set;
     302  	if (context_type_set(new_context, type))
     303  	    goto fail_set;
     304      }
     305    }
     306  
     307    if (mls_enabled) {
     308      if ((env = pam_getenv(pamh, "SELINUX_USE_CURRENT_RANGE")) != NULL && env[0] == '1') {
     309          if (debug)
     310  	    pam_syslog(pamh, LOG_NOTICE, "SELINUX_USE_CURRENT_RANGE is set");
     311  	use_current_range = 1;
     312      }
     313  
     314      if (use_current_range) {
     315          char *mycon = NULL;
     316  
     317  	if (getcon(&mycon) != 0)
     318  	    goto fail_set;
     319          my_context = context_new(mycon);
     320          if (my_context == NULL) {
     321              freecon(mycon);
     322  	    goto fail_set;
     323  	}
     324  	freecon(mycon);
     325  	env = context_range_get(my_context);
     326      } else {
     327          env = pam_getenv(pamh, "SELINUX_LEVEL_REQUESTED");
     328      }
     329  
     330      if (env != NULL && env[0] != '\0') {
     331          if (debug)
     332  	    pam_syslog(pamh, LOG_NOTICE, "Requested level: %s", env);
     333  	if (context_range_set(new_context, env))
     334  	    goto fail_set;
     335      }
     336    }
     337  
     338    newcon = strdup(context_str(new_context));
     339    if (newcon == NULL)
     340      goto fail_set;
     341  
     342    if (debug)
     343      pam_syslog(pamh, LOG_NOTICE, "Selected Security Context %s", newcon);
     344  
     345    /* Get the string value of the context and see if it is valid. */
     346    if (security_check_context(newcon)) {
     347      pam_syslog(pamh, LOG_NOTICE, "Not a valid security context %s", newcon);
     348  
     349      goto fail_set;
     350    }
     351  
     352    /* we have to check that this user is allowed to go into the
     353       range they have specified ... role is tied to an seuser, so that'll
     354       be checked at setexeccon time */
     355    if (mls_enabled &&
     356        selinux_check_access(defaultcon, newcon, "context", "contains", NULL) != 0) {
     357      pam_syslog(pamh, LOG_NOTICE, "Security context %s is not allowed for %s", defaultcon, newcon);
     358  
     359      goto fail_set;
     360    }
     361  
     362    fail = 0;
     363  
     364   fail_set:
     365    free(type);
     366    context_free(my_context);
     367    context_free(new_context);
     368    if (fail) {
     369      send_audit_message(pamh, 0, defaultcon, newcon);
     370      freecon(newcon);
     371      newcon = NULL;
     372    }
     373    return newcon;
     374  }
     375  
     376  #define DATANAME "pam_selinux_context"
     377  typedef struct {
     378    char *exec_context;
     379    char *prev_exec_context;
     380    char *default_user_context;
     381    char *tty_context;
     382    char *prev_tty_context;
     383    char *tty_path;
     384  } module_data_t;
     385  
     386  static void
     387  free_module_data(module_data_t *data)
     388  {
     389    free(data->tty_path);
     390    freecon(data->prev_tty_context);
     391    freecon(data->tty_context);
     392    freecon(data->default_user_context);
     393    freecon(data->prev_exec_context);
     394    if (data->exec_context != data->default_user_context)
     395      freecon(data->exec_context);
     396    free(data);
     397  }
     398  
     399  static void
     400  cleanup(pam_handle_t *pamh UNUSED, void *data, int err UNUSED)
     401  {
     402    free_module_data(data);
     403  }
     404  
     405  static const module_data_t *
     406  get_module_data(const pam_handle_t *pamh)
     407  {
     408    const void *data;
     409  
     410    return (pam_get_data(pamh, DATANAME, &data) == PAM_SUCCESS) ? data : NULL;
     411  }
     412  
     413  static const char *
     414  get_item(const pam_handle_t *pamh, int item_type)
     415  {
     416    const void *item;
     417  
     418    return (pam_get_item(pamh, item_type, &item) == PAM_SUCCESS) ? item : NULL;
     419  }
     420  
     421  static int
     422  set_exec_context(const pam_handle_t *pamh, const char *context)
     423  {
     424    if (setexeccon(context) == 0)
     425      return 0;
     426    pam_syslog(pamh, LOG_ERR, "Setting executable context \"%s\" failed: %m",
     427  	     context ? context : "");
     428    return -1;
     429  }
     430  
     431  static int
     432  set_file_context(const pam_handle_t *pamh, const char *context,
     433  		 const char *file)
     434  {
     435    if (!file)
     436      return 0;
     437    if (setfilecon(file, context) == 0 || errno == ENOENT)
     438      return 0;
     439    pam_syslog(pamh, LOG_ERR, "Setting file context \"%s\" failed for %s: %m",
     440  	     context ? context : "", file);
     441    return -1;
     442  }
     443  
     444  static int
     445  compute_exec_context(pam_handle_t *pamh, module_data_t *data,
     446  		     int select_context, int use_current_range,
     447  		     int env_params, int debug)
     448  {
     449    const char *username;
     450  
     451  #ifdef HAVE_GETSEUSER
     452    const char *service;
     453  #endif
     454    char *seuser = NULL;
     455    char *level = NULL;
     456    char **contextlist = NULL;
     457    int num_contexts = 0;
     458    const struct passwd *pwd;
     459  
     460    if (!(username = get_item(pamh, PAM_USER))) {
     461      pam_syslog(pamh, LOG_ERR, "Cannot obtain the user name");
     462      return PAM_USER_UNKNOWN;
     463    }
     464  
     465    if ((pwd = pam_modutil_getpwnam(pamh, username)) != NULL) {
     466      username = pwd->pw_name;
     467    } /* ignore error and keep using original username */
     468  
     469    /* compute execute context */
     470  #ifdef HAVE_GETSEUSER
     471    if (!(service = get_item(pamh, PAM_SERVICE))) {
     472      pam_syslog(pamh, LOG_ERR, "Cannot obtain the service name");
     473      return PAM_SESSION_ERR;
     474    }
     475    if (getseuser(username, service, &seuser, &level) == 0) {
     476  #else
     477    if (getseuserbyname(username, &seuser, &level) == 0) {
     478  #endif
     479      num_contexts = get_ordered_context_list_with_level(seuser, level, NULL,
     480  						       &contextlist);
     481      if (debug)
     482        pam_syslog(pamh, LOG_DEBUG, "Username= %s SELinux User= %s Level= %s",
     483  		 username, seuser, level);
     484      free(level);
     485    }
     486    if (num_contexts > 0) {
     487      free(seuser);
     488      data->default_user_context = strdup(contextlist[0]);
     489      freeconary(contextlist);
     490      if (!data->default_user_context) {
     491        pam_syslog(pamh, LOG_CRIT, "Out of memory");
     492        return PAM_BUF_ERR;
     493      }
     494  
     495      data->exec_context = data->default_user_context;
     496      if (select_context)
     497        data->exec_context = config_context(pamh, data->default_user_context,
     498  					  use_current_range, debug);
     499      else if (env_params || use_current_range)
     500        data->exec_context = context_from_env(pamh, data->default_user_context,
     501  					    env_params, use_current_range,
     502  					    debug);
     503    }
     504  
     505    if (!data->exec_context) {
     506      pam_syslog(pamh, LOG_ERR, "Unable to get valid context for %s", username);
     507      pam_prompt(pamh, PAM_ERROR_MSG, NULL,
     508  	       _("A valid context for %s could not be obtained."), username);
     509    }
     510  
     511    if (getexeccon(&data->prev_exec_context) < 0)
     512      data->prev_exec_context = NULL;
     513  
     514    return PAM_SUCCESS;
     515  }
     516  
     517  static int
     518  compute_tty_context(const pam_handle_t *pamh, module_data_t *data)
     519  {
     520    const char *tty = get_item(pamh, PAM_TTY);
     521    security_class_t tclass;
     522  
     523    if (!tty || !*tty || !strcmp(tty, "ssh")
     524        || pam_str_skip_prefix(tty, "NODEV") != NULL) {
     525      tty = ttyname(STDIN_FILENO);
     526      if (!tty || !*tty)
     527        tty = ttyname(STDOUT_FILENO);
     528      if (!tty || !*tty)
     529        tty = ttyname(STDERR_FILENO);
     530      if (!tty || !*tty)
     531        return PAM_SUCCESS;
     532    }
     533  
     534    if (pam_str_skip_prefix(tty, "/dev/") == NULL) {
     535      if (asprintf(&data->tty_path, "%s%s", "/dev/", tty) < 0)
     536        data->tty_path = NULL;
     537    } else {
     538      data->tty_path = strdup(tty);
     539    }
     540  
     541    if (!data->tty_path) {
     542      pam_syslog(pamh, LOG_CRIT, "Out of memory");
     543      return PAM_BUF_ERR;
     544    }
     545  
     546    if (getfilecon(data->tty_path, &data->prev_tty_context) < 0) {
     547      data->prev_tty_context = NULL;
     548      if (errno == ENOENT) {
     549        free(data->tty_path);
     550        data->tty_path = NULL;
     551        return PAM_SUCCESS;
     552      }
     553      pam_syslog(pamh, LOG_ERR, "Failed to get current context for %s: %m",
     554  	       data->tty_path);
     555      return (security_getenforce() != 0) ? PAM_SESSION_ERR : PAM_SUCCESS;
     556    }
     557  
     558    tclass = string_to_security_class("chr_file");
     559    if (tclass == 0) {
     560      pam_syslog(pamh, LOG_ERR, "Failed to get chr_file security class");
     561      freecon(data->prev_tty_context);
     562      data->prev_tty_context = NULL;
     563      free(data->tty_path);
     564      data->tty_path = NULL;
     565      return (security_getenforce() != 0) ? PAM_SESSION_ERR : PAM_SUCCESS;
     566    }
     567  
     568    if (security_compute_relabel(data->exec_context, data->prev_tty_context,
     569  			       tclass, &data->tty_context)) {
     570      data->tty_context = NULL;
     571      pam_syslog(pamh, LOG_ERR, "Failed to compute new context for %s: %m",
     572  	       data->tty_path);
     573      freecon(data->prev_tty_context);
     574      data->prev_tty_context = NULL;
     575      free(data->tty_path);
     576      data->tty_path = NULL;
     577      return (security_getenforce() != 0) ? PAM_SESSION_ERR : PAM_SUCCESS;
     578    }
     579  
     580    return PAM_SUCCESS;
     581  }
     582  
     583  static int
     584  restore_context(const pam_handle_t *pamh, const module_data_t *data, int debug)
     585  {
     586    int err;
     587  
     588    if (!data) {
     589      if (debug)
     590        pam_syslog(pamh, LOG_NOTICE, "No context to restore");
     591      return PAM_SUCCESS;
     592    }
     593  
     594    if (debug && data->tty_path)
     595      pam_syslog(pamh, LOG_NOTICE,
     596  	       "Restore file context of tty %s: [%s] -> [%s]",
     597  	       data->tty_path,
     598  	       data->tty_context ? data->tty_context : "",
     599  	       data->prev_tty_context ? data->prev_tty_context : "");
     600    err = set_file_context(pamh, data->prev_tty_context, data->tty_path);
     601  
     602    if (debug)
     603      pam_syslog(pamh, LOG_NOTICE, "Restore executable context: [%s] -> [%s]",
     604  	       data->exec_context,
     605  	       data->prev_exec_context ? data->prev_exec_context : "");
     606    err |= set_exec_context(pamh, data->prev_exec_context);
     607  
     608    if (err && security_getenforce() != 0)
     609      return PAM_SESSION_ERR;
     610  
     611    return PAM_SUCCESS;
     612  }
     613  
     614  static int
     615  set_context(pam_handle_t *pamh, const module_data_t *data,
     616  	    int debug, int verbose)
     617  {
     618    int rc, err;
     619  
     620    if (debug && data->tty_path)
     621      pam_syslog(pamh, LOG_NOTICE, "Set file context of tty %s: [%s] -> [%s]",
     622  	       data->tty_path,
     623  	       data->prev_tty_context ? data->prev_tty_context : "",
     624  	       data->tty_context ? data->tty_context : "");
     625    err = set_file_context(pamh, data->tty_context, data->tty_path);
     626  
     627    if (debug)
     628      pam_syslog(pamh, LOG_NOTICE, "Set executable context: [%s] -> [%s]",
     629  	       data->prev_exec_context ? data->prev_exec_context : "",
     630  	       data->exec_context);
     631    rc = set_exec_context(pamh, data->exec_context);
     632    err |= rc;
     633  
     634    send_audit_message(pamh, !rc, data->default_user_context, data->exec_context);
     635    if (verbose && !rc) {
     636      char msg[PATH_MAX];
     637  
     638      snprintf(msg, sizeof(msg),
     639  	     _("Security context %s has been assigned."), data->exec_context);
     640      send_text(pamh, msg, debug);
     641    }
     642  #ifdef HAVE_SETKEYCREATECON
     643    if (debug)
     644      pam_syslog(pamh, LOG_NOTICE, "Set key creation context to %s",
     645  	       data->exec_context ? data->exec_context : "");
     646    rc = setkeycreatecon(data->exec_context);
     647    err |= rc;
     648    if (rc)
     649      pam_syslog(pamh, LOG_ERR, "Setting key creation context %s failed: %m",
     650  	       data->exec_context ? data->exec_context : "");
     651    if (verbose && !rc) {
     652      char msg[PATH_MAX];
     653  
     654      snprintf(msg, sizeof(msg),
     655  	     _("Key creation context %s has been assigned."), data->exec_context);
     656      send_text(pamh, msg, debug);
     657    }
     658  #endif
     659  
     660    if (err && security_getenforce() != 0)
     661      return PAM_SESSION_ERR;
     662  
     663    return PAM_SUCCESS;
     664  }
     665  
     666  static int
     667  create_context(pam_handle_t *pamh, int argc, const char **argv,
     668  	       int debug, int verbose)
     669  {
     670    int i;
     671    int ttys = 1;
     672    int select_context = 0;
     673    int use_current_range = 0;
     674    int env_params = 0;
     675    module_data_t *data;
     676  
     677    /* Parse arguments. */
     678    for (i = 0; i < argc; i++) {
     679      if (strcmp(argv[i], "nottys") == 0) {
     680        ttys = 0;
     681      }
     682      if (strcmp(argv[i], "select_context") == 0) {
     683        select_context = 1;
     684      }
     685      if (strcmp(argv[i], "use_current_range") == 0) {
     686        use_current_range = 1;
     687      }
     688      if (strcmp(argv[i], "env_params") == 0) {
     689        env_params = 1;
     690      }
     691    }
     692  
     693    if (is_selinux_enabled() <= 0) {
     694      if (debug)
     695        pam_syslog(pamh, LOG_NOTICE, "SELinux is not enabled");
     696      return PAM_SUCCESS;
     697    }
     698  
     699    if (select_context && env_params) {
     700      pam_syslog(pamh, LOG_ERR,
     701  	       "select_context cannot be used with env_params");
     702      select_context = 0;
     703    }
     704  
     705    if (!(data = calloc(1, sizeof(*data)))) {
     706      pam_syslog(pamh, LOG_CRIT, "Out of memory");
     707      return PAM_BUF_ERR;
     708    }
     709  
     710    i = compute_exec_context(pamh, data, select_context, use_current_range,
     711  			   env_params, debug);
     712    if (i != PAM_SUCCESS) {
     713      free_module_data(data);
     714      return i;
     715    }
     716  
     717    if (!data->exec_context) {
     718      free_module_data(data);
     719      return (security_getenforce() != 0) ? PAM_SESSION_ERR : PAM_SUCCESS;
     720    }
     721  
     722    if (ttys && (i = compute_tty_context(pamh, data)) != PAM_SUCCESS) {
     723      free_module_data(data);
     724      return i;
     725    }
     726  
     727    if ((i = pam_set_data(pamh, DATANAME, data, cleanup)) != PAM_SUCCESS) {
     728      pam_syslog(pamh, LOG_ERR, "Error saving context: %m");
     729      free_module_data(data);
     730      return i;
     731    }
     732  
     733    return set_context(pamh, data, debug, verbose);
     734  }
     735  
     736  int
     737  pam_sm_authenticate(pam_handle_t *pamh UNUSED, int flags UNUSED,
     738  		    int argc UNUSED, const char **argv UNUSED)
     739  {
     740    /* Fail by default. */
     741    return PAM_AUTH_ERR;
     742  }
     743  
     744  int
     745  pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED,
     746  	       int argc UNUSED, const char **argv UNUSED)
     747  {
     748    return PAM_SUCCESS;
     749  }
     750  
     751  int
     752  pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
     753  		    int argc, const char **argv)
     754  {
     755    const module_data_t *data;
     756    int i, debug = 0, verbose = 0, close_session = 0, restore = 0;
     757  
     758    /* Parse arguments. */
     759    for (i = 0; i < argc; i++) {
     760      if (strcmp(argv[i], "debug") == 0) {
     761        debug = 1;
     762      }
     763      if (strcmp(argv[i], "verbose") == 0) {
     764        verbose = 1;
     765      }
     766      if (strcmp(argv[i], "close") == 0) {
     767        close_session = 1;
     768      }
     769      if (strcmp(argv[i], "restore") == 0) {
     770        restore = 1;
     771      }
     772    }
     773  
     774    if (debug)
     775      pam_syslog(pamh, LOG_NOTICE, "Open Session");
     776  
     777    /* Is this module supposed to execute close_session only? */
     778    if (close_session)
     779      return PAM_SUCCESS;
     780  
     781    data = get_module_data(pamh);
     782  
     783    /* Is this module supposed only to restore original context? */
     784    if (restore)
     785      return restore_context(pamh, data, debug);
     786  
     787    /* If there is a saved context, this module is supposed to set it again. */
     788    return data ? set_context(pamh, data, debug, verbose) :
     789      create_context(pamh, argc, argv, debug, verbose);
     790  }
     791  
     792  int
     793  pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED,
     794  		     int argc, const char **argv)
     795  {
     796    int i, debug = 0, open_session = 0;
     797  
     798    /* Parse arguments. */
     799    for (i = 0; i < argc; i++) {
     800      if (strcmp(argv[i], "debug") == 0) {
     801        debug = 1;
     802      }
     803      if (strcmp(argv[i], "open") == 0) {
     804        open_session = 1;
     805      }
     806    }
     807  
     808    if (debug)
     809      pam_syslog(pamh, LOG_NOTICE, "Close Session");
     810  
     811    /* Is this module supposed to execute open_session only? */
     812    if (open_session)
     813      return PAM_SUCCESS;
     814  
     815    /* Restore original context. */
     816    return restore_context(pamh, get_module_data(pamh), debug);
     817  }