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=],[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=],[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=],[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 +# 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 @@ + + + + + + + pam_usertype + 8 + Linux-PAM + + + + pam_usertype + check if the authenticated user is a system or regular account + + + + + + pam_usertype.so + flag + condition + + + + + + DESCRIPTION + + 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 + SYS_UID_MIN and SYS_UID_MAX + settings in /etc/login.defs. One use is to select + whether to load other modules based on this test. + + + + The module should be given only one condition as module argument. + Authentication will succeed only if the condition is met. + + + + + OPTIONS + + The following flags are supported: + + + + + + + + Evaluate conditions using the account of the user whose UID + the application is running under instead of the user being + authenticated. + + + + + + + + Log unknown users to the system log. + + + + + + + Available conditions are: + + + + + + + Succeed if the user is a system user. + + + + + + Succeed if the user is a regular user. + + + + + + + MODULE TYPES PROVIDED + + All module types (, , + and ) are provided. + + + + + RETURN VALUES + + + + PAM_SUCCESS + + + The condition was true. + + + + + + PAM_AUTH_ERR + + + The condition was false. + + + + + + PAM_SERVICE_ERR + + + A service error occurred or the arguments can't be + parsed correctly. + + + + + + PAM_USER_UNKNOWN + + + User was not found. + + + + + + + + + EXAMPLES + + Skip remaining modules if the user is a system user: + + +account sufficient pam_usertype.so issystem + + + + + SEE ALSO + + + login.defs5 + , + + pam8 + + + + + + AUTHOR + Pavel Březina <pbrezina@redhat.com> + + 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#define PAM_SM_AUTH +#define PAM_SM_ACCOUNT +#define PAM_SM_SESSION +#define PAM_SM_PASSWORD + +#include +#include +#include + +#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 + * - 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 @@ + + +--> +]> + +
+ + + + + <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" + href="pam_usertype.8.xml" xpointer='xpointer(//refnamediv[@id = "pam_usertype-name"]/*)'/> + + + + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
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