]> granicus.if.org Git - linux-pam/blob - modules/pam_selinux/pam_selinux.c
f99d433ae9eb2e1c5a53b8a3f2200ae651706959
[linux-pam] / 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
42 #include "config.h"
43
44 #include <errno.h>
45 #include <limits.h>
46 #include <pwd.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #include <fcntl.h>
54 #include <syslog.h>
55
56 #define PAM_SM_AUTH
57 #define PAM_SM_SESSION
58
59 #include <security/pam_modules.h>
60 #include <security/_pam_macros.h>
61 #include <security/pam_modutil.h>
62 #include <security/pam_ext.h>
63
64 #include <selinux/selinux.h>
65 #include <selinux/get_context_list.h>
66 #include <selinux/flask.h>
67 #include <selinux/av_permissions.h>
68 #include <selinux/selinux.h>
69 #include <selinux/context.h>
70 #include <selinux/get_default_type.h>
71
72 #ifdef HAVE_LIBAUDIT
73 #include <libaudit.h>
74 #include <sys/select.h>
75 #include <errno.h>
76 #endif
77
78 /* Send audit message */
79 static
80
81 int send_audit_message(pam_handle_t *pamh, int success, security_context_t default_context,
82                        security_context_t selected_context)
83 {
84         int rc=0;
85 #ifdef HAVE_LIBAUDIT
86         char *msg = NULL;
87         int audit_fd = audit_open();
88         security_context_t default_raw=NULL;
89         security_context_t selected_raw=NULL;
90         rc = -1;
91         if (audit_fd < 0) {
92                 if (errno == EINVAL || errno == EPROTONOSUPPORT ||
93                                         errno == EAFNOSUPPORT)
94                         return 0; /* No audit support in kernel */
95                 pam_syslog(pamh, LOG_ERR, "Error connecting to audit system.");
96                 return rc;
97         }
98         if (selinux_trans_to_raw_context(default_context, &default_raw) < 0) {
99                 pam_syslog(pamh, LOG_ERR, "Error translating default context.");
100                 default_raw = NULL;
101         }
102         if (selinux_trans_to_raw_context(selected_context, &selected_raw) < 0) {
103                 pam_syslog(pamh, LOG_ERR, "Error translating selected context.");
104                 selected_raw = NULL;
105         }
106         if (asprintf(&msg, "pam: default-context=%s selected-context=%s",
107                      default_raw ? default_raw : (default_context ? default_context : "?"),
108                      selected_raw ? selected_raw : (selected_context ? selected_context : "?")) < 0) {
109                 pam_syslog(pamh, LOG_ERR, "Error allocating memory.");
110                 goto out;
111         }
112         if (audit_log_user_message(audit_fd, AUDIT_USER_ROLE_CHANGE,
113                                    msg, NULL, NULL, NULL, success) <= 0) {
114                 pam_syslog(pamh, LOG_ERR, "Error sending audit message.");
115                 goto out;
116         }
117         rc = 0;
118       out:
119         free(msg);
120         freecon(default_raw);
121         freecon(selected_raw);
122         close(audit_fd);
123 #else
124         pam_syslog(pamh, LOG_NOTICE, "pam: default-context=%s selected-context=%s success %d", default_context, selected_context, success);
125 #endif
126         return rc;
127 }
128 static int
129 send_text (pam_handle_t *pamh, const char *text, int debug)
130 {
131   if (debug)
132     pam_syslog(pamh, LOG_NOTICE, "%s", text);
133   return pam_info (pamh, "%s", text);
134 }
135
136 /*
137  * This function sends a message to the user and gets the response. The caller
138  * is responsible for freeing the responses.
139  */
140 static int
141 query_response (pam_handle_t *pamh, const char *text, const char *def,
142                 char **response, int debug)
143 {
144   int rc;
145   if (def) 
146     rc = pam_prompt (pamh, PAM_PROMPT_ECHO_ON, response, "%s [%s] ", text, def);
147   else
148     rc = pam_prompt (pamh, PAM_PROMPT_ECHO_ON, response, "%s ", text);
149
150   if (*response == NULL) {
151     rc = PAM_CONV_ERR;
152   }
153   
154   if (rc != PAM_SUCCESS) {
155     pam_syslog(pamh, LOG_WARNING, "No response to query: %s", text);
156   } else  if (debug)
157     pam_syslog(pamh, LOG_NOTICE, "%s %s", text, *response);
158   return rc;
159 }
160
161 static security_context_t
162 manual_context (pam_handle_t *pamh, const char *user, int debug)
163 {
164   security_context_t newcon=NULL;
165   context_t new_context;
166   int mls_enabled = is_selinux_mls_enabled();
167   char *type=NULL;
168   char *response=NULL;
169
170   while (1) {
171     if (query_response(pamh,
172                    _("Would you like to enter a security context? [N] "), NULL,
173                    &response, debug) != PAM_SUCCESS)
174         return NULL;
175
176     if ((response[0] == 'y') || (response[0] == 'Y'))
177       {
178         if (mls_enabled)
179           new_context = context_new ("user:role:type:level");
180         else
181           new_context = context_new ("user:role:type");
182
183         if (!new_context)
184               goto fail_set;
185
186         if (context_user_set (new_context, user))
187               goto fail_set;
188
189         _pam_drop(response);
190         /* Allow the user to enter each field of the context individually */
191         if (query_response(pamh, _("role:"), NULL, &response, debug) == PAM_SUCCESS &&
192             response[0] != '\0') {
193            if (context_role_set (new_context, response)) 
194               goto fail_set;
195            if (get_default_type(response, &type)) 
196               goto fail_set;
197            if (context_type_set (new_context, type)) 
198               goto fail_set;
199            _pam_drop(type);
200         }
201         _pam_drop(response);
202
203         if (mls_enabled)
204           {
205             if (query_response(pamh, _("level:"), NULL, &response, debug) == PAM_SUCCESS &&
206                 response[0] != '\0') {
207               if (context_range_set (new_context, response))
208                 goto fail_set;
209             }
210             _pam_drop(response);
211           }
212
213         /* Get the string value of the context and see if it is valid. */
214         if (!security_check_context(context_str(new_context))) {
215           newcon = strdup(context_str(new_context));
216           context_free (new_context);
217           return newcon;
218         }
219         else
220           send_text(pamh,_("Not a valid security context"),debug);
221
222         context_free (new_context);
223       }
224     else {
225       _pam_drop(response);
226       return NULL;
227     }
228   } /* end while */
229  fail_set:
230   free(type);
231   _pam_drop(response);
232   context_free (new_context);
233   return NULL;
234 }
235
236 static int mls_range_allowed(pam_handle_t *pamh, security_context_t src, security_context_t dst, int debug)
237 {
238   struct av_decision avd;
239   int retval;
240   security_class_t class;
241   access_vector_t bit;
242   context_t src_context;
243   context_t dst_context;
244
245   class = string_to_security_class("context");
246   if (!class) {
247     pam_syslog(pamh, LOG_ERR, "Failed to translate security class context. %m");
248     return 0;
249   }
250
251   bit = string_to_av_perm(class, "contains");
252   if (!bit) {
253     pam_syslog(pamh, LOG_ERR, "Failed to translate av perm contains. %m");
254     return 0;
255   }
256
257   src_context = context_new (src);
258   dst_context = context_new (dst);
259   context_range_set(dst_context, context_range_get(src_context));
260   if (debug)
261     pam_syslog(pamh, LOG_NOTICE, "Checking if %s mls range valid for  %s", dst, context_str(dst_context));
262
263   retval = security_compute_av(context_str(dst_context), dst, class, bit, &avd);
264   context_free(src_context);
265   context_free(dst_context);
266   if (retval || ((bit & avd.allowed) != bit))
267     return 0;
268
269   return 1;
270 }
271
272 static security_context_t
273 config_context (pam_handle_t *pamh, security_context_t defaultcon, int use_current_range, int debug)
274 {
275   security_context_t newcon=NULL;
276   context_t new_context;
277   int mls_enabled = is_selinux_mls_enabled();
278   char *response=NULL;
279   char *type=NULL;
280   char resp_val = 0;
281
282   pam_prompt (pamh, PAM_TEXT_INFO, NULL, _("Default Security Context %s\n"), defaultcon);
283
284   while (1) {
285     if (query_response(pamh,
286                    _("Would you like to enter a different role or level?"), "n", 
287                    &response, debug) == PAM_SUCCESS) {
288         resp_val = response[0];
289         _pam_drop(response);
290     } else {
291         resp_val = 'N';
292     }
293     if ((resp_val == 'y') || (resp_val == 'Y'))
294       {
295         if ((new_context = context_new(defaultcon)) == NULL)
296             goto fail_set;
297
298         /* Allow the user to enter role and level individually */
299         if (query_response(pamh, _("role:"), context_role_get(new_context), 
300                        &response, debug) == PAM_SUCCESS && response[0]) {
301           if (get_default_type(response, &type)) {
302             pam_prompt (pamh, PAM_ERROR_MSG, NULL, _("No default type for role %s\n"), response);
303             _pam_drop(response);
304             continue;
305           } else {
306             if (context_role_set(new_context, response)) 
307               goto fail_set;
308             if (context_type_set (new_context, type))
309               goto fail_set;
310             _pam_drop(type);
311           } 
312         }
313         _pam_drop(response);
314
315         if (mls_enabled)
316           {
317             if (use_current_range) {
318                 security_context_t mycon = NULL;
319                 context_t my_context;
320
321                 if (getcon(&mycon) != 0)
322                     goto fail_set;
323                 my_context = context_new(mycon);
324                 if (my_context == NULL) {
325                     freecon(mycon);
326                     goto fail_set;
327                 }
328                 freecon(mycon);
329                 if (context_range_set(new_context, context_range_get(my_context))) {
330                     context_free(my_context);
331                     goto fail_set;
332                 }
333                 context_free(my_context);
334             } else if (query_response(pamh, _("level:"), context_range_get(new_context), 
335                            &response, debug) == PAM_SUCCESS && response[0]) {
336                 if (context_range_set(new_context, response))
337                     goto fail_set;
338             } 
339             _pam_drop(response);
340           }
341
342         if (debug)
343           pam_syslog(pamh, LOG_NOTICE, "Selected Security Context %s", context_str(new_context));
344
345         /* Get the string value of the context and see if it is valid. */
346         if (!security_check_context(context_str(new_context))) {
347           newcon = strdup(context_str(new_context));
348           if (newcon == NULL)
349             goto fail_set;
350           context_free(new_context);
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 && !mls_range_allowed(pamh, defaultcon, newcon, debug)) {
356             pam_syslog(pamh, LOG_NOTICE, "Security context %s is not allowed for %s", defaultcon, newcon);
357
358             send_audit_message(pamh, 0, defaultcon, newcon);
359
360             free(newcon);
361             goto fail_range;
362           }
363           return newcon;
364         }
365         else {
366           send_audit_message(pamh, 0, defaultcon, context_str(new_context));
367           send_text(pamh,_("Not a valid security context"),debug);
368         }
369         context_free(new_context); /* next time around allocates another */
370       }
371     else
372       return strdup(defaultcon);
373   } /* end while */
374
375   return NULL;
376
377  fail_set:
378   free(type);
379   _pam_drop(response);
380   context_free (new_context);
381   send_audit_message(pamh, 0, defaultcon, NULL);
382  fail_range:
383   return NULL;  
384 }
385
386 static security_context_t
387 context_from_env (pam_handle_t *pamh, security_context_t defaultcon, int env_params, int use_current_range, int debug)
388 {
389   security_context_t newcon = NULL;
390   context_t new_context;
391   context_t my_context = NULL;
392   int mls_enabled = is_selinux_mls_enabled();
393   const char *env = NULL;
394   char *type = NULL;
395   int fail = 1;
396
397   if ((new_context = context_new(defaultcon)) == NULL)
398     goto fail_set;
399
400   if (env_params && (env = pam_getenv(pamh, "SELINUX_ROLE_REQUESTED")) != NULL && env[0] != '\0') {
401     if (debug)
402         pam_syslog(pamh, LOG_NOTICE, "Requested role: %s", env);
403
404     if (get_default_type(env, &type)) {
405         pam_syslog(pamh, LOG_NOTICE, "No default type for role %s", env);
406         goto fail_set;
407     } else {
408         if (context_role_set(new_context, env)) 
409             goto fail_set;
410         if (context_type_set(new_context, type))
411             goto fail_set;
412     }
413   }
414
415   if (mls_enabled) {
416     if ((env = pam_getenv(pamh, "SELINUX_USE_CURRENT_RANGE")) != NULL && env[0] == '1') {
417         if (debug)
418             pam_syslog(pamh, LOG_NOTICE, "SELINUX_USE_CURRENT_RANGE is set");
419         use_current_range = 1;
420     }
421
422     if (use_current_range) {
423         security_context_t mycon = NULL;
424
425         if (getcon(&mycon) != 0)
426             goto fail_set;
427         my_context = context_new(mycon);
428         if (my_context == NULL) {
429             freecon(mycon);
430             goto fail_set;
431         }
432         freecon(mycon);
433         env = context_range_get(my_context);
434     } else {
435         env = pam_getenv(pamh, "SELINUX_LEVEL_REQUESTED");
436     }
437
438     if (env != NULL && env[0] != '\0') {
439         if (debug)
440             pam_syslog(pamh, LOG_NOTICE, "Requested level: %s", env);
441         if (context_range_set(new_context, env))
442             goto fail_set;
443     }
444   }
445
446   newcon = strdup(context_str(new_context));
447   if (newcon == NULL)
448     goto fail_set;
449
450   if (debug)
451     pam_syslog(pamh, LOG_NOTICE, "Selected Security Context %s", newcon);
452   
453   /* Get the string value of the context and see if it is valid. */
454   if (security_check_context(newcon)) {
455     pam_syslog(pamh, LOG_NOTICE, "Not a valid security context %s", newcon);
456
457     goto fail_set;
458   }
459
460   /* we have to check that this user is allowed to go into the
461      range they have specified ... role is tied to an seuser, so that'll
462      be checked at setexeccon time */
463   if (mls_enabled && !mls_range_allowed(pamh, defaultcon, newcon, debug)) {
464     pam_syslog(pamh, LOG_NOTICE, "Security context %s is not allowed for %s", defaultcon, newcon);
465
466     goto fail_set;
467   }
468
469   fail = 0;
470
471  fail_set:
472   free(type);
473   context_free(my_context);
474   context_free(new_context);
475   if (fail) {
476     send_audit_message(pamh, 0, defaultcon, newcon);
477     freecon(newcon);
478     newcon = NULL;
479   }
480   return newcon;
481 }
482
483 static void
484 security_restorelabel_tty(const pam_handle_t *pamh,
485                           const char *tty, security_context_t context)
486 {
487   char ttybuf[PATH_MAX];
488   const char *ptr;
489
490   if (context==NULL)
491     return;
492
493   if(strncmp("/dev/", tty, 5)) {
494     snprintf(ttybuf,sizeof(ttybuf),"/dev/%s",tty);
495     ptr = ttybuf;
496   }
497   else
498     ptr = tty;
499
500   if (setfilecon(ptr, context) && errno != ENOENT)
501   {
502     pam_syslog(pamh, LOG_NOTICE,
503                "Warning!  Could not relabel %s with %s, not relabeling: %m",
504                ptr, context);
505   }
506 }
507
508 static security_context_t
509 security_label_tty(pam_handle_t *pamh, char *tty,
510                    security_context_t usercon)
511 {
512   char ttybuf[PATH_MAX];
513   int status=0;
514   security_context_t newdev_context=NULL; /* The new context of a device */
515   security_context_t prev_context=NULL; /* The new context of a device */
516   const char *ptr;
517
518   if(strncmp("/dev/", tty, 5))
519   {
520     snprintf(ttybuf,sizeof(ttybuf),"/dev/%s",tty);
521     ptr = ttybuf;
522   }
523   else
524     ptr = tty;
525
526   if (getfilecon(ptr, &prev_context) < 0)
527   {
528     if(errno != ENOENT)
529       pam_syslog(pamh, LOG_NOTICE,
530              "Warning!  Could not get current context for %s, not relabeling: %m",
531              ptr);
532     return NULL;
533   }
534   if( security_compute_relabel(usercon,prev_context,SECCLASS_CHR_FILE,
535                                &newdev_context)!=0)
536   {
537     pam_syslog(pamh, LOG_NOTICE,
538            "Warning!  Could not get new context for %s, not relabeling: %m",
539            ptr);
540     pam_syslog(pamh, LOG_NOTICE,
541                "usercon=%s, prev_context=%s", usercon, prev_context);
542     freecon(prev_context);
543     return NULL;
544   }
545   status=setfilecon(ptr,newdev_context);
546   if (status)
547   {
548       pam_syslog(pamh, LOG_NOTICE,
549                  "Warning!  Could not relabel %s with %s, not relabeling: %m",
550                  ptr,newdev_context);
551       freecon(prev_context);
552       prev_context=NULL;
553   }
554   freecon(newdev_context);
555   return prev_context;
556 }
557
558 static security_context_t user_context=NULL;
559 static security_context_t prev_user_context=NULL;
560 static security_context_t ttyn_context=NULL;  /* The current context of ttyn device */
561 static int selinux_enabled=0;
562 static char *ttyn=NULL;
563
564 PAM_EXTERN int
565 pam_sm_authenticate(pam_handle_t *pamh UNUSED, int flags UNUSED,
566                     int argc UNUSED, const char **argv UNUSED)
567 {
568         /* Fail by default. */
569         return PAM_AUTH_ERR;
570 }
571
572 PAM_EXTERN int
573 pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED,
574                int argc UNUSED, const char **argv UNUSED)
575 {
576         return PAM_SUCCESS;
577 }
578
579 PAM_EXTERN int
580 pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
581                     int argc, const char **argv)
582 {
583   int i, debug = 0, ttys=1;
584   int verbose=0, close_session=0;
585   int select_context = 0;
586   int use_current_range = 0;
587   int ret = 0;
588   security_context_t* contextlist = NULL;
589   int num_contexts = 0;
590   int env_params = 0;
591   const char *username;
592   const void *void_username;
593   const void *tty = NULL;
594   char *seuser=NULL;
595   char *level=NULL;
596   security_context_t default_user_context=NULL;
597 #ifdef HAVE_GETSEUSER
598   const void *void_service;
599   const char *service;
600 #endif
601
602   /* Parse arguments. */
603   for (i = 0; i < argc; i++) {
604     if (strcmp(argv[i], "debug") == 0) {
605       debug = 1;
606     }
607     if (strcmp(argv[i], "nottys") == 0) {
608       ttys = 0;
609     }
610     if (strcmp(argv[i], "verbose") == 0) {
611       verbose = 1;
612     }
613     if (strcmp(argv[i], "close") == 0) {
614       close_session = 1;
615     }
616     if (strcmp(argv[i], "select_context") == 0) {
617       select_context = 1;
618     }
619     if (strcmp(argv[i], "use_current_range") == 0) {
620       use_current_range = 1;
621     }
622     if (strcmp(argv[i], "env_params") == 0) {
623       env_params = 1;
624     }
625   }
626   
627   if (debug)
628     pam_syslog(pamh, LOG_NOTICE, "Open Session");
629
630   if (select_context && env_params) {
631     pam_syslog(pamh, LOG_ERR, "select_context cannot be used with env_params");
632     select_context = 0;
633   }
634
635   /* this module is only supposed to execute close_session */
636   if (close_session)
637       return PAM_SUCCESS;
638
639   if (!(selinux_enabled = is_selinux_enabled()>0) )
640       return PAM_SUCCESS;
641
642   if (pam_get_item(pamh, PAM_USER, &void_username) != PAM_SUCCESS ||
643                    void_username == NULL) {
644     return PAM_USER_UNKNOWN;
645   }
646   username = void_username;
647
648 #ifdef HAVE_GETSEUSER
649   if (pam_get_item(pamh, PAM_SERVICE, (void *) &void_service) != PAM_SUCCESS ||
650                    void_service == NULL) {
651     return PAM_SESSION_ERR;
652   }
653   service = void_service;
654
655   if (getseuser(username, service, &seuser, &level) == 0) {
656 #else
657   if (getseuserbyname(username, &seuser, &level) == 0) {
658 #endif
659           num_contexts = get_ordered_context_list_with_level(seuser, 
660                                                              level,
661                                                              NULL, 
662                                                              &contextlist);
663           if (debug)
664                   pam_syslog(pamh, LOG_DEBUG, "Username= %s SELinux User = %s Level= %s",
665                              username, seuser, level);
666           free(level);
667   }
668   if (num_contexts > 0) {
669     free(seuser);
670     default_user_context=strdup(contextlist[0]);
671     freeconary(contextlist);
672     if (default_user_context == NULL) {
673           pam_syslog(pamh, LOG_ERR, "Out of memory");
674           return PAM_BUF_ERR;
675     }
676
677     user_context = default_user_context;
678     if (select_context) {
679         user_context = config_context(pamh, default_user_context, use_current_range, debug);
680     } else if (env_params || use_current_range) {
681         user_context = context_from_env(pamh, default_user_context, env_params, use_current_range, debug);
682     }
683
684     if (user_context == NULL) {
685         freecon(default_user_context);
686         pam_syslog(pamh, LOG_ERR, "Unable to get valid context for %s",
687                     username);
688         pam_prompt (pamh, PAM_ERROR_MSG, NULL,  _("Unable to get valid context for %s"), username);
689         if (security_getenforce() == 1)
690           return PAM_AUTH_ERR;
691         else
692           return PAM_SUCCESS;
693     }
694   }
695   else { 
696       if (seuser != NULL) {
697         user_context = manual_context(pamh,seuser,debug);
698         free(seuser);
699       }
700       if (user_context == NULL) {
701         pam_syslog (pamh, LOG_ERR, "Unable to get valid context for %s",
702                     username);
703         if (security_getenforce() == 1)
704           return PAM_AUTH_ERR;
705         else
706           return PAM_SUCCESS;
707       }
708   }
709
710   if (getexeccon(&prev_user_context)<0) {
711     prev_user_context=NULL;
712   }
713   if (ttys) {
714     /* Get the name of the terminal. */
715     if (pam_get_item(pamh, PAM_TTY, &tty) != PAM_SUCCESS) {
716       tty = NULL;
717     }
718
719     if ((tty == NULL) || (strlen(tty) == 0) ||
720         strcmp(tty, "ssh") == 0 || strncmp(tty, "NODEV", 5) == 0) {
721       tty = ttyname(STDIN_FILENO);
722       if ((tty == NULL) || (strlen(tty) == 0)) {
723         tty = ttyname(STDOUT_FILENO);
724       }
725       if ((tty == NULL) || (strlen(tty) == 0)) {
726         tty = ttyname(STDERR_FILENO);
727       }
728     }
729   }
730   if (ttys && tty) {
731     ttyn=strdup(tty);
732     ttyn_context=security_label_tty(pamh,ttyn,user_context);
733   }
734   send_audit_message(pamh, 1, default_user_context, user_context);
735   if (default_user_context != user_context) {
736     freecon(default_user_context);
737   }
738   ret = setexeccon(user_context);
739   if (ret==0 && verbose) {
740     char msg[PATH_MAX];
741     snprintf(msg, sizeof(msg),
742              _("Security Context %s Assigned"), user_context);
743     send_text(pamh, msg, debug);
744   }
745   if (ret) {
746     pam_syslog(pamh, LOG_ERR,
747                "Error!  Unable to set %s executable context %s.",
748                username, user_context);
749     if (security_getenforce() == 1) {
750        freecon(user_context);
751        return PAM_AUTH_ERR;
752     }
753   } else {
754     if (debug)
755       pam_syslog(pamh, LOG_NOTICE, "set %s security context to %s",
756                  username, user_context);
757   }
758 #ifdef HAVE_SETKEYCREATECON
759   ret = setkeycreatecon(user_context);
760   if (ret==0 && verbose) {
761     char msg[PATH_MAX];
762     snprintf(msg, sizeof(msg),
763              _("Key Creation Context %s Assigned"), user_context);
764     send_text(pamh, msg, debug);
765   }
766   if (ret) {
767     pam_syslog(pamh, LOG_ERR,
768                "Error!  Unable to set %s key creation context %s.",
769                username, user_context);
770     if (security_getenforce() == 1) {
771        freecon(user_context);
772        return PAM_AUTH_ERR;
773     }
774   } else {
775     if (debug)
776       pam_syslog(pamh, LOG_NOTICE, "set %s key creation context to %s",
777                  username, user_context);
778   }
779 #endif
780   freecon(user_context);
781
782   return PAM_SUCCESS;
783 }
784
785 PAM_EXTERN int
786 pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED,
787                      int argc, const char **argv)
788 {
789   int i, debug = 0, status = PAM_SUCCESS, open_session = 0;
790   if (! (selinux_enabled ))
791       return PAM_SUCCESS;
792
793   /* Parse arguments. */
794   for (i = 0; i < argc; i++) {
795     if (strcmp(argv[i], "debug") == 0) {
796       debug = 1;
797     }
798     if (strcmp(argv[i], "open") == 0) {
799       open_session = 1;
800     }
801   }
802
803   if (debug)
804     pam_syslog(pamh, LOG_NOTICE, "Close Session");
805
806   if (open_session)
807     return PAM_SUCCESS;
808
809   if (ttyn) {
810     if (debug)
811       pam_syslog(pamh, LOG_NOTICE, "Restore tty  %s -> %s",
812                  ttyn,ttyn_context);
813
814     security_restorelabel_tty(pamh,ttyn,ttyn_context);
815     freecon(ttyn_context);
816     free(ttyn);
817     ttyn=NULL;
818   }
819
820   if (setexeccon(prev_user_context)) {
821       pam_syslog(pamh, LOG_ERR, "Unable to restore executable context %s.",
822                prev_user_context ? prev_user_context : "");
823       if (security_getenforce() == 1)
824          status = PAM_AUTH_ERR;
825       else
826          status = PAM_SUCCESS;
827   } else if (debug)
828       pam_syslog(pamh, LOG_NOTICE, "Executable context back to original");
829
830   if (prev_user_context) {
831     freecon(prev_user_context);
832     prev_user_context = NULL;
833   }
834
835   return status;
836 }