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 }