Blob Blame History Raw
diff -up Linux-PAM-1.3.1/configure.ac.pam-usertype Linux-PAM-1.3.1/configure.ac
--- Linux-PAM-1.3.1/configure.ac.pam-usertype	2020-05-15 10:03:27.247468160 +0200
+++ Linux-PAM-1.3.1/configure.ac	2020-05-15 10:03:27.270468089 +0200
@@ -606,6 +606,27 @@ AC_SUBST([HAVE_KEY_MANAGEMENT], $HAVE_KE
 
 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/Makefil
 	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 -up Linux-PAM-1.3.1/modules/Makefile.am.pam-usertype Linux-PAM-1.3.1/modules/Makefile.am
--- Linux-PAM-1.3.1/modules/Makefile.am.pam-usertype	2020-05-15 10:03:27.247468160 +0200
+++ Linux-PAM-1.3.1/modules/Makefile.am	2020-05-15 10:03:27.270468089 +0200
@@ -12,7 +12,7 @@ SUBDIRS = pam_access pam_cracklib pam_de
 	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 -up Linux-PAM-1.3.1/modules/pam_usertype/Makefile.am.pam-usertype Linux-PAM-1.3.1/modules/pam_usertype/Makefile.am
--- Linux-PAM-1.3.1/modules/pam_usertype/Makefile.am.pam-usertype	2020-05-15 10:03:27.270468089 +0200
+++ Linux-PAM-1.3.1/modules/pam_usertype/Makefile.am	2020-05-15 10:03:27.270468089 +0200
@@ -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 -up Linux-PAM-1.3.1/modules/pam_usertype/pam_usertype.8.xml.pam-usertype Linux-PAM-1.3.1/modules/pam_usertype/pam_usertype.8.xml
--- Linux-PAM-1.3.1/modules/pam_usertype/pam_usertype.8.xml.pam-usertype	2020-05-15 10:03:27.270468089 +0200
+++ Linux-PAM-1.3.1/modules/pam_usertype/pam_usertype.8.xml	2020-05-15 10:03:27.270468089 +0200
@@ -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 -up Linux-PAM-1.3.1/modules/pam_usertype/pam_usertype.c.pam-usertype Linux-PAM-1.3.1/modules/pam_usertype/pam_usertype.c
--- Linux-PAM-1.3.1/modules/pam_usertype/pam_usertype.c.pam-usertype	2020-05-15 10:03:27.270468089 +0200
+++ Linux-PAM-1.3.1/modules/pam_usertype/pam_usertype.c	2020-05-15 10:16:08.053198025 +0200
@@ -0,0 +1,394 @@
+/******************************************************************************
+ * 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>
+#include <stdio.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
+
+/* lookup a value for key in login.defs file or similar key value format */
+char *
+pam_usertype_search_key(pam_handle_t *pamh UNUSED,
+		       const char *file_name,
+		       const char *key)
+{
+	FILE *fp;
+	char *buf = NULL;
+	size_t buflen = 0;
+	char *retval = NULL;
+
+	fp = fopen(file_name, "r");
+	if (NULL == fp)
+		return NULL;
+
+	while (!feof(fp)) {
+		char *tmp, *cp;
+#if defined(HAVE_GETLINE)
+		ssize_t n = getline(&buf, &buflen, fp);
+#elif defined (HAVE_GETDELIM)
+		ssize_t n = getdelim(&buf, &buflen, '\n', fp);
+#else
+		ssize_t n;
+
+		if (buf == NULL) {
+			buflen = BUF_SIZE;
+			buf = malloc(buflen);
+			if (buf == NULL) {
+				fclose(fp);
+				return NULL;
+			}
+		}
+		buf[0] = '\0';
+		if (fgets(buf, buflen - 1, fp) == NULL)
+			break;
+		else if (buf != NULL)
+			n = strlen(buf);
+		else
+			n = 0;
+#endif /* HAVE_GETLINE / HAVE_GETDELIM */
+		cp = buf;
+
+		if (n < 1)
+			break;
+		if (cp[n - 1] == '\n')
+			cp[n - 1] = '\0';
+
+		tmp = strchr(cp, '#');  /* remove comments */
+		if (tmp)
+			*tmp = '\0';
+		while (isspace((int)*cp))    /* remove spaces and tabs */
+			++cp;
+		if (*cp == '\0')        /* ignore empty lines */
+			continue;
+
+		tmp = strsep (&cp, " \t=");
+		if (cp != NULL)
+			while (isspace((int)*cp) || *cp == '=')
+				++cp;
+		else
+			cp = "";
+
+		if (strcasecmp(tmp, key) == 0) {
+			retval = strdup(cp);
+			break;
+		}
+	}
+	fclose(fp);
+
+	free(buf);
+
+	return retval;
+}
+
+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_usertype_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 -up Linux-PAM-1.3.1/modules/pam_usertype/README.xml.pam-usertype Linux-PAM-1.3.1/modules/pam_usertype/README.xml
--- Linux-PAM-1.3.1/modules/pam_usertype/README.xml.pam-usertype	2020-05-15 10:03:27.270468089 +0200
+++ Linux-PAM-1.3.1/modules/pam_usertype/README.xml	2020-05-15 10:03:27.270468089 +0200
@@ -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 -up Linux-PAM-1.3.1/modules/pam_usertype/tst-pam_usertype.pam-usertype Linux-PAM-1.3.1/modules/pam_usertype/tst-pam_usertype
--- Linux-PAM-1.3.1/modules/pam_usertype/tst-pam_usertype.pam-usertype	2020-05-15 10:03:27.270468089 +0200
+++ Linux-PAM-1.3.1/modules/pam_usertype/tst-pam_usertype	2020-05-15 10:03:27.270468089 +0200
@@ -0,0 +1,2 @@
+#!/bin/sh
+../../tests/tst-dlopen .libs/pam_usertype.so