Blob Blame History Raw
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 &lt;pbrezina@redhat.com&gt;</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