685 lines
21 KiB
Diff
685 lines
21 KiB
Diff
From 88df4b5383b776b7b8ee9eb4c33231d54185b1e2 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
|
|
Date: Fri, 10 Jan 2020 15:53:35 +0100
|
|
Subject: [PATCH] pam_usertype: new module to tell if uid is in login.defs
|
|
ranges
|
|
|
|
This module will check if the user account type is system or regular based
|
|
on its uid. To evaluate the condition it will use 0-99 reserved range
|
|
together with `SYS_UID_MIN` and `SYS_UID_MAX` values from `/etc/login.defs`.
|
|
|
|
If these values are not set, it uses configure-time defaults
|
|
`--with-sys-uid-min` and `--with-uid-min` (according to `login.defs` man page
|
|
`SYS_UID_MAX` defaults to `UID_MIN - 1`.
|
|
|
|
This information can be used to skip specific module in pam stack
|
|
based on the account type. `pam_succeed_if uid < 1000` is used at the moment
|
|
however it does not reflect changes to `login.defs`.
|
|
---
|
|
configure.ac | 22 ++
|
|
modules/Makefile.am | 2 +-
|
|
modules/pam_usertype/Makefile.am | 34 +++
|
|
modules/pam_usertype/README.xml | 41 +++
|
|
modules/pam_usertype/pam_usertype.8.xml | 170 +++++++++++++
|
|
modules/pam_usertype/pam_usertype.c | 319 ++++++++++++++++++++++++
|
|
modules/pam_usertype/tst-pam_usertype | 2 +
|
|
7 files changed, 589 insertions(+), 1 deletion(-)
|
|
create mode 100644 modules/pam_usertype/Makefile.am
|
|
create mode 100644 modules/pam_usertype/README.xml
|
|
create mode 100644 modules/pam_usertype/pam_usertype.8.xml
|
|
create mode 100644 modules/pam_usertype/pam_usertype.c
|
|
create mode 100755 modules/pam_usertype/tst-pam_usertype
|
|
|
|
diff --git a/configure.ac b/configure.ac
|
|
index 0267202d2f56cbb641ce74d283bc4ba2a4b3d0d9..f10a09e14c10639b91c356d6ef883da4a0a87a66 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -606,6 +606,27 @@ AC_SUBST([HAVE_KEY_MANAGEMENT], $HAVE_KEY_MANAGEMENT)
|
|
|
|
AM_CONDITIONAL([HAVE_KEY_MANAGEMENT], [test "$have_key_syscalls" = 1])
|
|
|
|
+dnl
|
|
+dnl Get values for default uid ranges in login.defs used in pam_usertype
|
|
+dnl
|
|
+AC_ARG_WITH([uidmin], AS_HELP_STRING([--with-uidmin=<number>],[default value for regular user min uid (1000)]), opt_uidmin=$withval)
|
|
+if test x"$opt_uidmin" == x; then
|
|
+ opt_uidmin=1000
|
|
+fi
|
|
+AC_DEFINE_UNQUOTED(PAM_USERTYPE_UIDMIN, $opt_uidmin, [Minimum regular user uid.])
|
|
+
|
|
+AC_ARG_WITH([sysuidmin], AS_HELP_STRING([--with-sysuidmin=<number>],[default value for system user min uid (101)]), opt_sysuidmin=$withval)
|
|
+if test x"$opt_sysuidmin" == x; then
|
|
+ opt_sysuidmin=101
|
|
+fi
|
|
+AC_DEFINE_UNQUOTED(PAM_USERTYPE_SYSUIDMIN, $opt_sysuidmin, [Minimum system user uid.])
|
|
+
|
|
+AC_ARG_WITH([kerneloverflowuid], AS_HELP_STRING([--with-kernel-overflow-uid=<number>],[kernel overflow uid, default (uint16_t)-2=65534]), opt_kerneloverflowuid=$withval)
|
|
+if test x"$opt_kerneloverflowuid" == x; then
|
|
+ opt_kerneloverflowuid=65534
|
|
+fi
|
|
+AC_DEFINE_UNQUOTED(PAM_USERTYPE_OVERFLOW_UID, $opt_kerneloverflowuid, [Kernel overflow uid.])
|
|
+
|
|
dnl Files to be created from when we run configure
|
|
AC_CONFIG_FILES([Makefile libpam/Makefile libpamc/Makefile libpamc/test/Makefile \
|
|
libpam_misc/Makefile conf/Makefile conf/pam_conv1/Makefile \
|
|
@@ -636,6 +657,7 @@ AC_CONFIG_FILES([Makefile libpam/Makefile libpamc/Makefile libpamc/test/Makefile
|
|
modules/pam_timestamp/Makefile modules/pam_tty_audit/Makefile \
|
|
modules/pam_umask/Makefile \
|
|
modules/pam_unix/Makefile modules/pam_userdb/Makefile \
|
|
+ modules/pam_usertype/Makefile \
|
|
modules/pam_warn/Makefile modules/pam_wheel/Makefile \
|
|
modules/pam_xauth/Makefile doc/Makefile doc/specs/Makefile \
|
|
doc/man/Makefile doc/sag/Makefile doc/adg/Makefile \
|
|
diff --git a/modules/Makefile.am b/modules/Makefile.am
|
|
index 5149181e2d1aeefbab8876433e8a54848ec56fc6..c1b5c5611c79e666bbd2f94fa0712a2b78bd2f5f 100644
|
|
--- a/modules/Makefile.am
|
|
+++ b/modules/Makefile.am
|
|
@@ -12,7 +12,7 @@ SUBDIRS = pam_access pam_cracklib pam_debug pam_deny pam_echo \
|
|
pam_selinux pam_sepermit pam_shells pam_stress \
|
|
pam_succeed_if pam_time pam_timestamp \
|
|
pam_tty_audit pam_umask \
|
|
- pam_unix pam_userdb pam_warn pam_wheel pam_xauth
|
|
+ pam_unix pam_userdb pam_usertype pam_warn pam_wheel pam_xauth
|
|
|
|
CLEANFILES = *~
|
|
|
|
diff --git a/modules/pam_usertype/Makefile.am b/modules/pam_usertype/Makefile.am
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..1646bc34f2fbc44032af5a5b38d160614b247b72
|
|
--- /dev/null
|
|
+++ b/modules/pam_usertype/Makefile.am
|
|
@@ -0,0 +1,34 @@
|
|
+#
|
|
+# Copyright (c) 2005, 2006, 2009 Thorsten Kukuk <kukuk@suse.de>
|
|
+# Copyright (c) 2020 Red Hat, Inc.
|
|
+#
|
|
+
|
|
+CLEANFILES = *~
|
|
+MAINTAINERCLEANFILES = $(MANS) README
|
|
+
|
|
+EXTRA_DIST = README ${MANS} ${XMLS} tst-pam_usertype
|
|
+
|
|
+TESTS = tst-pam_usertype
|
|
+
|
|
+man_MANS = pam_usertype.8
|
|
+
|
|
+XMLS = README.xml pam_usertype.8.xml
|
|
+
|
|
+securelibdir = $(SECUREDIR)
|
|
+secureconfdir = $(SCONFIGDIR)
|
|
+
|
|
+AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \
|
|
+ $(WARN_CFLAGS)
|
|
+AM_LDFLAGS = -no-undefined -avoid-version -module
|
|
+if HAVE_VERSIONING
|
|
+ AM_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map
|
|
+endif
|
|
+
|
|
+securelib_LTLIBRARIES = pam_usertype.la
|
|
+pam_usertype_la_LIBADD = $(top_builddir)/libpam/libpam.la
|
|
+
|
|
+if ENABLE_REGENERATE_MAN
|
|
+noinst_DATA = README
|
|
+README: pam_usertype.8.xml
|
|
+-include $(top_srcdir)/Make.xml.rules
|
|
+endif
|
|
diff --git a/modules/pam_usertype/README.xml b/modules/pam_usertype/README.xml
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..58550465459222ace5e346c32b54cf6776eeeec5
|
|
--- /dev/null
|
|
+++ b/modules/pam_usertype/README.xml
|
|
@@ -0,0 +1,41 @@
|
|
+<?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 pamaccess SYSTEM "pam_usertype.8.xml">
|
|
+-->
|
|
+]>
|
|
+
|
|
+<article>
|
|
+
|
|
+ <articleinfo>
|
|
+
|
|
+ <title>
|
|
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"
|
|
+ href="pam_usertype.8.xml" xpointer='xpointer(//refnamediv[@id = "pam_usertype-name"]/*)'/>
|
|
+ </title>
|
|
+
|
|
+ </articleinfo>
|
|
+
|
|
+ <section>
|
|
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"
|
|
+ href="pam_usertype.8.xml" xpointer='xpointer(//refsect1[@id = "pam_usertype-description"]/*)'/>
|
|
+ </section>
|
|
+
|
|
+ <section>
|
|
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"
|
|
+ href="pam_usertype.8.xml" xpointer='xpointer(//refsect1[@id = "pam_usertype-options"]/*)'/>
|
|
+ </section>
|
|
+
|
|
+ <section>
|
|
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"
|
|
+ href="pam_usertype.8.xml" xpointer='xpointer(//refsect1[@id = "pam_usertype-examples"]/*)'/>
|
|
+ </section>
|
|
+
|
|
+ <section>
|
|
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"
|
|
+ href="pam_usertype.8.xml" xpointer='xpointer(//refsect1[@id = "pam_usertype-author"]/*)'/>
|
|
+ </section>
|
|
+
|
|
+</article>
|
|
diff --git a/modules/pam_usertype/pam_usertype.8.xml b/modules/pam_usertype/pam_usertype.8.xml
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..1ba4ee71dcd4faee1bf5293c718d1bdf823689f0
|
|
--- /dev/null
|
|
+++ b/modules/pam_usertype/pam_usertype.8.xml
|
|
@@ -0,0 +1,170 @@
|
|
+<?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_usertype'>
|
|
+ <refmeta>
|
|
+ <refentrytitle>pam_usertype</refentrytitle>
|
|
+ <manvolnum>8</manvolnum>
|
|
+ <refmiscinfo class='sectdesc'>Linux-PAM</refmiscinfo>
|
|
+ </refmeta>
|
|
+
|
|
+ <refnamediv id='pam_usertype-name'>
|
|
+ <refname>pam_usertype</refname>
|
|
+ <refpurpose>check if the authenticated user is a system or regular account</refpurpose>
|
|
+ </refnamediv>
|
|
+
|
|
+
|
|
+ <refsynopsisdiv>
|
|
+ <cmdsynopsis id='pam_usertype-cmdsynopsis'>
|
|
+ <command>pam_usertype.so</command>
|
|
+ <arg choice='opt' rep='repeat'><replaceable>flag</replaceable></arg>
|
|
+ <arg choice='req'><replaceable>condition</replaceable></arg>
|
|
+ </cmdsynopsis>
|
|
+ </refsynopsisdiv>
|
|
+
|
|
+
|
|
+ <refsect1 id='pam_usertype-description'>
|
|
+ <title>DESCRIPTION</title>
|
|
+ <para>
|
|
+ pam_usertype.so is designed to succeed or fail authentication
|
|
+ based on type of the account of the authenticated user.
|
|
+ The type of the account is decided with help of
|
|
+ <emphasis>SYS_UID_MIN</emphasis> and <emphasis>SYS_UID_MAX</emphasis>
|
|
+ settings in <emphasis>/etc/login.defs</emphasis>. One use is to select
|
|
+ whether to load other modules based on this test.
|
|
+ </para>
|
|
+
|
|
+ <para>
|
|
+ The module should be given only one condition as module argument.
|
|
+ Authentication will succeed only if the condition is met.
|
|
+ </para>
|
|
+ </refsect1>
|
|
+
|
|
+ <refsect1 id="pam_usertype-options">
|
|
+ <title>OPTIONS</title>
|
|
+ <para>
|
|
+ The following <emphasis>flag</emphasis>s are supported:
|
|
+ </para>
|
|
+
|
|
+ <variablelist>
|
|
+ <varlistentry>
|
|
+ <term><option>use_uid</option></term>
|
|
+ <listitem>
|
|
+ <para>
|
|
+ Evaluate conditions using the account of the user whose UID
|
|
+ the application is running under instead of the user being
|
|
+ authenticated.
|
|
+ </para>
|
|
+ </listitem>
|
|
+ </varlistentry>
|
|
+ <varlistentry>
|
|
+ <term><option>audit</option></term>
|
|
+ <listitem>
|
|
+ <para>
|
|
+ Log unknown users to the system log.
|
|
+ </para>
|
|
+ </listitem>
|
|
+ </varlistentry>
|
|
+ </variablelist>
|
|
+
|
|
+ <para>
|
|
+ Available <emphasis>condition</emphasis>s are:
|
|
+ </para>
|
|
+
|
|
+ <variablelist>
|
|
+ <varlistentry>
|
|
+ <term><option>issystem</option></term>
|
|
+ <listitem>
|
|
+ <para>Succeed if the user is a system user.</para>
|
|
+ </listitem>
|
|
+ </varlistentry>
|
|
+ <varlistentry>
|
|
+ <term><option>isregular</option></term>
|
|
+ <listitem>
|
|
+ <para>Succeed if the user is a regular user.</para>
|
|
+ </listitem>
|
|
+ </varlistentry>
|
|
+ </variablelist>
|
|
+ </refsect1>
|
|
+
|
|
+ <refsect1 id="pam_usertype-types">
|
|
+ <title>MODULE TYPES PROVIDED</title>
|
|
+ <para>
|
|
+ All module types (<option>account</option>, <option>auth</option>,
|
|
+ <option>password</option> and <option>session</option>) are provided.
|
|
+ </para>
|
|
+ </refsect1>
|
|
+
|
|
+ <refsect1 id='pam_usertype-return_values'>
|
|
+ <title>RETURN VALUES</title>
|
|
+ <variablelist>
|
|
+
|
|
+ <varlistentry>
|
|
+ <term>PAM_SUCCESS</term>
|
|
+ <listitem>
|
|
+ <para>
|
|
+ The condition was true.
|
|
+ </para>
|
|
+ </listitem>
|
|
+ </varlistentry>
|
|
+
|
|
+ <varlistentry>
|
|
+ <term>PAM_AUTH_ERR</term>
|
|
+ <listitem>
|
|
+ <para>
|
|
+ The condition was false.
|
|
+ </para>
|
|
+ </listitem>
|
|
+ </varlistentry>
|
|
+
|
|
+ <varlistentry>
|
|
+ <term>PAM_SERVICE_ERR</term>
|
|
+ <listitem>
|
|
+ <para>
|
|
+ A service error occurred or the arguments can't be
|
|
+ parsed correctly.
|
|
+ </para>
|
|
+ </listitem>
|
|
+ </varlistentry>
|
|
+
|
|
+ <varlistentry>
|
|
+ <term>PAM_USER_UNKNOWN</term>
|
|
+ <listitem>
|
|
+ <para>
|
|
+ User was not found.
|
|
+ </para>
|
|
+ </listitem>
|
|
+ </varlistentry>
|
|
+ </variablelist>
|
|
+ </refsect1>
|
|
+
|
|
+
|
|
+ <refsect1 id='pam_usertype-examples'>
|
|
+ <title>EXAMPLES</title>
|
|
+ <para>
|
|
+ Skip remaining modules if the user is a system user:
|
|
+ </para>
|
|
+ <programlisting>
|
|
+account sufficient pam_usertype.so issystem
|
|
+ </programlisting>
|
|
+ </refsect1>
|
|
+
|
|
+ <refsect1 id='pam_usertype-see_also'>
|
|
+ <title>SEE ALSO</title>
|
|
+ <para>
|
|
+ <citerefentry>
|
|
+ <refentrytitle>login.defs</refentrytitle><manvolnum>5</manvolnum>
|
|
+ </citerefentry>,
|
|
+ <citerefentry>
|
|
+ <refentrytitle>pam</refentrytitle><manvolnum>8</manvolnum>
|
|
+ </citerefentry>
|
|
+ </para>
|
|
+ </refsect1>
|
|
+
|
|
+ <refsect1 id='pam_usertype-author'>
|
|
+ <title>AUTHOR</title>
|
|
+ <para>Pavel Březina <pbrezina@redhat.com></para>
|
|
+ </refsect1>
|
|
+</refentry>
|
|
diff --git a/modules/pam_usertype/pam_usertype.c b/modules/pam_usertype/pam_usertype.c
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..d3629c137d98545871d24ff26c06d8377068141f
|
|
--- /dev/null
|
|
+++ b/modules/pam_usertype/pam_usertype.c
|
|
@@ -0,0 +1,319 @@
|
|
+/******************************************************************************
|
|
+ * Check user type based on login.defs.
|
|
+ *
|
|
+ * Copyright (c) 2020 Red Hat, Inc.
|
|
+ * Written by Pavel Březina <pbrezina@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 <sys/types.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <syslog.h>
|
|
+#include <unistd.h>
|
|
+#include <pwd.h>
|
|
+#include <ctype.h>
|
|
+#include <errno.h>
|
|
+
|
|
+#define PAM_SM_AUTH
|
|
+#define PAM_SM_ACCOUNT
|
|
+#define PAM_SM_SESSION
|
|
+#define PAM_SM_PASSWORD
|
|
+
|
|
+#include <security/pam_modules.h>
|
|
+#include <security/pam_modutil.h>
|
|
+#include <security/pam_ext.h>
|
|
+
|
|
+#define LOGIN_DEFS "/etc/login.defs"
|
|
+
|
|
+enum pam_usertype_op {
|
|
+ OP_IS_SYSTEM,
|
|
+ OP_IS_REGULAR,
|
|
+
|
|
+ OP_SENTINEL
|
|
+};
|
|
+
|
|
+struct pam_usertype_opts {
|
|
+ enum pam_usertype_op op;
|
|
+ int use_uid;
|
|
+ int audit;
|
|
+};
|
|
+
|
|
+static int
|
|
+pam_usertype_parse_args(struct pam_usertype_opts *opts,
|
|
+ pam_handle_t *pamh,
|
|
+ int argc,
|
|
+ const char **argv)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ memset(opts, 0, sizeof(struct pam_usertype_opts));
|
|
+ opts->op = OP_SENTINEL;
|
|
+
|
|
+ for (i = 0; i < argc; i++) {
|
|
+ if (strcmp(argv[i], "use_uid") == 0) {
|
|
+ opts->use_uid = 1;
|
|
+ } else if (strcmp(argv[i], "audit") == 0) {
|
|
+ opts->audit = 1;
|
|
+ } else if (strcmp(argv[i], "issystem") == 0) {
|
|
+ opts->op = OP_IS_SYSTEM;
|
|
+ } else if (strcmp(argv[i], "isregular") == 0) {
|
|
+ opts->op = OP_IS_REGULAR;
|
|
+ } else {
|
|
+ pam_syslog(pamh, LOG_WARNING, "Unknown argument: %s", argv[i]);
|
|
+ /* Just continue. */
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (opts->op == OP_SENTINEL) {
|
|
+ pam_syslog(pamh, LOG_ERR, "Operation not specified");
|
|
+ return PAM_SERVICE_ERR;
|
|
+ }
|
|
+
|
|
+ return PAM_SUCCESS;
|
|
+}
|
|
+
|
|
+static int
|
|
+pam_usertype_get_uid(struct pam_usertype_opts *opts,
|
|
+ pam_handle_t *pamh,
|
|
+ uid_t *_uid)
|
|
+{
|
|
+ struct passwd *pwd;
|
|
+ const void *prompt;
|
|
+ const char *username;
|
|
+ int ret;
|
|
+
|
|
+ /* Get uid of user that runs the application. */
|
|
+ if (opts->use_uid) {
|
|
+ pwd = pam_modutil_getpwuid(pamh, getuid());
|
|
+ if (pwd == NULL) {
|
|
+ pam_syslog(pamh, LOG_ERR,
|
|
+ "error retrieving information about user %lu",
|
|
+ (unsigned long)getuid());
|
|
+ return PAM_USER_UNKNOWN;
|
|
+ }
|
|
+
|
|
+ *_uid = pwd->pw_uid;
|
|
+ return PAM_SUCCESS;
|
|
+ }
|
|
+
|
|
+ /* Get uid of user that is being authenticated. */
|
|
+ ret = pam_get_item(pamh, PAM_USER_PROMPT, &prompt);
|
|
+ if (ret != PAM_SUCCESS || prompt == NULL || strlen(prompt) == 0) {
|
|
+ prompt = "login: ";
|
|
+ }
|
|
+
|
|
+ ret = pam_get_user(pamh, &username, prompt);
|
|
+ if (ret != PAM_SUCCESS || username == NULL) {
|
|
+ pam_syslog(pamh, LOG_ERR, "error retrieving user name: %s",
|
|
+ pam_strerror(pamh, ret));
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ pwd = pam_modutil_getpwnam(pamh, username);
|
|
+ if (pwd == NULL) {
|
|
+ if (opts->audit) {
|
|
+ pam_syslog(pamh, LOG_NOTICE,
|
|
+ "error retrieving information about user %s", username);
|
|
+ }
|
|
+
|
|
+ return PAM_USER_UNKNOWN;
|
|
+ }
|
|
+
|
|
+ *_uid = pwd->pw_uid;
|
|
+
|
|
+ return PAM_SUCCESS;
|
|
+}
|
|
+
|
|
+#define MAX_UID_VALUE 0xFFFFFFFFUL
|
|
+
|
|
+static uid_t
|
|
+pam_usertype_get_id(pam_handle_t *pamh,
|
|
+ const char *key,
|
|
+ uid_t default_value)
|
|
+{
|
|
+ unsigned long ul;
|
|
+ char *value;
|
|
+ char *ep;
|
|
+ uid_t uid;
|
|
+
|
|
+ value = pam_modutil_search_key(pamh, LOGIN_DEFS, key);
|
|
+ if (value == NULL) {
|
|
+ return default_value;
|
|
+ }
|
|
+
|
|
+ /* taken from get_lastlog_uid_max() */
|
|
+ ep = value + strlen(value);
|
|
+ while (ep > value && isspace(*(--ep))) {
|
|
+ *ep = '\0';
|
|
+ }
|
|
+
|
|
+ errno = 0;
|
|
+ ul = strtoul(value, &ep, 10);
|
|
+ if (!(ul >= MAX_UID_VALUE
|
|
+ || (uid_t)ul >= MAX_UID_VALUE
|
|
+ || (errno != 0 && ul == 0)
|
|
+ || value == ep
|
|
+ || *ep != '\0')) {
|
|
+ uid = (uid_t)ul;
|
|
+ } else {
|
|
+ uid = default_value;
|
|
+ }
|
|
+
|
|
+ free(value);
|
|
+
|
|
+ return uid;
|
|
+}
|
|
+
|
|
+static int
|
|
+pam_usertype_is_system(pam_handle_t *pamh, uid_t uid)
|
|
+{
|
|
+ uid_t uid_min;
|
|
+ uid_t sys_min;
|
|
+ uid_t sys_max;
|
|
+
|
|
+ if (uid == (uid_t)-1) {
|
|
+ pam_syslog(pamh, LOG_WARNING, "invalid uid");
|
|
+ return PAM_USER_UNKNOWN;
|
|
+ }
|
|
+
|
|
+ if (uid <= 99) {
|
|
+ /* Reserved. */
|
|
+ return PAM_SUCCESS;
|
|
+ }
|
|
+
|
|
+ if (uid == PAM_USERTYPE_OVERFLOW_UID) {
|
|
+ /* nobody */
|
|
+ return PAM_SUCCESS;
|
|
+ }
|
|
+
|
|
+ uid_min = pam_usertype_get_id(pamh, "UID_MIN", PAM_USERTYPE_UIDMIN);
|
|
+ sys_min = pam_usertype_get_id(pamh, "SYS_UID_MIN", PAM_USERTYPE_SYSUIDMIN);
|
|
+ sys_max = pam_usertype_get_id(pamh, "SYS_UID_MAX", uid_min - 1);
|
|
+
|
|
+ return uid >= sys_min && uid <= sys_max ? PAM_SUCCESS : PAM_AUTH_ERR;
|
|
+}
|
|
+
|
|
+static int
|
|
+pam_usertype_is_regular(pam_handle_t *pamh, uid_t uid)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = pam_usertype_is_system(pamh, uid);
|
|
+ switch (ret) {
|
|
+ case PAM_SUCCESS:
|
|
+ return PAM_AUTH_ERR;
|
|
+ case PAM_USER_UNKNOWN:
|
|
+ return PAM_USER_UNKNOWN;
|
|
+ default:
|
|
+ return PAM_SUCCESS;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int
|
|
+pam_usertype_evaluate(struct pam_usertype_opts *opts,
|
|
+ pam_handle_t *pamh,
|
|
+ uid_t uid)
|
|
+{
|
|
+ switch (opts->op) {
|
|
+ case OP_IS_SYSTEM:
|
|
+ return pam_usertype_is_system(pamh, uid);
|
|
+ case OP_IS_REGULAR:
|
|
+ return pam_usertype_is_regular(pamh, uid);
|
|
+ default:
|
|
+ pam_syslog(pamh, LOG_ERR, "Unknown operation: %d", opts->op);
|
|
+ return PAM_SERVICE_ERR;
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Arguments:
|
|
+ * - issystem: uid in <SYS_UID_MIN, SYS_UID_MAX>
|
|
+ * - isregular: not issystem
|
|
+ * - use_uid: use user that runs application not that is being authenticate (same as in pam_succeed_if)
|
|
+ * - audit: log unknown users to syslog
|
|
+ */
|
|
+int
|
|
+pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED,
|
|
+ int argc, const char **argv)
|
|
+{
|
|
+ struct pam_usertype_opts opts;
|
|
+ uid_t uid;
|
|
+ int ret;
|
|
+
|
|
+ ret = pam_usertype_parse_args(&opts, pamh, argc, argv);
|
|
+ if (ret != PAM_SUCCESS) {
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = pam_usertype_get_uid(&opts, pamh, &uid);
|
|
+ if (ret != PAM_SUCCESS) {
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return pam_usertype_evaluate(&opts, pamh, uid);
|
|
+}
|
|
+
|
|
+int
|
|
+pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED,
|
|
+ int argc UNUSED, const char **argv UNUSED)
|
|
+{
|
|
+ return PAM_IGNORE;
|
|
+}
|
|
+
|
|
+int
|
|
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
|
+{
|
|
+ return pam_sm_authenticate(pamh, flags, argc, argv);
|
|
+}
|
|
+
|
|
+int
|
|
+pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
|
+{
|
|
+ return pam_sm_authenticate(pamh, flags, argc, argv);
|
|
+}
|
|
+
|
|
+int
|
|
+pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
|
+{
|
|
+ return pam_sm_authenticate(pamh, flags, argc, argv);
|
|
+}
|
|
+
|
|
+int
|
|
+pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
|
+{
|
|
+ return pam_sm_authenticate(pamh, flags, argc, argv);
|
|
+}
|
|
diff --git a/modules/pam_usertype/tst-pam_usertype b/modules/pam_usertype/tst-pam_usertype
|
|
new file mode 100755
|
|
index 0000000000000000000000000000000000000000..a21f8fe7cef3daf6a842bc35972976ee189d3570
|
|
--- /dev/null
|
|
+++ b/modules/pam_usertype/tst-pam_usertype
|
|
@@ -0,0 +1,2 @@
|
|
+#!/bin/sh
|
|
+../../tests/tst-dlopen .libs/pam_usertype.so
|
|
--
|
|
2.24.1
|
|
|