pam/pam-0.99.8.1-selinux-permit.patch
Tomáš Mráz 790525d4ab - review
- don't free/malloc when unnecessary
2007-09-19 19:25:24 +00:00

474 lines
14 KiB
Diff

Written-by: Tomas Mraz <tmraz@redhat.com>
Reviewed-by: Karel Zak <kzak@redhat.com>
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 @@
+<?xml version="1.0" encoding='UTF-8'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+ "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
+
+<refentry id="pam_selinux_permit">
+
+ <refmeta>
+ <refentrytitle>pam_selinux_permit</refentrytitle>
+ <manvolnum>8</manvolnum>
+ <refmiscinfo class="sectdesc">Linux-PAM Manual</refmiscinfo>
+ </refmeta>
+
+ <refnamediv id="pam_selinux_permit-name">
+ <refname>pam_selinux_permit</refname>
+ <refpurpose>PAM module to allow/deny login depending on SELinux enforcement state</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis id="pam_selinux_permit-cmdsynopsis">
+ <command>pam_selinux_permit.so</command>
+ <arg choice="opt">
+ debug
+ </arg>
+ <arg choice="opt">
+ conf=<replaceable>/path/to/config/file</replaceable>
+ </arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="pam_selinux_permit-description">
+ <title>DESCRIPTION</title>
+ <para>
+ The pam_selinux module allows or denies login depending on SELinux enforcement
+ state.
+ </para>
+ <para>
+ 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.
+ </para>
+ <para>
+ The config file contains a simple list of user names one per line. If the
+ <replaceable>name</replaceable> is prefixed with @ character it means that all
+ users in the group <replaceable>name</replaceable> match. If it is prefixed
+ with a % character the SELinux user is used to match against the <replaceable>name</replaceable>
+ 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.
+ </para>
+ </refsect1>
+
+ <refsect1 id="pam_selinux_permit-options">
+ <title>OPTIONS</title>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <option>debug</option>
+ </term>
+ <listitem>
+ <para>
+ Turns on debugging via
+ <citerefentry>
+ <refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>conf=<replaceable>/path/to/config/file</replaceable></option>
+ </term>
+ <listitem>
+ <para>
+ Path to alternative config file overriding the default.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1 id="pam_selinux_permit-services">
+ <title>MODULE SERVICES PROVIDED</title>
+ <para>
+ Only the <option>auth</option> and <option>account</option>
+ services are supported.
+ </para>
+ </refsect1>
+
+ <refsect1 id='pam_selinux_permit-return_values'>
+ <title>RETURN VALUES</title>
+ <variablelist>
+ <varlistentry>
+ <term>PAM_AUTH_ERR</term>
+ <listitem>
+ <para>
+ SELinux is disabled or in the permissive mode and the user
+ matches.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>PAM_SUCCESS</term>
+ <listitem>
+ <para>
+ SELinux is in the enforcing mode and the user matches.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>PAM_IGNORE</term>
+ <listitem>
+ <para>
+ The user does not match any entry in the config file.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>PAM_USER_UNKNOWN</term>
+ <listitem>
+ <para>
+ The module was unable to determine the user's name.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>PAM_SERVICE_ERR</term>
+ <listitem>
+ <para>
+ Error during reading or parsing the config file.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1 id="pam_selinux_permit-files">
+ <title>FILES</title>
+ <variablelist>
+ <varlistentry>
+ <term><filename>/etc/security/sepermit.conf</filename></term>
+ <listitem>
+ <para>Default configuration file</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1 id='pam_selinux_permit-examples'>
+ <title>EXAMPLES</title>
+ <programlisting>
+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
+ </programlisting>
+ </refsect1>
+
+ <refsect1 id='pam_selinux_permit-see_also'>
+ <title>SEE ALSO</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>pam.conf</refentrytitle><manvolnum>5</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>pam.d</refentrytitle><manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>pam</refentrytitle><manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+
+ <refsect1 id='pam_selinux_permit-author'>
+ <title>AUTHOR</title>
+ <para>
+ pam_selinux_permit was written by Tomas Mraz &lt;tmraz@redhat.com&gt;.
+ </para>
+ </refsect1>
+
+</refentry>
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 <tmraz@redhat.com>
+ *
+ * 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 <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <ctype.h>
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+
+#include <security/pam_modules.h>
+#include <security/_pam_macros.h>
+#include <security/pam_modutil.h>
+#include <security/pam_ext.h>
+
+#include <selinux/selinux.h>
+
+/* 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