--- configure.in | 3 +- modules/Makefile.am | 2 +- modules/pam_nnp/Makefile.am | 40 +++++ modules/pam_nnp/README.xml | 39 +++++ modules/pam_nnp/nnp.conf | 16 ++ modules/pam_nnp/nnp.conf.5.xml | 142 ++++++++++++++++ modules/pam_nnp/pam_nnp.8.xml | 174 ++++++++++++++++++++ modules/pam_nnp/pam_nnp.c | 358 +++++++++++++++++++++++++++++++++++++++++ modules/pam_nnp/tst-pam_nnp | 2 + 9 files changed, 774 insertions(+), 2 deletions(-) create mode 100644 modules/pam_nnp/Makefile.am create mode 100644 modules/pam_nnp/README.xml create mode 100644 modules/pam_nnp/nnp.conf create mode 100644 modules/pam_nnp/nnp.conf.5.xml create mode 100644 modules/pam_nnp/pam_nnp.8.xml create mode 100644 modules/pam_nnp/pam_nnp.c create mode 100755 modules/pam_nnp/tst-pam_nnp diff --git a/configure.in b/configure.in index 424a634..ce89edd 100644 --- a/configure.in +++ b/configure.in @@ -616,7 +616,8 @@ AC_CONFIG_FILES([Makefile libpam/Makefile libpamc/Makefile libpamc/test/Makefile modules/pam_loginuid/Makefile modules/pam_mail/Makefile \ modules/pam_mkhomedir/Makefile modules/pam_motd/Makefile \ modules/pam_namespace/Makefile \ - modules/pam_nologin/Makefile modules/pam_permit/Makefile \ + modules/pam_nologin/Makefile modules/pam_nnp/Makefile \ + modules/pam_permit/Makefile \ modules/pam_pwhistory/Makefile modules/pam_rhosts/Makefile \ modules/pam_rootok/Makefile modules/pam_exec/Makefile \ modules/pam_securetty/Makefile modules/pam_selinux/Makefile \ diff --git a/modules/Makefile.am b/modules/Makefile.am index 0c80cea..8a32ed9 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -6,7 +6,7 @@ SUBDIRS = pam_access pam_cracklib pam_debug pam_deny pam_echo \ pam_env pam_exec pam_faildelay pam_filter pam_ftp \ pam_group pam_issue pam_keyinit pam_lastlog pam_limits \ pam_listfile pam_localuser pam_loginuid pam_mail \ - pam_mkhomedir pam_motd pam_namespace pam_nologin \ + pam_mkhomedir pam_motd pam_namespace pam_nologin pam_nnp \ pam_permit pam_pwhistory pam_rhosts pam_rootok pam_securetty \ pam_selinux pam_sepermit pam_shells pam_stress \ pam_succeed_if pam_tally pam_tally2 pam_time pam_timestamp \ diff --git a/modules/pam_nnp/Makefile.am b/modules/pam_nnp/Makefile.am new file mode 100644 index 0000000..9d98c32 --- /dev/null +++ b/modules/pam_nnp/Makefile.am @@ -0,0 +1,40 @@ +# +# Copyright (c) 2005, 2006, 2009 Thorsten Kukuk <kukuk@xxxxxxx> +# Copyright (c) 2013 Andy Lutomirski <luto@xxxxxxxxxxxxxx> +# + +CLEANFILES = *~ +MAINTAINERCLEANFILES = $(MANS) README + +EXTRA_DIST = README $(MANS) $(XMLS) nnp.conf tst-pam_nnp + +man_MANS = nnp.conf.5 pam_nnp.8 +XMLS = README.xml nnp.conf.5.xml pam_nnp.8.xml + +TESTS = tst-pam_nnp + +securelibdir = $(SECUREDIR) +secureconfdir = $(SCONFIGDIR) +#nnp_conf_dir = $(SCONFIGDIR)/nnp.d + +AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \ + -DNNP_FILE_DIR=\"$(nnp_conf_dir)/*.conf\" \ + -DNNP_FILE=\"$(SCONFIGDIR)/nnp.conf\" +AM_LDFLAGS = -no-undefined -avoid-version -module +if HAVE_VERSIONING + AM_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map +endif + +securelib_LTLIBRARIES = pam_nnp.la +pam_nnp_la_LIBADD = $(top_builddir)/libpam/libpam.la + +secureconf_DATA = nnp.conf + +if ENABLE_REGENERATE_MAN +noinst_DATA = README +README: pam_nnp.8.xml nnp.conf.5.xml +-include $(top_srcdir)/Make.xml.rules +endif + +#install-data-local: +# mkdir -p $(DESTDIR)$(nnp_conf_dir) diff --git a/modules/pam_nnp/README.xml b/modules/pam_nnp/README.xml new file mode 100644 index 0000000..92f26f0 --- /dev/null +++ b/modules/pam_nnp/README.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding='UTF-8'?> +<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" +"http://www.docbook.org/xml/4.3/docbookx.dtd" +[ +<!-- +<!ENTITY pamnnp SYSTEM "pam_nnp.8.xml"> +--> +<!-- +<!ENTITY nnpconf SYSTEM "nnp.conf.5.xml"> +--> +]> + +<article> + + <articleinfo> + + <title> + <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" + href="pam_nnp.8.xml" xpointer='xpointer(//refnamediv[@id = "pam_nnp-name"]/*)'/> + </title> + + </articleinfo> + + <section> + <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" + href="pam_nnp.8.xml" xpointer='xpointer(//refsect1[@id = "pam_nnp-description"]/*)'/> + </section> + + <section> + <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" + href="pam_nnp.8.xml" xpointer='xpointer(//refsect1[@id = "pam_nnp-options"]/*)'/> + </section> + + <section> + <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" + href="nnp.conf.5.xml" xpointer='xpointer(//refsect1[@id = "nnp.conf-examples"]/*)'/> + </section> + +</article> diff --git a/modules/pam_nnp/nnp.conf b/modules/pam_nnp/nnp.conf new file mode 100644 index 0000000..38152fa --- /dev/null +++ b/modules/pam_nnp/nnp.conf @@ -0,0 +1,16 @@ +# /etc/security/nnp.conf +# +#Each line describes a no_new_privs instruction for a user, group, or range. +# +#<domain> <action> +# +#Where: +#<domain> can be: +# - an user name +# - a group name, with @group syntax +# - the wildcard *, for default entry +# +#<action> can have the two values: +# - "no_new_privs" to set no_new_privs +# - "done" to stop processing further lines + diff --git a/modules/pam_nnp/nnp.conf.5.xml b/modules/pam_nnp/nnp.conf.5.xml new file mode 100644 index 0000000..9297a43 --- /dev/null +++ b/modules/pam_nnp/nnp.conf.5.xml @@ -0,0 +1,142 @@ +<?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="nnp.conf"> + + <refmeta> + <refentrytitle>nnp.conf</refentrytitle> + <manvolnum>5</manvolnum> + <refmiscinfo class="sectdesc">Linux-PAM Manual</refmiscinfo> + </refmeta> + + <refnamediv> + <refname>nnp.conf</refname> + <refpurpose>configuration file for the pam_nnp module</refpurpose> + </refnamediv> + + <refsect1 id='nnp.conf-description'> + <title>DESCRIPTION</title> + <para> + The <emphasis>pam_nnp.so</emphasis> PAM module sets the + no_new_privs flag on sessions for selected users or groups. + Thae <filename>/etc/security/nnp.conf</filename> file determines + which users or groups are affected. + </para> + <para> + The syntax of the lines is as follows: + </para> + <para> + <replaceable><domain></replaceable> <replaceable><action></replaceable> + </para> + <para> + The fields listed above should be filled as follows: + </para> + <variablelist> + <varlistentry> + <term> + <option><domain></option> + </term> + <listitem> + <itemizedlist> + <listitem> + <para> + a username + </para> + </listitem> + <listitem> + <para> + a groupname, with <emphasis remap='B'>@group</emphasis> syntax. + </para> + </listitem> + <listitem> + <para> + the wildcard <emphasis remap='B'>*</emphasis> matches all users. + </para> + </listitem> + <listitem> + <para> + an uid range specified as <replaceable><min_uid></replaceable><emphasis + remap='B'>:</emphasis><replaceable><max_uid></replaceable>. If min_uid + is omitted, the match is exact for the max_uid. If max_uid is omitted, all + uids greater than or equal min_uid match. + </para> + </listitem> + <listitem> + <para> + a gid range specified as <emphasis + remap='B'>@</emphasis><replaceable><min_gid></replaceable><emphasis + remap='B'>:</emphasis><replaceable><max_gid></replaceable>. If min_gid + is omitted, the match is exact for the max_gid. If max_gid is omitted, all + gids greater than or equal min_gid match. For the exact match all groups including + the user's supplementary groups are examined. For the range matches only + the user's primary group is examined. + </para> + </listitem> + </itemizedlist> + </listitem> + </varlistentry> + + <varlistentry> + <term> + <option><action></option> + </term> + <listitem> + <variablelist> + <varlistentry> + <term><option>no_new_privs</option></term> + <listitem> + <para>Set the no_new_privs flag for the session.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>done</option></term> + <listitem> + <para>Stop processing rules.</para> + </listitem> + </varlistentry> + </variablelist> + </listitem> + </varlistentry> + + </variablelist> + <para> + The pam_nnp module reports configuration problems + found in its configuration file and errors via <citerefentry> + <refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>. + </para> + </refsect1> + + <refsect1 id="nnp.conf-examples"> + <title>EXAMPLES</title> + <para> + These are some example lines which might be specified in + <filename>/etc/security/nnp.conf</filename>. + </para> + <programlisting> +@student no_new_privs +@faculty done +ftp no_new_privs +:123 no_new_privs +@650: done +600:700 no_new_privs + </programlisting> + </refsect1> + + <refsect1 id="nnp.conf-see_also"> + <title>SEE ALSO</title> + <para> + <citerefentry><refentrytitle>pam_nnp</refentrytitle><manvolnum>8</manvolnum></citerefentry>, + <citerefentry><refentrytitle>pam.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>, + <citerefentry><refentrytitle>pam</refentrytitle><manvolnum>8</manvolnum></citerefentry>, + <citerefentry><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry> + </para> + </refsect1> + + <refsect1 id="nnp.conf-author"> + <title>AUTHOR</title> + <para> + pam_nnp was initially written by Andy Lutomirski <luto@xxxxxxxxxxxxxx>. + </para> + </refsect1> +</refentry> diff --git a/modules/pam_nnp/pam_nnp.8.xml b/modules/pam_nnp/pam_nnp.8.xml new file mode 100644 index 0000000..11edcd8 --- /dev/null +++ b/modules/pam_nnp/pam_nnp.8.xml @@ -0,0 +1,174 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" + "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"> + +<refentry id='pam_nnp'> + + <refmeta> + <refentrytitle>pam_nnp</refentrytitle> + <manvolnum>8</manvolnum> + <refmiscinfo class='setdesc'>Linux-PAM Manual</refmiscinfo> + </refmeta> + + <refnamediv id='pam_nnp-name'> + <refname>pam_nnp</refname> + <refpurpose> + PAM module to set no_new_privs + </refpurpose> + </refnamediv> + +<!-- body begins here --> + + <refsynopsisdiv> + <cmdsynopsis id="pam_nnp-cmdsynopsis"> + <command>pam_nnp.so</command> + <arg choice="opt"> + conf=<replaceable>/path/to/nnp.conf</replaceable> + </arg> + <arg choice="opt"> + debug + </arg> + </cmdsynopsis> + </refsynopsisdiv> + + + <refsect1 id="pam_nnp-description"> + <title>DESCRIPTION</title> + <para> + The pam_nnp PAM module sets the no_new_privs flag on sessions for selected users or groups. + The no_new_privs flag prevents affected processes and their descendents from gaining privilege + via setuid programs, setgid programs, and file capabilities. This can reduce the attack + surface available to these processes. + </para> + <para> + By default settings are taken from the <filename>/etc/security/nnp.conf</filename> config + file. If a config file is explicitly specified with a module option then the files in the + above directory are not parsed. + </para> + <para> + The module must not be called by a multithreaded application. + </para> + </refsect1> + + <refsect1 id="pam_nnp-options"> + <title>OPTIONS</title> + <variablelist> + <varlistentry> + <term> + <option>conf=<replaceable>/path/to/nnp.conf</replaceable></option> + </term> + <listitem> + <para> + Indicate an alternative nnp.conf style configuration file to + override the default. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <option>debug</option> + </term> + <listitem> + <para> + Print debug information. + </para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1 id="pam_nnp-types"> + <title>MODULE TYPES PROVIDED</title> + <para> + Only the <option>session</option> module type is provided. + </para> + </refsect1> + + <refsect1 id="pam_nnp-return_values"> + <title>RETURN VALUES</title> + <variablelist> + <varlistentry> + <term>PAM_IGNORE</term> + <listitem> + <para> + no_new_privs was not configured for this user. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>PAM_SERVICE_ERR</term> + <listitem> + <para> + Cannot read config file. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>PAM_SESSION_ERR</term> + <listitem> + <para> + Error recovering account name. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>PAM_SYSTEM_ERR</term> + <listitem> + <para> + no_new_privs was configured, but the kernel rejected the attempt to set it. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>PAM_SUCCESS</term> + <listitem> + <para> + no_new_privs was set. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>PAM_USER_UNKNOWN</term> + <listitem> + <para> + The user is not known to the system. + </para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1 id="pam_nnp-files"> + <title>FILES</title> + <variablelist> + <varlistentry> + <term><filename>/etc/security/nnp.conf</filename></term> + <listitem> + <para>Default configuration file</para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1 id="pam_nnp-see_also"> + <title>SEE ALSO</title> + <para> + <citerefentry> + <refentrytitle>nnp.conf</refentrytitle><manvolnum>5</manvolnum> + </citerefentry>, + <citerefentry> + <refentrytitle>pam.d</refentrytitle><manvolnum>5</manvolnum> + </citerefentry>, + <citerefentry> + <refentrytitle>pam</refentrytitle><manvolnum>8</manvolnum> + </citerefentry>. + </para> + </refsect1> + + <refsect1 id="pam_nnp-authors"> + <title>AUTHORS</title> + <para> + pam_nnp was initially written by Andy Lutomirski <luto@xxxxxxxxxxxxxx> + </para> + </refsect1> +</refentry> diff --git a/modules/pam_nnp/pam_nnp.c b/modules/pam_nnp/pam_nnp.c new file mode 100644 index 0000000..9b43566 --- /dev/null +++ b/modules/pam_nnp/pam_nnp.c @@ -0,0 +1,358 @@ +/* + * pam_nnp: no_new_privs support for pam + * + * Loosely based on pam_limits from Linux-PAM. + * + * + * Copyright (c) 2012 Andrew Lutomirski + * Copyright (c) Cristian Gafton, 1996-1997, <gafton@xxxxxxxxxx> + * All rights reserved. + * + * 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. + */ + +#if !defined(linux) && !defined(__linux) +#warning THIS CODE IS KNOWN TO WORK ONLY ON LINUX !!! +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#include <errno.h> +#include <syslog.h> +#include <stdbool.h> +#include <sys/prctl.h> + +#include <pwd.h> + +#define UNUSED __attribute__((unused)) + +/* Module defines */ +#define LINE_LENGTH 1024 + +#define NNP_RANGE_ERR -1 /* error in specified uid/gid range */ +#define NNP_RANGE_NONE 0 /* no range specified */ +#define NNP_RANGE_ONE 1 /* exact uid/gid specified (:max_uid)*/ +#define NNP_RANGE_MIN 2 /* only minimum uid/gid specified (min_uid:) */ +#define NNP_RANGE_MM 3 /* both min and max uid/gid specified (min_uid:max_uid) */ + +#define PAM_DEBUG_ARG 1 + +/* internal data */ +struct pam_nnp_s { + bool nnp; + const char *conf_file; +}; + +#define PAM_SM_SESSION + +#include <security/pam_modules.h> +#include <security/_pam_macros.h> +#include <security/pam_modutil.h> +#include <security/pam_ext.h> + +static int +_pam_parse (const pam_handle_t *pamh, int argc, const char **argv, + struct pam_nnp_s *pl) +{ + int ctrl=0; + + /* step through arguments */ + for (ctrl = 0; argc-- > 0; ++argv) { + if (!strcmp(*argv,"debug")) { + ctrl |= PAM_DEBUG_ARG; + } else { + pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv); + } + } + + return ctrl; +} + +static int +parse_uid_range(pam_handle_t *pamh, const char *domain, + uid_t *min_uid, uid_t *max_uid) +{ + const char *range = domain; + char *pmax; + char *endptr; + int rv = NNP_RANGE_MM; + + if ((pmax=strchr(range, ':')) == NULL) + return NNP_RANGE_NONE; + ++pmax; + + if (range[0] == '@') + ++range; + + if (range[0] == ':') + rv = NNP_RANGE_ONE; + else { + errno = 0; + *min_uid = strtoul (range, &endptr, 10); + if (errno != 0 || (range == endptr) || *endptr != ':') { + pam_syslog(pamh, LOG_DEBUG, + "wrong min_uid/gid value in '%s'", domain); + return NNP_RANGE_ERR; + } + } + + if (*pmax == '\0') { + if (rv == NNP_RANGE_ONE) + return NNP_RANGE_ERR; + else + return NNP_RANGE_MIN; + } + + errno = 0; + *max_uid = strtoul (pmax, &endptr, 10); + if (errno != 0 || (pmax == endptr) || *endptr != '\0') { + pam_syslog(pamh, LOG_DEBUG, + "wrong max_uid/gid value in '%s'", domain); + return NNP_RANGE_ERR; + } + + if (rv == NNP_RANGE_ONE) + *min_uid = *max_uid; + return rv; +} + +static int +parse_config_file(pam_handle_t *pamh, const char *uname, uid_t uid, gid_t gid, + int ctrl, struct pam_nnp_s *pl) +{ + FILE *fil; + char buf[LINE_LENGTH]; + const char *conf_file = pl->conf_file ? pl->conf_file : NNP_FILE; + + /* check for the NNP_FILE */ + if (ctrl & PAM_DEBUG_ARG) + pam_syslog(pamh, LOG_DEBUG, "reading settings from '%s'", conf_file); + fil = fopen(conf_file, "r"); + if (fil == NULL) { + pam_syslog (pamh, LOG_WARNING, + "cannot read settings from %s: %m", conf_file); + return PAM_SERVICE_ERR; + } + + enum nnp_mode { DONE, NNP } mode = DONE; + + /* start the show */ + while (fgets(buf, LINE_LENGTH, fil) != NULL) { + char domain[LINE_LENGTH]; + char action[LINE_LENGTH]; + + int i; + int rngtype; + char *tptr,*line; + uid_t min_uid = (uid_t)-1, max_uid = (uid_t)-1; + + line = buf; + /* skip the leading white space */ + while (*line && isspace(*line)) + line++; + + /* Rip off the comments */ + tptr = strchr(line,'#'); + if (tptr) + *tptr = '\0'; + /* Rip off the newline char */ + tptr = strchr(line,'\n'); + if (tptr) + *tptr = '\0'; + /* Anything left ? */ + if (!strlen(line)) + continue; + + domain[0] = action[0] = '\0'; + + i = sscanf(line, "%s%s", domain, action); + D(("scanned line[%d]: domain[%s], action[%s]", i, domain, action)); + + if ((rngtype=parse_uid_range(pamh, domain, &min_uid, &max_uid)) < 0) { + pam_syslog(pamh, LOG_WARNING, "invalid uid range '%s' - skipped", domain); + continue; + } + + if (i == 2) { /* a complete line */ + enum nnp_mode this_mode; + if (!strcasecmp(action, "no_new_privs") != 0) { + this_mode = NNP; + } else if (!strcasecmp(action, "done") != 0) { + this_mode = DONE; + } else { + pam_syslog(pamh, LOG_WARNING, "unknown action %s", action); + continue; + } + + if (strcmp(uname, domain) == 0) { /* match for user name */ + if (ctrl & PAM_DEBUG_ARG) + pam_syslog(pamh, LOG_DEBUG, "direct match for user %s", uname); + mode = this_mode; + goto parse_done; + } else if (domain[0]=='@') { /* some kind of group */ + if (ctrl & PAM_DEBUG_ARG) { + pam_syslog(pamh, LOG_DEBUG, + "checking if %s is in group %s", + uname, domain + 1); + } + switch(rngtype) { + case NNP_RANGE_NONE: + if (pam_modutil_user_in_group_nam_nam(pamh, uname, domain+1)) { + mode = this_mode; + goto parse_done; + } + break; + case NNP_RANGE_ONE: + if (pam_modutil_user_in_group_nam_gid(pamh, uname, (gid_t)max_uid)) { + mode = this_mode; + goto parse_done; + } + break; + case NNP_RANGE_MM: + if (gid > (gid_t)max_uid) + break; + /* fallthrough */ + case NNP_RANGE_MIN: + if (gid >= (gid_t)min_uid) { + mode = this_mode; + goto parse_done; + } + } + } else { + switch(rngtype) { /* match against uid (not username) */ + case NNP_RANGE_NONE: + if (strcmp(domain, "*") == 0) { + mode = this_mode; + goto parse_done; + } + break; + case NNP_RANGE_ONE: + if (uid != max_uid) + break; + /* fallthrough */ + case NNP_RANGE_MM: + if (uid > max_uid) + break; + /* fallthrough */ + case NNP_RANGE_MIN: + if (uid >= min_uid) { + mode = this_mode; + goto parse_done; + } + } + } + } else { + pam_syslog(pamh, LOG_WARNING, "invalid line '%s' - skipped", line); + } + } + parse_done: + fclose(fil); + + pl->nnp = (mode == NNP); + + return PAM_SUCCESS; +} + +/* now the session stuff */ +PAM_EXTERN int +pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED, + int argc, const char **argv) +{ + int retval; + char *user_name; + struct passwd *pwd; + int ctrl; + struct pam_nnp_s plstruct; + struct pam_nnp_s *pl = &plstruct; + + D(("called.")); + + memset(pl, 0, sizeof(*pl)); + + ctrl = _pam_parse(pamh, argc, argv, pl); + retval = pam_get_item( pamh, PAM_USER, (void*) &user_name ); + if ( user_name == NULL || retval != PAM_SUCCESS ) { + pam_syslog(pamh, LOG_CRIT, "open_session - error recovering username"); + return PAM_SESSION_ERR; + } + + pwd = pam_modutil_getpwnam(pamh, user_name); + if (!pwd) { + if (ctrl & PAM_DEBUG_ARG) + pam_syslog(pamh, LOG_WARNING, + "open_session username '%s' does not exist", user_name); + return PAM_USER_UNKNOWN; + } + + retval = parse_config_file(pamh, pwd->pw_name, pwd->pw_uid, pwd->pw_gid, ctrl, pl); + + if (retval == PAM_SUCCESS && pl->nnp) { + if (ctrl & PAM_DEBUG_ARG) + pam_syslog(pamh, LOG_DEBUG, + "Setting no_new_privs for user '%s'", user_name); + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) { + pam_error(pamh, "Failed to set no_new_privs for '%s'.", + pwd->pw_name); + return PAM_SYSTEM_ERR; /* This really has no business failing. */ + } + return PAM_SUCCESS; + } + + return PAM_IGNORE; +} + +PAM_EXTERN int +pam_sm_close_session (pam_handle_t *pamh UNUSED, int flags UNUSED, + int argc UNUSED, const char **argv UNUSED) +{ + /* nothing to do */ + return PAM_SUCCESS; +} + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_nnp_modstruct = { + "pam_nnp", + NULL, + NULL, + NULL, + pam_sm_open_session, + pam_sm_close_session, + NULL +}; +#endif + diff --git a/modules/pam_nnp/tst-pam_nnp b/modules/pam_nnp/tst-pam_nnp new file mode 100755 index 0000000..295821d --- /dev/null +++ b/modules/pam_nnp/tst-pam_nnp @@ -0,0 +1,2 @@ +#!/bin/sh +../../tests/tst-dlopen .libs/pam_nnp.so -- 1.8.3.1 _______________________________________________ Pam-list mailing list Pam-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/pam-list