Written-by: Tomas Mraz Reviewed-by: Karel Zak diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_selinux/pam_selinux_permit.8.xml --- /dev/null 2007-09-17 08:57:19.474470099 +0200 +++ Linux-PAM-0.99.8.1/modules/pam_selinux/pam_selinux_permit.8.xml 2007-09-19 19:37:26.000000000 +0200 @@ -0,0 +1,182 @@ + + + + + + + pam_selinux_permit + 8 + Linux-PAM Manual + + + + pam_selinux_permit + PAM module to allow/deny login depending on SELinux enforcement state + + + + + pam_selinux_permit.so + + debug + + + conf=/path/to/config/file + + + + + + DESCRIPTION + + The pam_selinux module allows or denies login depending on SELinux enforcement + state. + + + When the user which is logging in matches an entry in the config file + he is allowed access only when the SELinux is in enforcing mode. Otherwise + he is denied access. For users not matching any entry in the config file + the pam_selinux_permit module returns PAM_IGNORE return value. + + + The config file contains a simple list of user names one per line. If the + name is prefixed with @ character it means that all + users in the group name match. If it is prefixed + with a % character the SELinux user is used to match against the name + instead of the account name. Note that when SELinux is disabled the + SELinux user assigned to the account cannot be determined. This means that + such entries are never matched when SELinux is disabled and pam_selinux_permit + will return PAM_IGNORE. + + + + + OPTIONS + + + + + + + + Turns on debugging via + + syslog3 + . + + + + + + + + + + Path to alternative config file overriding the default. + + + + + + + + MODULE SERVICES PROVIDED + + Only the and + services are supported. + + + + + RETURN VALUES + + + PAM_AUTH_ERR + + + SELinux is disabled or in the permissive mode and the user + matches. + + + + + PAM_SUCCESS + + + SELinux is in the enforcing mode and the user matches. + + + + + PAM_IGNORE + + + The user does not match any entry in the config file. + + + + + PAM_USER_UNKNOWN + + + The module was unable to determine the user's name. + + + + + PAM_SERVICE_ERR + + + Error during reading or parsing the config file. + + + + + + + + FILES + + + /etc/security/sepermit.conf + + Default configuration file + + + + + + + EXAMPLES + +auth [success=done ignore=ignore default=bad] pam_selinux_permit.so +auth required pam_unix.so +account required pam_unix.so +session required pam_permit.so + + + + + SEE ALSO + + + pam.conf5 + , + + pam.d8 + , + + pam8 + + + + + + AUTHOR + + pam_selinux_permit was written by Tomas Mraz <tmraz@redhat.com>. + + + + diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_selinux/pam_selinux_permit.c --- /dev/null 2007-09-17 08:57:19.474470099 +0200 +++ Linux-PAM-0.99.8.1/modules/pam_selinux/pam_selinux_permit.c 2007-09-19 20:29:47.000000000 +0200 @@ -0,0 +1,222 @@ +/****************************************************************************** + * A module for Linux-PAM that allows/denies acces based on SELinux state. + * + * Copyright (c) 2007 Red Hat, Inc. + * Written by Tomas Mraz + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#define PAM_SM_AUTH +#define PAM_SM_ACCOUNT + +#include +#include +#include +#include + +#include + +/* return 0 when matched, -1 when unmatched, pam error otherwise */ +static int +sepermit_match(pam_handle_t *pamh, const char *cfgfile, const char *user, + const char *seuser, int debug) +{ + FILE *f; + char *line = NULL; + char *start; + size_t len = 0; + int matched = 0; + + f = fopen(cfgfile, "r"); + + if (!f) { + pam_syslog(pamh, LOG_ERR, "Failed to open config file %s: %m", cfgfile); + return PAM_SERVICE_ERR; + } + + while (!matched && getline(&line, &len, f) != -1) { + size_t n; + + if (line[0] == '#') + continue; + + start = line; + while (isspace(*start)) + ++start; + n = strlen(start); + while (n > 0 && isspace(start[n-1])) { + --n; + } + if (n == 0) + continue; + + start[n] = '\0'; + + switch (start[0]) { + case '@': + ++start; + if (debug) + pam_syslog(pamh, LOG_NOTICE, "Matching user %s against group %s", user, start); + if (pam_modutil_user_in_group_nam_nam(pamh, user, start)) { + matched = 1; + } + break; + case '%': + ++start; + if (debug) + pam_syslog(pamh, LOG_NOTICE, "Matching seuser %s against seuser %s", seuser, start); + if (strcmp(seuser, start) == 0) { + matched = 1; + } + break; + default: + if (debug) + pam_syslog(pamh, LOG_NOTICE, "Matching user %s against user %s", user, start); + if (strcmp(user, start) == 0) { + matched = 1; + } + } + } + + free(line); + fclose(f); + return matched ? 0 : -1; +} + +PAM_EXTERN int +pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED, + int argc, const char **argv) +{ + int i; + int rv; + int debug = 0; + int sense = PAM_AUTH_ERR; + const char *user = NULL; + char *seuser = NULL; + char *level = NULL; + const char *cfgfile = SEPERMIT_CONF_FILE; + + /* Parse arguments. */ + for (i = 0; i < argc; i++) { + if (strcmp(argv[i], "debug") == 0) { + debug = 1; + } + if (strcmp(argv[i], "conf=") == 0) { + cfgfile = argv[i] + 5; + } + } + + if (debug) + pam_syslog(pamh, LOG_NOTICE, "Parsing config file: %s", cfgfile); + + if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || user == NULL + || *user == '\0') { + pam_syslog(pamh, LOG_ERR, "Cannot determine the user's name"); + return PAM_USER_UNKNOWN; + } + + if (is_selinux_enabled() > 0) { + if (security_getenforce() == 1) { + if (debug) + pam_syslog(pamh, LOG_NOTICE, "Enforcing mode, access will be allowed on match"); + sense = PAM_SUCCESS; + } + + if (getseuserbyname(user, &seuser, &level) != 0) { + seuser = NULL; + level = NULL; + pam_syslog(pamh, LOG_ERR, "getseuserbyname failed: %m"); + } + } + + if (debug && sense != PAM_SUCCESS) + pam_syslog(pamh, LOG_NOTICE, "Access will not be allowed on match"); + + rv = sepermit_match(pamh, cfgfile, user, seuser, debug); + + if (debug) + pam_syslog(pamh, LOG_NOTICE, "sepermit_match returned: %d", rv); + + free(seuser); + free(level); + + switch (rv) { + case -1: + return PAM_IGNORE; + case 0: + return sense; + } + + return rv; +} + +PAM_EXTERN int +pam_sm_setcred (pam_handle_t *pamh UNUSED, int flags UNUSED, + int argc UNUSED, const char **argv UNUSED) +{ + return PAM_IGNORE; +} + +PAM_EXTERN int +pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + return pam_sm_authenticate(pamh, flags, argc, argv); +} + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_access_modstruct = { + "pam_access", + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + NULL, + NULL, + NULL +}; +#endif + diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_selinux/sepermit.conf --- /dev/null 2007-09-17 08:57:19.474470099 +0200 +++ Linux-PAM-0.99.8.1/modules/pam_selinux/sepermit.conf 2007-09-19 19:37:26.000000000 +0200 @@ -0,0 +1,6 @@ +# /etc/security/sepermit.conf +# +# Each line contains either: +# - an user name +# - a group name, with @group syntax +# - a SELinux user name, with %seuser syntax diff -up Linux-PAM-0.99.8.1/modules/pam_selinux/Makefile.am.permit Linux-PAM-0.99.8.1/modules/pam_selinux/Makefile.am --- Linux-PAM-0.99.8.1/modules/pam_selinux/Makefile.am.permit 2007-01-23 11:09:25.000000000 +0100 +++ Linux-PAM-0.99.8.1/modules/pam_selinux/Makefile.am 2007-09-19 19:37:26.000000000 +0200 @@ -5,20 +5,21 @@ CLEANFILES = *~ EXTRA_DIST = README $(XMLS) pam_selinux.8 pam_selinux_check.8 \ - tst-pam_selinux + pam_seliux_permit.8 sepermit.conf tst-pam_selinux if HAVE_LIBSELINUX TESTS = tst-pam_selinux - man_MANS = pam_selinux.8 + man_MANS = pam_selinux.8 pam_selinux_permit.8 endif -XMLS = README.xml pam_selinux.8.xml +XMLS = README.xml pam_selinux.8.xml pam_selinux_permit.8.xml securelibdir = $(SECUREDIR) secureconfdir = $(SCONFIGDIR) AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \ - -I$(top_srcdir)/libpam_misc/include + -I$(top_srcdir)/libpam_misc/include \ + -D SEPERMIT_CONF_FILE=\"$(SCONFIGDIR)/sepermit.conf\" AM_LDFLAGS = -no-undefined \ -L$(top_builddir)/libpam -lpam @LIBSELINUX@ @@ -30,12 +31,16 @@ if HAVE_VERSIONING -Wl,--version-script=$(srcdir)/../modules.map endif +pam_selinux_permit_la_LDFLAGS= $(pam_selinux_la_LDFLAGS) + +secureconf_DATA = sepermit.conf + if HAVE_LIBSELINUX - securelib_LTLIBRARIES = pam_selinux.la + securelib_LTLIBRARIES = pam_selinux.la pam_selinux_permit.la noinst_PROGRAMS = pam_selinux_check endif if ENABLE_REGENERATE_MAN -noinst_DATA = README pam_selinux.8 +noinst_DATA = README pam_selinux.8 pam_selinux_permit.8 README: pam_selinux.8.xml -include $(top_srcdir)/Make.xml.rules endif