aboutsummaryrefslogtreecommitdiff
path: root/lib/libpam/modules
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpam/modules')
-rw-r--r--lib/libpam/modules/Makefile31
-rw-r--r--lib/libpam/modules/Makefile.inc10
-rw-r--r--lib/libpam/modules/modules.inc33
-rw-r--r--lib/libpam/modules/pam_chroot/Makefile5
-rw-r--r--lib/libpam/modules/pam_chroot/Makefile.depend16
-rw-r--r--lib/libpam/modules/pam_chroot/pam_chroot.892
-rw-r--r--lib/libpam/modules/pam_chroot/pam_chroot.c108
-rw-r--r--lib/libpam/modules/pam_deny/Makefile30
-rw-r--r--lib/libpam/modules/pam_deny/Makefile.depend15
-rw-r--r--lib/libpam/modules/pam_deny/pam_deny.878
-rw-r--r--lib/libpam/modules/pam_deny/pam_deny.c93
-rw-r--r--lib/libpam/modules/pam_echo/Makefile5
-rw-r--r--lib/libpam/modules/pam_echo/Makefile.depend16
-rw-r--r--lib/libpam/modules/pam_echo/pam_echo.891
-rw-r--r--lib/libpam/modules/pam_echo/pam_echo.c156
-rw-r--r--lib/libpam/modules/pam_exec/Makefile7
-rw-r--r--lib/libpam/modules/pam_exec/Makefile.depend16
-rw-r--r--lib/libpam/modules/pam_exec/pam_exec.8169
-rw-r--r--lib/libpam/modules/pam_exec/pam_exec.c698
-rw-r--r--lib/libpam/modules/pam_ftpusers/Makefile5
-rw-r--r--lib/libpam/modules/pam_ftpusers/Makefile.depend16
-rw-r--r--lib/libpam/modules/pam_ftpusers/pam_ftpusers.897
-rw-r--r--lib/libpam/modules/pam_ftpusers/pam_ftpusers.c115
-rw-r--r--lib/libpam/modules/pam_group/Makefile5
-rw-r--r--lib/libpam/modules/pam_group/Makefile.depend16
-rw-r--r--lib/libpam/modules/pam_group/pam_group.8100
-rw-r--r--lib/libpam/modules/pam_group/pam_group.c145
-rw-r--r--lib/libpam/modules/pam_guest/Makefile5
-rw-r--r--lib/libpam/modules/pam_guest/Makefile.depend16
-rw-r--r--lib/libpam/modules/pam_guest/pam_guest.896
-rw-r--r--lib/libpam/modules/pam_guest/pam_guest.c114
-rw-r--r--lib/libpam/modules/pam_krb5/Makefile92
-rw-r--r--lib/libpam/modules/pam_krb5/Makefile.depend19
-rw-r--r--lib/libpam/modules/pam_krb5/config.h412
-rw-r--r--lib/libpam/modules/pam_krb5/pam-krb5.81025
-rw-r--r--lib/libpam/modules/pam_krb5/pam_krb5.8235
-rw-r--r--lib/libpam/modules/pam_krb5/pam_krb5.c1076
-rw-r--r--lib/libpam/modules/pam_ksu/Makefile45
-rw-r--r--lib/libpam/modules/pam_ksu/Makefile.depend18
-rw-r--r--lib/libpam/modules/pam_ksu/pam_ksu.8120
-rw-r--r--lib/libpam/modules/pam_ksu/pam_ksu.c307
-rw-r--r--lib/libpam/modules/pam_lastlog/Makefile32
-rw-r--r--lib/libpam/modules/pam_lastlog/Makefile.depend16
-rw-r--r--lib/libpam/modules/pam_lastlog/pam_lastlog.899
-rw-r--r--lib/libpam/modules/pam_lastlog/pam_lastlog.c180
-rw-r--r--lib/libpam/modules/pam_login_access/Makefile32
-rw-r--r--lib/libpam/modules/pam_login_access/Makefile.depend16
-rw-r--r--lib/libpam/modules/pam_login_access/login.access.566
-rw-r--r--lib/libpam/modules/pam_login_access/login_access.c294
-rw-r--r--lib/libpam/modules/pam_login_access/pam_login_access.8120
-rw-r--r--lib/libpam/modules/pam_login_access/pam_login_access.c129
-rw-r--r--lib/libpam/modules/pam_login_access/pam_login_access.h50
-rw-r--r--lib/libpam/modules/pam_nologin/Makefile34
-rw-r--r--lib/libpam/modules/pam_nologin/Makefile.depend17
-rw-r--r--lib/libpam/modules/pam_nologin/pam_nologin.888
-rw-r--r--lib/libpam/modules/pam_nologin/pam_nologin.c126
-rw-r--r--lib/libpam/modules/pam_passwdqc/Makefile14
-rw-r--r--lib/libpam/modules/pam_passwdqc/Makefile.depend17
-rw-r--r--lib/libpam/modules/pam_passwdqc/pam_passwdqc.8265
-rw-r--r--lib/libpam/modules/pam_permit/Makefile30
-rw-r--r--lib/libpam/modules/pam_permit/Makefile.depend15
-rw-r--r--lib/libpam/modules/pam_permit/pam_permit.873
-rw-r--r--lib/libpam/modules/pam_permit/pam_permit.c93
-rw-r--r--lib/libpam/modules/pam_radius/Makefile33
-rw-r--r--lib/libpam/modules/pam_radius/Makefile.depend17
-rw-r--r--lib/libpam/modules/pam_radius/pam_radius.8148
-rw-r--r--lib/libpam/modules/pam_radius/pam_radius.c417
-rw-r--r--lib/libpam/modules/pam_rhosts/Makefile5
-rw-r--r--lib/libpam/modules/pam_rhosts/Makefile.depend16
-rw-r--r--lib/libpam/modules/pam_rhosts/pam_rhosts.893
-rw-r--r--lib/libpam/modules/pam_rhosts/pam_rhosts.c95
-rw-r--r--lib/libpam/modules/pam_rootok/Makefile30
-rw-r--r--lib/libpam/modules/pam_rootok/Makefile.depend15
-rw-r--r--lib/libpam/modules/pam_rootok/pam_rootok.873
-rw-r--r--lib/libpam/modules/pam_rootok/pam_rootok.c73
-rw-r--r--lib/libpam/modules/pam_securetty/Makefile32
-rw-r--r--lib/libpam/modules/pam_securetty/Makefile.depend16
-rw-r--r--lib/libpam/modules/pam_securetty/pam_securetty.890
-rw-r--r--lib/libpam/modules/pam_securetty/pam_securetty.c95
-rw-r--r--lib/libpam/modules/pam_self/Makefile32
-rw-r--r--lib/libpam/modules/pam_self/Makefile.depend15
-rw-r--r--lib/libpam/modules/pam_self/pam_self.894
-rw-r--r--lib/libpam/modules/pam_self/pam_self.c89
-rw-r--r--lib/libpam/modules/pam_ssh/Makefile18
-rw-r--r--lib/libpam/modules/pam_ssh/Makefile.depend18
-rw-r--r--lib/libpam/modules/pam_ssh/pam_ssh.8157
-rw-r--r--lib/libpam/modules/pam_ssh/pam_ssh.c442
-rw-r--r--lib/libpam/modules/pam_tacplus/Makefile32
-rw-r--r--lib/libpam/modules/pam_tacplus/Makefile.depend17
-rw-r--r--lib/libpam/modules/pam_tacplus/pam_tacplus.8125
-rw-r--r--lib/libpam/modules/pam_tacplus/pam_tacplus.c280
-rw-r--r--lib/libpam/modules/pam_unix/Makefile52
-rw-r--r--lib/libpam/modules/pam_unix/Makefile.depend19
-rw-r--r--lib/libpam/modules/pam_unix/Makefile.depend.options7
-rw-r--r--lib/libpam/modules/pam_unix/pam_unix.8215
-rw-r--r--lib/libpam/modules/pam_unix/pam_unix.c492
-rw-r--r--lib/libpam/modules/pam_xdg/Makefile5
-rw-r--r--lib/libpam/modules/pam_xdg/pam_xdg.864
-rw-r--r--lib/libpam/modules/pam_xdg/pam_xdg.c329
99 files changed, 11304 insertions, 0 deletions
diff --git a/lib/libpam/modules/Makefile b/lib/libpam/modules/Makefile
new file mode 100644
index 000000000000..0fd25117025c
--- /dev/null
+++ b/lib/libpam/modules/Makefile
@@ -0,0 +1,31 @@
+# Copyright 1998 Juniper Networks, Inc.
+# 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, this list of conditions and the following disclaimer.
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 "modules.inc"
+
+SUBDIR= ${MODULES}
+SUBDIR_PARALLEL=
+
+.include <bsd.subdir.mk>
diff --git a/lib/libpam/modules/Makefile.inc b/lib/libpam/modules/Makefile.inc
new file mode 100644
index 000000000000..2e66aec64f07
--- /dev/null
+++ b/lib/libpam/modules/Makefile.inc
@@ -0,0 +1,10 @@
+PAMDIR= ${SRCTOP}/contrib/openpam
+
+MK_INSTALLLIB= no
+
+CFLAGS+= -I${PAMDIR}/include -I${SRCTOP}/lib/libpam
+
+SHLIB_NAME?= ${LIB}.so.${SHLIB_MAJOR}
+LIBADD+= pam
+
+.include "../Makefile.inc"
diff --git a/lib/libpam/modules/modules.inc b/lib/libpam/modules/modules.inc
new file mode 100644
index 000000000000..f3ab65333f4f
--- /dev/null
+++ b/lib/libpam/modules/modules.inc
@@ -0,0 +1,33 @@
+
+.include <src.opts.mk>
+
+MODULES =
+MODULES += pam_chroot
+MODULES += pam_deny
+MODULES += pam_echo
+MODULES += pam_exec
+MODULES += pam_ftpusers
+MODULES += pam_group
+MODULES += pam_guest
+.if ${MK_KERBEROS} != "no"
+MODULES += pam_krb5
+MODULES += pam_ksu
+.endif
+MODULES += pam_lastlog
+MODULES += pam_login_access
+MODULES += pam_nologin
+MODULES += pam_passwdqc
+MODULES += pam_permit
+.if ${MK_RADIUS_SUPPORT} != "no"
+MODULES += pam_radius
+.endif
+MODULES += pam_rhosts
+MODULES += pam_rootok
+MODULES += pam_securetty
+MODULES += pam_self
+.if ${MK_OPENSSH} != "no"
+MODULES += pam_ssh
+.endif
+MODULES += pam_tacplus
+MODULES += pam_unix
+MODULES += pam_xdg \ No newline at end of file
diff --git a/lib/libpam/modules/pam_chroot/Makefile b/lib/libpam/modules/pam_chroot/Makefile
new file mode 100644
index 000000000000..206f8fa40a09
--- /dev/null
+++ b/lib/libpam/modules/pam_chroot/Makefile
@@ -0,0 +1,5 @@
+LIB= pam_chroot
+SRCS= pam_chroot.c
+MAN= pam_chroot.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_chroot/Makefile.depend b/lib/libpam/modules/pam_chroot/Makefile.depend
new file mode 100644
index 000000000000..0665960a2cd2
--- /dev/null
+++ b/lib/libpam/modules/pam_chroot/Makefile.depend
@@ -0,0 +1,16 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_chroot/pam_chroot.8 b/lib/libpam/modules/pam_chroot/pam_chroot.8
new file mode 100644
index 000000000000..1f614264ba8e
--- /dev/null
+++ b/lib/libpam/modules/pam_chroot/pam_chroot.8
@@ -0,0 +1,92 @@
+.\" Copyright (c) 2003 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS and NAI Labs, the Security Research Division of Network
+.\" Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+.\" ("CBOSS"), as part of the DARPA CHATS research program.
+.\"
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd February 10, 2003
+.Dt PAM_CHROOT 8
+.Os
+.Sh NAME
+.Nm pam_chroot
+.Nd Chroot PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_chroot
+.Op Ar arguments
+.Sh DESCRIPTION
+The chroot service module for PAM chroots users into either a
+predetermined directory or one derived from their home directory.
+If a user's home directory as specified in the
+.Vt passwd
+structure returned by
+.Xr getpwnam 3
+contains the string
+.Dq Li /./ ,
+the portion of the directory name to the left of that string is used
+as the chroot directory, and the portion to the right will be the
+current working directory inside the chroot tree.
+Otherwise, the directories specified by the
+.Cm dir
+and
+.Cm cwd
+options (see below) are used.
+.Bl -tag -width ".Cm also_root"
+.It Cm also_root
+Do not hold user ID 0 exempt from the chroot requirement.
+.It Cm always
+Report a failure if a chroot directory could not be derived from the
+user's home directory, and the
+.Cm dir
+option was not specified.
+.It Cm cwd Ns = Ns Ar directory
+Specify the directory to
+.Xr chdir 2
+into after a successful
+.Xr chroot 2
+call.
+.It Cm dir Ns = Ns Ar directory
+Specify the chroot directory to use if one could not be derived from
+the user's home directory.
+.El
+.Sh SEE ALSO
+.Xr pam 3 ,
+.Xr pam.conf 5
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_chroot/pam_chroot.c b/lib/libpam/modules/pam_chroot/pam_chroot.c
new file mode 100644
index 000000000000..346be34683c1
--- /dev/null
+++ b/lib/libpam/modules/pam_chroot/pam_chroot.c
@@ -0,0 +1,108 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS and
+ * NAI Labs, the Security Research Division of Network Associates, Inc.
+ * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
+ * DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/param.h>
+
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#define PAM_SM_SESSION
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/openpam.h>
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ const char *dir, *end, *cwd, *user;
+ struct passwd *pwd;
+ char buf[PATH_MAX];
+
+ if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS ||
+ user == NULL || (pwd = getpwnam(user)) == NULL)
+ return (PAM_SESSION_ERR);
+ if (pwd->pw_uid == 0 && !openpam_get_option(pamh, "also_root"))
+ return (PAM_SUCCESS);
+ if (pwd->pw_dir == NULL)
+ return (PAM_SESSION_ERR);
+ if ((end = strstr(pwd->pw_dir, "/./")) != NULL) {
+ if (snprintf(buf, sizeof(buf), "%.*s",
+ (int)(end - pwd->pw_dir), pwd->pw_dir) > (int)sizeof(buf)) {
+ openpam_log(PAM_LOG_ERROR,
+ "%s's home directory is too long", user);
+ return (PAM_SESSION_ERR);
+ }
+ dir = buf;
+ cwd = end + 2;
+ } else if ((dir = openpam_get_option(pamh, "dir")) != NULL) {
+ if ((cwd = openpam_get_option(pamh, "cwd")) == NULL)
+ cwd = "/";
+ } else {
+ if (openpam_get_option(pamh, "always")) {
+ openpam_log(PAM_LOG_ERROR,
+ "%s has no chroot directory", user);
+ return (PAM_SESSION_ERR);
+ }
+ return (PAM_SUCCESS);
+ }
+
+ openpam_log(PAM_LOG_DEBUG, "chrooting %s to %s", dir, user);
+
+ if (chroot(dir) == -1) {
+ openpam_log(PAM_LOG_ERROR, "chroot(): %m");
+ return (PAM_SESSION_ERR);
+ }
+ if (chdir(cwd) == -1) {
+ openpam_log(PAM_LOG_ERROR, "chdir(): %m");
+ return (PAM_SESSION_ERR);
+ }
+ pam_setenv(pamh, "HOME", cwd, 1);
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_chroot");
diff --git a/lib/libpam/modules/pam_deny/Makefile b/lib/libpam/modules/pam_deny/Makefile
new file mode 100644
index 000000000000..862d1859d0d6
--- /dev/null
+++ b/lib/libpam/modules/pam_deny/Makefile
@@ -0,0 +1,30 @@
+# Copyright 1999 Max Khon.
+# 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, this list of conditions and the following disclaimer.
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+#
+
+LIB= pam_deny
+SRCS= pam_deny.c
+MAN= pam_deny.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_deny/Makefile.depend b/lib/libpam/modules/pam_deny/Makefile.depend
new file mode 100644
index 000000000000..a8b8ddf9d074
--- /dev/null
+++ b/lib/libpam/modules/pam_deny/Makefile.depend
@@ -0,0 +1,15 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_deny/pam_deny.8 b/lib/libpam/modules/pam_deny/pam_deny.8
new file mode 100644
index 000000000000..5d70bde200d9
--- /dev/null
+++ b/lib/libpam/modules/pam_deny/pam_deny.8
@@ -0,0 +1,78 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd July 7, 2001
+.Dt PAM_DENY 8
+.Os
+.Sh NAME
+.Nm pam_deny
+.Nd Deny PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_deny
+.Op Ar options
+.Sh DESCRIPTION
+The Deny authentication service module for PAM,
+.Nm
+provides functionality for all the PAM categories:
+authentication,
+account management,
+session management and
+password management.
+In terms of the
+.Ar module-type
+parameter, these are the
+.Dq Li auth ,
+.Dq Li account ,
+.Dq Li session ,
+and
+.Dq Li password
+features.
+.Pp
+The Deny module
+will universally deny all requests.
+It is primarily of use during testing,
+and to
+.Dq null-out
+unwanted functionality.
+.Pp
+The following options may be passed to the module:
+.Bl -tag -width ".Cm no_warn"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include
+reasons why the user's
+authentication attempt was declined.
+.El
+.Sh SEE ALSO
+.Xr pam 3 ,
+.Xr syslog 3 ,
+.Xr pam.conf 5
diff --git a/lib/libpam/modules/pam_deny/pam_deny.c b/lib/libpam/modules/pam_deny/pam_deny.c
new file mode 100644
index 000000000000..a3edb213141a
--- /dev/null
+++ b/lib/libpam/modules/pam_deny/pam_deny.c
@@ -0,0 +1,93 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright 2001 Mark R V Murray
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/cdefs.h>
+#include <stddef.h>
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_SESSION
+#define PAM_SM_PASSWORD
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ const char *user;
+ int r;
+
+ if ((r = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS)
+ return (r);
+
+ return (PAM_AUTH_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_CRED_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_AUTH_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_chauthtok(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_AUTHTOK_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SESSION_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SESSION_ERR);
+}
+
+PAM_MODULE_ENTRY("pam_deny");
diff --git a/lib/libpam/modules/pam_echo/Makefile b/lib/libpam/modules/pam_echo/Makefile
new file mode 100644
index 000000000000..532d0a51b58e
--- /dev/null
+++ b/lib/libpam/modules/pam_echo/Makefile
@@ -0,0 +1,5 @@
+LIB= pam_echo
+SRCS= pam_echo.c
+MAN= pam_echo.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_echo/Makefile.depend b/lib/libpam/modules/pam_echo/Makefile.depend
new file mode 100644
index 000000000000..0665960a2cd2
--- /dev/null
+++ b/lib/libpam/modules/pam_echo/Makefile.depend
@@ -0,0 +1,16 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_echo/pam_echo.8 b/lib/libpam/modules/pam_echo/pam_echo.8
new file mode 100644
index 000000000000..19c083917bbf
--- /dev/null
+++ b/lib/libpam/modules/pam_echo/pam_echo.8
@@ -0,0 +1,91 @@
+.\" Copyright (c) 2001,2003 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS and NAI Labs, the Security Research Division of Network
+.\" Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+.\" ("CBOSS"), as part of the DARPA CHATS research program.
+.\"
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd February 6, 2003
+.Dt PAM_ECHO 8
+.Os
+.Sh NAME
+.Nm pam_echo
+.Nd Echo PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_echo
+.Op Ar arguments
+.Sh DESCRIPTION
+The echo service module for PAM displays its arguments to the user,
+separated by spaces, using the current conversation function.
+.Pp
+If the
+.Cm %
+character occurs anywhere in the arguments to
+.Nm ,
+it is assumed to introduce one of the following escape sequences:
+.Bl -tag -width 4n
+.It Cm %H
+The name of the host on which the client runs
+.Pq Dv PAM_RHOST .
+.\".It Cm %h
+.\"The name of the host on which the server runs.
+.It Cm %s
+The current service name
+.Pq Dv PAM_SERVICE .
+.It Cm %t
+The name of the controlling tty
+.Pq Dv PAM_TTY .
+.It Cm \&%U
+The applicant's user name
+.Pq Dv PAM_RUSER .
+.It Cm %u
+The target account's user name
+.Pq Dv PAM_USER .
+.El
+.Pp
+Any other two-character sequence beginning with
+.Cm %
+expands to the character following the
+.Cm %
+character.
+.Sh SEE ALSO
+.Xr pam 3 ,
+.Xr pam.conf 5
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_echo/pam_echo.c b/lib/libpam/modules/pam_echo/pam_echo.c
new file mode 100644
index 000000000000..73f1c11eca61
--- /dev/null
+++ b/lib/libpam/modules/pam_echo/pam_echo.c
@@ -0,0 +1,156 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2001,2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS and
+ * NAI Labs, the Security Research Division of Network Associates, Inc.
+ * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
+ * DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/cdefs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/openpam.h>
+
+static int
+_pam_echo(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+ char msg[PAM_MAX_MSG_SIZE];
+ const void *str;
+ const char *p, *q;
+ int err, i, item;
+ size_t len;
+
+ if (flags & PAM_SILENT)
+ return (PAM_SUCCESS);
+ for (i = 0, len = 0; i < argc && len < sizeof(msg) - 1; ++i) {
+ if (i > 0)
+ msg[len++] = ' ';
+ for (p = argv[i]; *p != '\0' && len < sizeof(msg) - 1; ++p) {
+ if (*p != '%' || p[1] == '\0') {
+ msg[len++] = *p;
+ continue;
+ }
+ switch (*++p) {
+ case 'H':
+ item = PAM_RHOST;
+ break;
+ case 'h':
+ /* not implemented */
+ item = -1;
+ break;
+ case 's':
+ item = PAM_SERVICE;
+ break;
+ case 't':
+ item = PAM_TTY;
+ break;
+ case 'U':
+ item = PAM_RUSER;
+ break;
+ case 'u':
+ item = PAM_USER;
+ break;
+ default:
+ item = -1;
+ msg[len++] = *p;
+ break;
+ }
+ if (item == -1)
+ continue;
+ err = pam_get_item(pamh, item, &str);
+ if (err != PAM_SUCCESS)
+ return (err);
+ if (str == NULL)
+ str = "(null)";
+ for (q = str; *q != '\0' && len < sizeof(msg) - 1; ++q)
+ msg[len++] = *q;
+ }
+ }
+ msg[len] = '\0';
+ return (pam_info(pamh, "%s", msg));
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ return (_pam_echo(pamh, flags, argc, argv));
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ return (_pam_echo(pamh, flags, argc, argv));
+}
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ return (_pam_echo(pamh, flags, argc, argv));
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ return (_pam_echo(pamh, flags, argc, argv));
+}
+
+PAM_EXTERN int
+pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ if (flags & PAM_PRELIM_CHECK)
+ return (PAM_SUCCESS);
+ return (_pam_echo(pamh, flags, argc, argv));
+}
+
+PAM_MODULE_ENTRY("pam_echo");
diff --git a/lib/libpam/modules/pam_exec/Makefile b/lib/libpam/modules/pam_exec/Makefile
new file mode 100644
index 000000000000..c2327a2860cd
--- /dev/null
+++ b/lib/libpam/modules/pam_exec/Makefile
@@ -0,0 +1,7 @@
+LIB= pam_exec
+SRCS= pam_exec.c
+MAN= pam_exec.8
+
+WARNS?= 1
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_exec/Makefile.depend b/lib/libpam/modules/pam_exec/Makefile.depend
new file mode 100644
index 000000000000..0665960a2cd2
--- /dev/null
+++ b/lib/libpam/modules/pam_exec/Makefile.depend
@@ -0,0 +1,16 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_exec/pam_exec.8 b/lib/libpam/modules/pam_exec/pam_exec.8
new file mode 100644
index 000000000000..be5666003557
--- /dev/null
+++ b/lib/libpam/modules/pam_exec/pam_exec.8
@@ -0,0 +1,169 @@
+.\" Copyright (c) 2001,2003 Networks Associates Technology, Inc.
+.\" Copyright (c) 2017-2019 Dag-Erling Smørgrav
+.\" Copyright (c) 2018 Thomas Munro
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS and NAI Labs, the Security Research Division of Network
+.\" Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+.\" ("CBOSS"), as part of the DARPA CHATS research program.
+.\"
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd May 24, 2019
+.Dt PAM_EXEC 8
+.Os
+.Sh NAME
+.Nm pam_exec
+.Nd Exec PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_exec
+.Op Ar arguments
+.Sh DESCRIPTION
+The exec service module for PAM executes the program designated by
+its first argument if no options are specified, with its remaining
+arguments as command-line arguments.
+If options are specified, the program and its arguments follow the last
+option or
+.Cm --
+if the program name conflicts with an option name.
+.Pp
+The following options may be passed before the program and its
+arguments:
+.Bl -tag -width indent
+.It Cm capture_stderr
+Capture text printed by the program to its standard error stream and
+pass it to the conversation function as error messages.
+No attempt is made at buffering the text, so results may vary.
+.It Cm capture_stdout
+Capture text printed by the program to its standard output stream and
+pass it to the conversation function as informational messages.
+No attempt is made at buffering the text, so results may vary.
+.It Cm debug
+Ignored for compatibility reasons.
+.It Cm no_warn
+Ignored for compatibility reasons.
+.It Cm return_prog_exit_status
+Use the program exit status as the return code of the pam_sm_* function.
+It must be a valid return value for this function.
+.It Cm expose_authtok
+Write the authentication token to the program's standard input stream,
+followed by a NUL character.
+Ignored for
+.Fn pam_sm_setcred .
+.It Cm use_first_pass
+If
+.Cm expose_authtok
+was specified, do not prompt for an authentication token if one is not
+already available.
+.It Cm --
+Stop options parsing;
+program and its arguments follow.
+.El
+.Pp
+The child's environment is set to the current PAM environment list,
+as returned by
+.Xr pam_getenvlist 3 .
+In addition, the following PAM items are exported as environment
+variables:
+.Ev PAM_RHOST ,
+.Ev PAM_RUSER ,
+.Ev PAM_SERVICE ,
+.Ev PAM_SM_FUNC ,
+.Ev PAM_TTY
+and
+.Ev PAM_USER .
+.Pp
+The
+.Ev PAM_SM_FUNC
+variable contains the name of the PAM service module function being
+called.
+It may be:
+.Bl -dash -offset indent -compact
+.It
+pam_sm_acct_mgmt
+.It
+pam_sm_authenticate
+.It
+pam_sm_chauthtok
+.It
+pam_sm_close_session
+.It
+pam_sm_open_session
+.It
+pam_sm_setcred
+.El
+.Pp
+If
+.Cm return_prog_exit_status
+is not set (default), the
+.Ev PAM_SM_FUNC
+function returns
+.Er PAM_SUCCESS
+if the program exit status is 0,
+.Er PAM_PERM_DENIED
+otherwise.
+.Pp
+If
+.Cm return_prog_exit_status
+is set, the program exit status is used.
+It should be
+.Er PAM_SUCCESS
+or one of the error codes allowed by the calling
+.Ev PAM_SM_FUNC
+function.
+The valid codes are documented in each function man page.
+If the exit status is not a valid return code,
+.Er PAM_SERVICE_ERR
+is returned.
+Each valid codes numerical value is available as an environment variable
+(eg.\&
+.Ev PAM_SUCESS ,
+.Ev PAM_USER_UNKNOWN ,
+etc).
+This is useful in shell scripts for instance.
+.Sh SEE ALSO
+.Xr pam 3 ,
+.Xr pam_get_item 3 ,
+.Xr pam_sm_acct_mgmt 3 ,
+.Xr pam_sm_authenticate 3 ,
+.Xr pam_sm_chauthtok 3 ,
+.Xr pam_sm_close_session 3 ,
+.Xr pam_sm_open_session 3 ,
+.Xr pam_sm_setcred 3 ,
+.Xr pam.conf 5
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_exec/pam_exec.c b/lib/libpam/modules/pam_exec/pam_exec.c
new file mode 100644
index 000000000000..800a791f04a1
--- /dev/null
+++ b/lib/libpam/modules/pam_exec/pam_exec.c
@@ -0,0 +1,698 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2001,2003 Networks Associates Technology, Inc.
+ * Copyright (c) 2017-2019 Dag-Erling Smørgrav
+ * Copyright (c) 2018 Thomas Munro
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS and
+ * NAI Labs, the Security Research Division of Network Associates, Inc.
+ * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
+ * DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/types.h>
+#include <sys/poll.h>
+#include <sys/procdesc.h>
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/openpam.h>
+
+#define PAM_ITEM_ENV(n) { (n), #n }
+static struct {
+ int item;
+ const char *name;
+} pam_item_env[] = {
+ PAM_ITEM_ENV(PAM_SERVICE),
+ PAM_ITEM_ENV(PAM_USER),
+ PAM_ITEM_ENV(PAM_TTY),
+ PAM_ITEM_ENV(PAM_RHOST),
+ PAM_ITEM_ENV(PAM_RUSER),
+};
+#define NUM_PAM_ITEM_ENV (sizeof(pam_item_env) / sizeof(pam_item_env[0]))
+
+#define PAM_ERR_ENV_X(str, num) str "=" #num
+#define PAM_ERR_ENV(pam_err) PAM_ERR_ENV_X(#pam_err, pam_err)
+static const char *pam_err_env[] = {
+ PAM_ERR_ENV(PAM_SUCCESS),
+ PAM_ERR_ENV(PAM_OPEN_ERR),
+ PAM_ERR_ENV(PAM_SYMBOL_ERR),
+ PAM_ERR_ENV(PAM_SERVICE_ERR),
+ PAM_ERR_ENV(PAM_SYSTEM_ERR),
+ PAM_ERR_ENV(PAM_BUF_ERR),
+ PAM_ERR_ENV(PAM_CONV_ERR),
+ PAM_ERR_ENV(PAM_PERM_DENIED),
+ PAM_ERR_ENV(PAM_MAXTRIES),
+ PAM_ERR_ENV(PAM_AUTH_ERR),
+ PAM_ERR_ENV(PAM_NEW_AUTHTOK_REQD),
+ PAM_ERR_ENV(PAM_CRED_INSUFFICIENT),
+ PAM_ERR_ENV(PAM_AUTHINFO_UNAVAIL),
+ PAM_ERR_ENV(PAM_USER_UNKNOWN),
+ PAM_ERR_ENV(PAM_CRED_UNAVAIL),
+ PAM_ERR_ENV(PAM_CRED_EXPIRED),
+ PAM_ERR_ENV(PAM_CRED_ERR),
+ PAM_ERR_ENV(PAM_ACCT_EXPIRED),
+ PAM_ERR_ENV(PAM_AUTHTOK_EXPIRED),
+ PAM_ERR_ENV(PAM_SESSION_ERR),
+ PAM_ERR_ENV(PAM_AUTHTOK_ERR),
+ PAM_ERR_ENV(PAM_AUTHTOK_RECOVERY_ERR),
+ PAM_ERR_ENV(PAM_AUTHTOK_LOCK_BUSY),
+ PAM_ERR_ENV(PAM_AUTHTOK_DISABLE_AGING),
+ PAM_ERR_ENV(PAM_NO_MODULE_DATA),
+ PAM_ERR_ENV(PAM_IGNORE),
+ PAM_ERR_ENV(PAM_ABORT),
+ PAM_ERR_ENV(PAM_TRY_AGAIN),
+ PAM_ERR_ENV(PAM_MODULE_UNKNOWN),
+ PAM_ERR_ENV(PAM_DOMAIN_UNKNOWN),
+ PAM_ERR_ENV(PAM_NUM_ERR),
+};
+#define NUM_PAM_ERR_ENV (sizeof(pam_err_env) / sizeof(pam_err_env[0]))
+
+struct pe_opts {
+ int return_prog_exit_status;
+ int capture_stdout;
+ int capture_stderr;
+ int expose_authtok;
+ int use_first_pass;
+};
+
+static int
+parse_options(const char *func, int *argc, const char **argv[],
+ struct pe_opts *options)
+{
+ int i;
+
+ /*
+ * Parse options:
+ * return_prog_exit_status:
+ * use the program exit status as the return code of pam_exec
+ * --:
+ * stop options parsing; what follows is the command to execute
+ */
+ memset(options, 0, sizeof(*options));
+
+ for (i = 0; i < *argc; ++i) {
+ if (strcmp((*argv)[i], "debug") == 0 ||
+ strcmp((*argv)[i], "no_warn") == 0) {
+ /* ignore */
+ } else if (strcmp((*argv)[i], "capture_stdout") == 0) {
+ options->capture_stdout = 1;
+ } else if (strcmp((*argv)[i], "capture_stderr") == 0) {
+ options->capture_stderr = 1;
+ } else if (strcmp((*argv)[i], "return_prog_exit_status") == 0) {
+ options->return_prog_exit_status = 1;
+ } else if (strcmp((*argv)[i], "expose_authtok") == 0) {
+ options->expose_authtok = 1;
+ } else if (strcmp((*argv)[i], "use_first_pass") == 0) {
+ options->use_first_pass = 1;
+ } else {
+ if (strcmp((*argv)[i], "--") == 0) {
+ (*argc)--;
+ (*argv)++;
+ }
+ break;
+ }
+ openpam_log(PAM_LOG_DEBUG, "%s: option \"%s\" enabled",
+ func, (*argv)[i]);
+ }
+
+ (*argc) -= i;
+ (*argv) += i;
+
+ return (0);
+}
+
+static int
+_pam_exec(pam_handle_t *pamh,
+ const char *func, int flags __unused, int argc, const char *argv[],
+ struct pe_opts *options)
+{
+ char buf[PAM_MAX_MSG_SIZE];
+ struct pollfd pfd[4];
+ const void *item;
+ char **envlist, *envstr, *resp, **tmp;
+ ssize_t rlen, wlen;
+ int envlen, extralen, i;
+ int pam_err, serrno, status;
+ int chin[2], chout[2], cherr[2], pd;
+ nfds_t nfds, nreadfds;
+ pid_t pid;
+ const char *authtok;
+ size_t authtok_size;
+ int rc;
+
+ pd = -1;
+ pid = 0;
+ chin[0] = chin[1] = chout[0] = chout[1] = cherr[0] = cherr[1] = -1;
+ envlist = NULL;
+
+#define OUT(ret) do { pam_err = (ret); goto out; } while (0)
+
+ /* Check there's a program name left after parsing options. */
+ if (argc < 1) {
+ openpam_log(PAM_LOG_ERROR, "%s: No program specified: aborting",
+ func);
+ OUT(PAM_SERVICE_ERR);
+ }
+
+ /*
+ * Set up the child's environment list. It consists of the PAM
+ * environment, a few hand-picked PAM items, the name of the
+ * service function, and if return_prog_exit_status is set, the
+ * numerical values of all PAM error codes.
+ */
+
+ /* compute the final size of the environment. */
+ envlist = pam_getenvlist(pamh);
+ for (envlen = 0; envlist[envlen] != NULL; ++envlen)
+ /* nothing */ ;
+ extralen = NUM_PAM_ITEM_ENV + 1;
+ if (options->return_prog_exit_status)
+ extralen += NUM_PAM_ERR_ENV;
+ tmp = reallocarray(envlist, envlen + extralen + 1, sizeof(*envlist));
+ openpam_log(PAM_LOG_DEBUG, "envlen = %d extralen = %d tmp = %p",
+ envlen, extralen, tmp);
+ if (tmp == NULL)
+ OUT(PAM_BUF_ERR);
+ envlist = tmp;
+ extralen += envlen;
+
+ /* copy selected PAM items to the environment */
+ for (i = 0; i < NUM_PAM_ITEM_ENV; ++i) {
+ pam_err = pam_get_item(pamh, pam_item_env[i].item, &item);
+ if (pam_err != PAM_SUCCESS || item == NULL)
+ continue;
+ if (asprintf(&envstr, "%s=%s", pam_item_env[i].name,
+ (const char *)item) < 0)
+ OUT(PAM_BUF_ERR);
+ envlist[envlen++] = envstr;
+ envlist[envlen] = NULL;
+ openpam_log(PAM_LOG_DEBUG, "setenv %s", envstr);
+ }
+
+ /* add the name of the service function to the environment */
+ if (asprintf(&envstr, "PAM_SM_FUNC=%s", func) < 0)
+ OUT(PAM_BUF_ERR);
+ envlist[envlen++] = envstr;
+ envlist[envlen] = NULL;
+
+ /* add the PAM error codes to the environment. */
+ if (options->return_prog_exit_status) {
+ for (i = 0; i < (int)NUM_PAM_ERR_ENV; ++i) {
+ if ((envstr = strdup(pam_err_env[i])) == NULL)
+ OUT(PAM_BUF_ERR);
+ envlist[envlen++] = envstr;
+ envlist[envlen] = NULL;
+ }
+ }
+
+ openpam_log(PAM_LOG_DEBUG, "envlen = %d extralen = %d envlist = %p",
+ envlen, extralen, envlist);
+
+ /* set up pipe and get authtok if requested */
+ if (options->expose_authtok) {
+ if (pipe(chin) != 0) {
+ openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func);
+ OUT(PAM_SYSTEM_ERR);
+ }
+ if (fcntl(chin[1], F_SETFL, O_NONBLOCK)) {
+ openpam_log(PAM_LOG_ERROR, "%s: fcntl(): %m", func);
+ OUT(PAM_SYSTEM_ERR);
+ }
+ if (options->use_first_pass ||
+ strcmp(func, "pam_sm_setcred") == 0) {
+ /* don't prompt, only expose existing token */
+ rc = pam_get_item(pamh, PAM_AUTHTOK, &item);
+ authtok = item;
+ if (authtok == NULL && rc == PAM_SUCCESS) {
+ openpam_log(PAM_LOG_ERROR,
+ "%s: pam_get_authtok(): %s",
+ func, "authentication token not available");
+ OUT(PAM_SYSTEM_ERR);
+ }
+
+ } else {
+ rc = pam_get_authtok(pamh, PAM_AUTHTOK, &authtok, NULL);
+ }
+ if (rc == PAM_SUCCESS) {
+ /* We include the trailing null terminator. */
+ authtok_size = strlen(authtok) + 1;
+ } else {
+ openpam_log(PAM_LOG_ERROR, "%s: pam_get_authtok(): %s",
+ func, pam_strerror(pamh, rc));
+ OUT(PAM_SYSTEM_ERR);
+ }
+ }
+ /* set up pipes if capture was requested */
+ if (options->capture_stdout) {
+ if (pipe(chout) != 0) {
+ openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func);
+ OUT(PAM_SYSTEM_ERR);
+ }
+ if (fcntl(chout[0], F_SETFL, O_NONBLOCK) != 0) {
+ openpam_log(PAM_LOG_ERROR, "%s: fcntl(): %m", func);
+ OUT(PAM_SYSTEM_ERR);
+ }
+ } else {
+ if ((chout[1] = open("/dev/null", O_RDWR)) < 0) {
+ openpam_log(PAM_LOG_ERROR, "%s: /dev/null: %m", func);
+ OUT(PAM_SYSTEM_ERR);
+ }
+ }
+ if (options->capture_stderr) {
+ if (pipe(cherr) != 0) {
+ openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func);
+ OUT(PAM_SYSTEM_ERR);
+ }
+ if (fcntl(cherr[0], F_SETFL, O_NONBLOCK) != 0) {
+ openpam_log(PAM_LOG_ERROR, "%s: fcntl(): %m", func);
+ OUT(PAM_SYSTEM_ERR);
+ }
+ } else {
+ if ((cherr[1] = open("/dev/null", O_RDWR)) < 0) {
+ openpam_log(PAM_LOG_ERROR, "%s: /dev/null: %m", func);
+ OUT(PAM_SYSTEM_ERR);
+ }
+ }
+
+ if ((pid = pdfork(&pd, 0)) == 0) {
+ /* child */
+ if ((chin[1] >= 0 && close(chin[1]) != 0) ||
+ (chout[0] >= 0 && close(chout[0]) != 0) ||
+ (cherr[0] >= 0 && close(cherr[0]) != 0)) {
+ openpam_log(PAM_LOG_ERROR, "%s: close(): %m", func);
+ } else if (chin[0] >= 0 &&
+ dup2(chin[0], STDIN_FILENO) != STDIN_FILENO) {
+ openpam_log(PAM_LOG_ERROR, "%s: dup2(): %m", func);
+ } else if (dup2(chout[1], STDOUT_FILENO) != STDOUT_FILENO ||
+ dup2(cherr[1], STDERR_FILENO) != STDERR_FILENO) {
+ openpam_log(PAM_LOG_ERROR, "%s: dup2(): %m", func);
+ } else {
+ execve(argv[0], (char * const *)argv,
+ (char * const *)envlist);
+ openpam_log(PAM_LOG_ERROR, "%s: execve(%s): %m",
+ func, argv[0]);
+ }
+ _exit(1);
+ }
+ /* parent */
+ if (pid == -1) {
+ openpam_log(PAM_LOG_ERROR, "%s: pdfork(): %m", func);
+ OUT(PAM_SYSTEM_ERR);
+ }
+ /* use poll() to watch the process and stdin / stdout / stderr */
+ if (chin[0] >= 0)
+ close(chin[0]);
+ if (chout[1] >= 0)
+ close(chout[1]);
+ if (cherr[1] >= 0)
+ close(cherr[1]);
+ memset(pfd, 0, sizeof pfd);
+ pfd[0].fd = pd;
+ pfd[0].events = POLLHUP;
+ nfds = 1;
+ nreadfds = 0;
+ if (options->capture_stdout) {
+ pfd[nfds].fd = chout[0];
+ pfd[nfds].events = POLLIN|POLLERR|POLLHUP;
+ nfds++;
+ nreadfds++;
+ }
+ if (options->capture_stderr) {
+ pfd[nfds].fd = cherr[0];
+ pfd[nfds].events = POLLIN|POLLERR|POLLHUP;
+ nfds++;
+ nreadfds++;
+ }
+ if (options->expose_authtok) {
+ pfd[nfds].fd = chin[1];
+ pfd[nfds].events = POLLOUT|POLLERR|POLLHUP;
+ nfds++;
+ }
+
+ /* loop until the process exits */
+ do {
+ if (poll(pfd, nfds, INFTIM) < 0) {
+ openpam_log(PAM_LOG_ERROR, "%s: poll(): %m", func);
+ OUT(PAM_SYSTEM_ERR);
+ }
+ /* are the stderr / stdout pipes ready for reading? */
+ for (i = 1; i < 1 + nreadfds; ++i) {
+ if ((pfd[i].revents & POLLIN) == 0)
+ continue;
+ if ((rlen = read(pfd[i].fd, buf, sizeof(buf) - 1)) < 0) {
+ openpam_log(PAM_LOG_ERROR, "%s: read(): %m",
+ func);
+ OUT(PAM_SYSTEM_ERR);
+ } else if (rlen == 0) {
+ continue;
+ }
+ buf[rlen] = '\0';
+ (void)pam_prompt(pamh, pfd[i].fd == chout[0] ?
+ PAM_TEXT_INFO : PAM_ERROR_MSG, &resp, "%s", buf);
+ }
+ /* is the stdin pipe ready for writing? */
+ if (options->expose_authtok && authtok_size > 0 &&
+ (pfd[nfds - 1].revents & POLLOUT) != 0) {
+ if ((wlen = write(chin[1], authtok, authtok_size)) < 0) {
+ if (errno == EAGAIN)
+ continue;
+ openpam_log(PAM_LOG_ERROR, "%s: write(): %m",
+ func);
+ OUT(PAM_SYSTEM_ERR);
+ } else {
+ authtok += wlen;
+ authtok_size -= wlen;
+ if (authtok_size == 0) {
+ /* finished writing; close and forget the pipe */
+ close(chin[1]);
+ chin[1] = -1;
+ nfds--;
+ }
+ }
+ }
+ } while (pfd[0].revents == 0);
+
+ /* the child process has exited */
+ while (waitpid(pid, &status, 0) == -1) {
+ if (errno == EINTR)
+ continue;
+ openpam_log(PAM_LOG_ERROR, "%s: waitpid(): %m", func);
+ OUT(PAM_SYSTEM_ERR);
+ }
+
+ /* check exit code */
+ if (WIFSIGNALED(status)) {
+ openpam_log(PAM_LOG_ERROR, "%s: %s caught signal %d%s",
+ func, argv[0], WTERMSIG(status),
+ WCOREDUMP(status) ? " (core dumped)" : "");
+ OUT(PAM_SERVICE_ERR);
+ }
+ if (!WIFEXITED(status)) {
+ openpam_log(PAM_LOG_ERROR, "%s: unknown status 0x%x",
+ func, status);
+ OUT(PAM_SERVICE_ERR);
+ }
+
+ if (options->return_prog_exit_status) {
+ openpam_log(PAM_LOG_DEBUG,
+ "%s: Use program exit status as return value: %d",
+ func, WEXITSTATUS(status));
+ OUT(WEXITSTATUS(status));
+ } else {
+ OUT(WEXITSTATUS(status) == 0 ? PAM_SUCCESS : PAM_PERM_DENIED);
+ }
+ /* unreachable */
+out:
+ serrno = errno;
+ if (pd >= 0)
+ close(pd);
+ if (chin[0] >= 0)
+ close(chin[0]);
+ if (chin[1] >= 0)
+ close(chin[1]);
+ if (chout[0] >= 0)
+ close(chout[0]);
+ if (chout[1] >= 0)
+ close(chout[1]);
+ if (cherr[0] >= 0)
+ close(cherr[0]);
+ if (cherr[0] >= 0)
+ close(cherr[1]);
+ if (envlist != NULL)
+ openpam_free_envlist(envlist);
+ errno = serrno;
+ return (pam_err);
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+ int ret;
+ struct pe_opts options;
+
+ ret = parse_options(__func__, &argc, &argv, &options);
+ if (ret != 0)
+ return (PAM_SERVICE_ERR);
+
+ ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
+
+ /*
+ * We must check that the program returned a valid code for this
+ * function.
+ */
+ switch (ret) {
+ case PAM_SUCCESS:
+ case PAM_ABORT:
+ case PAM_AUTHINFO_UNAVAIL:
+ case PAM_AUTH_ERR:
+ case PAM_BUF_ERR:
+ case PAM_CONV_ERR:
+ case PAM_CRED_INSUFFICIENT:
+ case PAM_IGNORE:
+ case PAM_MAXTRIES:
+ case PAM_PERM_DENIED:
+ case PAM_SERVICE_ERR:
+ case PAM_SYSTEM_ERR:
+ case PAM_USER_UNKNOWN:
+ break;
+ default:
+ openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
+ argv[0], ret);
+ ret = PAM_SERVICE_ERR;
+ }
+
+ return (ret);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+ int ret;
+ struct pe_opts options;
+
+ ret = parse_options(__func__, &argc, &argv, &options);
+ if (ret != 0)
+ return (PAM_SERVICE_ERR);
+
+ ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
+
+ /*
+ * We must check that the program returned a valid code for this
+ * function.
+ */
+ switch (ret) {
+ case PAM_SUCCESS:
+ case PAM_ABORT:
+ case PAM_BUF_ERR:
+ case PAM_CONV_ERR:
+ case PAM_CRED_ERR:
+ case PAM_CRED_EXPIRED:
+ case PAM_CRED_UNAVAIL:
+ case PAM_IGNORE:
+ case PAM_PERM_DENIED:
+ case PAM_SERVICE_ERR:
+ case PAM_SYSTEM_ERR:
+ case PAM_USER_UNKNOWN:
+ break;
+ default:
+ openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
+ argv[0], ret);
+ ret = PAM_SERVICE_ERR;
+ }
+
+ return (ret);
+}
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+ int ret;
+ struct pe_opts options;
+
+ ret = parse_options(__func__, &argc, &argv, &options);
+ if (ret != 0)
+ return (PAM_SERVICE_ERR);
+
+ ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
+
+ /*
+ * We must check that the program returned a valid code for this
+ * function.
+ */
+ switch (ret) {
+ case PAM_SUCCESS:
+ case PAM_ABORT:
+ case PAM_ACCT_EXPIRED:
+ case PAM_AUTH_ERR:
+ case PAM_BUF_ERR:
+ case PAM_CONV_ERR:
+ case PAM_IGNORE:
+ case PAM_NEW_AUTHTOK_REQD:
+ case PAM_PERM_DENIED:
+ case PAM_SERVICE_ERR:
+ case PAM_SYSTEM_ERR:
+ case PAM_USER_UNKNOWN:
+ break;
+ default:
+ openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
+ argv[0], ret);
+ ret = PAM_SERVICE_ERR;
+ }
+
+ return (ret);
+}
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+ int ret;
+ struct pe_opts options;
+
+ ret = parse_options(__func__, &argc, &argv, &options);
+ if (ret != 0)
+ return (PAM_SERVICE_ERR);
+
+ ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
+
+ /*
+ * We must check that the program returned a valid code for this
+ * function.
+ */
+ switch (ret) {
+ case PAM_SUCCESS:
+ case PAM_ABORT:
+ case PAM_BUF_ERR:
+ case PAM_CONV_ERR:
+ case PAM_IGNORE:
+ case PAM_PERM_DENIED:
+ case PAM_SERVICE_ERR:
+ case PAM_SESSION_ERR:
+ case PAM_SYSTEM_ERR:
+ break;
+ default:
+ openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
+ argv[0], ret);
+ ret = PAM_SERVICE_ERR;
+ }
+
+ return (ret);
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+ int ret;
+ struct pe_opts options;
+
+ ret = parse_options(__func__, &argc, &argv, &options);
+ if (ret != 0)
+ return (PAM_SERVICE_ERR);
+
+ ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
+
+ /*
+ * We must check that the program returned a valid code for this
+ * function.
+ */
+ switch (ret) {
+ case PAM_SUCCESS:
+ case PAM_ABORT:
+ case PAM_BUF_ERR:
+ case PAM_CONV_ERR:
+ case PAM_IGNORE:
+ case PAM_PERM_DENIED:
+ case PAM_SERVICE_ERR:
+ case PAM_SESSION_ERR:
+ case PAM_SYSTEM_ERR:
+ break;
+ default:
+ openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
+ argv[0], ret);
+ ret = PAM_SERVICE_ERR;
+ }
+
+ return (ret);
+}
+
+PAM_EXTERN int
+pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+ int ret;
+ struct pe_opts options;
+
+ ret = parse_options(__func__, &argc, &argv, &options);
+ if (ret != 0)
+ return (PAM_SERVICE_ERR);
+
+ ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
+
+ /*
+ * We must check that the program returned a valid code for this
+ * function.
+ */
+ switch (ret) {
+ case PAM_SUCCESS:
+ case PAM_ABORT:
+ case PAM_AUTHTOK_DISABLE_AGING:
+ case PAM_AUTHTOK_ERR:
+ case PAM_AUTHTOK_LOCK_BUSY:
+ case PAM_AUTHTOK_RECOVERY_ERR:
+ case PAM_BUF_ERR:
+ case PAM_CONV_ERR:
+ case PAM_IGNORE:
+ case PAM_PERM_DENIED:
+ case PAM_SERVICE_ERR:
+ case PAM_SYSTEM_ERR:
+ case PAM_TRY_AGAIN:
+ break;
+ default:
+ openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
+ argv[0], ret);
+ ret = PAM_SERVICE_ERR;
+ }
+
+ return (ret);
+}
+
+PAM_MODULE_ENTRY("pam_exec");
diff --git a/lib/libpam/modules/pam_ftpusers/Makefile b/lib/libpam/modules/pam_ftpusers/Makefile
new file mode 100644
index 000000000000..07d37c8b17a8
--- /dev/null
+++ b/lib/libpam/modules/pam_ftpusers/Makefile
@@ -0,0 +1,5 @@
+LIB= pam_ftpusers
+SRCS= pam_ftpusers.c
+MAN= pam_ftpusers.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_ftpusers/Makefile.depend b/lib/libpam/modules/pam_ftpusers/Makefile.depend
new file mode 100644
index 000000000000..0665960a2cd2
--- /dev/null
+++ b/lib/libpam/modules/pam_ftpusers/Makefile.depend
@@ -0,0 +1,16 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_ftpusers/pam_ftpusers.8 b/lib/libpam/modules/pam_ftpusers/pam_ftpusers.8
new file mode 100644
index 000000000000..d5a0f0f1fd2e
--- /dev/null
+++ b/lib/libpam/modules/pam_ftpusers/pam_ftpusers.8
@@ -0,0 +1,97 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2002 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS and NAI Labs, the Security Research Division of Network
+.\" Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+.\" ("CBOSS"), as part of the DARPA CHATS research program.
+.\"
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd April 17, 2002
+.Dt PAM_FTPUSERS 8
+.Os
+.Sh NAME
+.Nm pam_ftpusers
+.Nd ftpusers PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_ftpusers
+.Op Ar options
+.Sh DESCRIPTION
+The
+.Pa ftpusers
+service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+account management.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li account
+feature.
+.Ss Ftpusers Account Management Module
+The
+.Pa ftpusers
+account management component
+.Pq Fn pam_sm_acct_mgmt ,
+succeeds if and only if the user is listed in
+.Pa /etc/ftpusers .
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm disallow"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include reasons why the user's authentication attempt
+was declined.
+.It Cm disallow
+reverse the semantics;
+.Nm
+will succeed if and only if the user is not listed in
+.Pa /etc/ftpusers .
+.El
+.Sh SEE ALSO
+.Xr pam 3 ,
+.Xr ftpusers 5 ,
+.Xr pam.conf 5
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_ftpusers/pam_ftpusers.c b/lib/libpam/modules/pam_ftpusers/pam_ftpusers.c
new file mode 100644
index 000000000000..d33c0e85e0cb
--- /dev/null
+++ b/lib/libpam/modules/pam_ftpusers/pam_ftpusers.c
@@ -0,0 +1,115 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2001 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS and
+ * NAI Labs, the Security Research Division of Network Associates, Inc.
+ * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
+ * DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/cdefs.h>
+#include <ctype.h>
+#include <grp.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define PAM_SM_ACCOUNT
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+#include <security/openpam.h>
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct passwd *pwd;
+ struct group *grp;
+ const char *user;
+ int pam_err, found, allow;
+ char *line, *name, **mem;
+ size_t len, ulen;
+ FILE *f;
+
+ pam_err = pam_get_user(pamh, &user, NULL);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+ if (user == NULL || (pwd = getpwnam(user)) == NULL)
+ return (PAM_SERVICE_ERR);
+
+ found = 0;
+ ulen = strlen(user);
+ if ((f = fopen(_PATH_FTPUSERS, "r")) == NULL) {
+ PAM_LOG("%s: %m", _PATH_FTPUSERS);
+ goto done;
+ }
+ while (!found && (line = fgetln(f, &len)) != NULL) {
+ if (*line == '#')
+ continue;
+ while (len > 0 && isspace(line[len - 1]))
+ --len;
+ if (len == 0)
+ continue;
+ /* simple case first */
+ if (*line != '@') {
+ if (len == ulen && strncmp(user, line, len) == 0)
+ found = 1;
+ continue;
+ }
+ /* member of specified group? */
+ asprintf(&name, "%.*s", (int)len - 1, line + 1);
+ if (name == NULL) {
+ fclose(f);
+ return (PAM_BUF_ERR);
+ }
+ grp = getgrnam(name);
+ free(name);
+ if (grp == NULL)
+ continue;
+ for (mem = grp->gr_mem; mem && *mem && !found; ++mem)
+ if (strcmp(user, *mem) == 0)
+ found = 1;
+ }
+ done:
+ allow = (openpam_get_option(pamh, "disallow") == NULL);
+ if (found)
+ pam_err = allow ? PAM_SUCCESS : PAM_AUTH_ERR;
+ else
+ pam_err = allow ? PAM_AUTH_ERR : PAM_SUCCESS;
+ if (f != NULL)
+ fclose(f);
+ return (pam_err);
+}
+
+PAM_MODULE_ENTRY("pam_ftpusers");
diff --git a/lib/libpam/modules/pam_group/Makefile b/lib/libpam/modules/pam_group/Makefile
new file mode 100644
index 000000000000..0395b3a8f355
--- /dev/null
+++ b/lib/libpam/modules/pam_group/Makefile
@@ -0,0 +1,5 @@
+LIB= pam_group
+SRCS= pam_group.c
+MAN= pam_group.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_group/Makefile.depend b/lib/libpam/modules/pam_group/Makefile.depend
new file mode 100644
index 000000000000..0665960a2cd2
--- /dev/null
+++ b/lib/libpam/modules/pam_group/Makefile.depend
@@ -0,0 +1,16 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_group/pam_group.8 b/lib/libpam/modules/pam_group/pam_group.8
new file mode 100644
index 000000000000..315aaa6cc267
--- /dev/null
+++ b/lib/libpam/modules/pam_group/pam_group.8
@@ -0,0 +1,100 @@
+.\" Copyright (c) 2003 Networks Associates Technology, Inc.
+.\" Copyright (c) 2004-2011 Dag-Erling Smørgrav
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS and NAI Labs, the Security Research Division of Network
+.\" Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+.\" ("CBOSS"), as part of the DARPA CHATS research program.
+.\"
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd July 19, 2014
+.Dt PAM_GROUP 8
+.Os
+.Sh NAME
+.Nm pam_group
+.Nd Group PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_group
+.Op Ar arguments
+.Sh DESCRIPTION
+The group service module for PAM accepts or rejects users based on
+their membership in a particular file group.
+.Nm pam_group
+provides functionality for two PAM categories: authentication and
+account management.
+In terms of the module-type parameter, they are the ``auth'' and
+``account'' features.
+.Pp
+The following options may be passed to the
+.Nm
+module:
+.Bl -tag -width ".Cm fail_safe"
+.It Cm deny
+Reverse the meaning of the test, i.e., reject the applicant if and only
+if he or she is a member of the specified group.
+This can be useful to exclude certain groups of users from certain
+services.
+.It Cm fail_safe
+If the specified group does not exist, or has no members, act as if
+it does exist and the applicant is a member.
+.It Cm group Ns = Ns Ar groupname
+Specify the name of the group to check.
+The default is
+.Dq Li wheel .
+.It Cm luser
+Accept or reject based on the target user's group membership.
+.It Cm root_only
+Skip this module entirely if the target account is not the superuser
+account.
+.It Cm ruser
+Accept or reject based on the supplicant's group membership.
+This is the default.
+.El
+.Pp
+Note that the
+.Cm luser
+and
+.Cm ruser
+options are mutually exclusive, and that
+.Nm
+will fail if both are specified.
+.Sh SEE ALSO
+.Xr pam 3 ,
+.Xr pam.conf 5
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_group/pam_group.c b/lib/libpam/modules/pam_group/pam_group.c
new file mode 100644
index 000000000000..9707a9cd278c
--- /dev/null
+++ b/lib/libpam/modules/pam_group/pam_group.c
@@ -0,0 +1,145 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * Copyright (c) 2004-2011 Dag-Erling Smørgrav
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/types.h>
+
+#include <grp.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/openpam.h>
+
+static int
+pam_group(pam_handle_t *pamh)
+{
+ int local, remote;
+ const char *group, *user;
+ const void *ruser;
+ char *const *list;
+ struct passwd *pwd;
+ struct group *grp;
+
+ /* get target account */
+ if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS ||
+ user == NULL || (pwd = getpwnam(user)) == NULL)
+ return (PAM_AUTH_ERR);
+ if (pwd->pw_uid != 0 && openpam_get_option(pamh, "root_only"))
+ return (PAM_IGNORE);
+
+ /* check local / remote */
+ local = openpam_get_option(pamh, "luser") ? 1 : 0;
+ remote = openpam_get_option(pamh, "ruser") ? 1 : 0;
+ if (local && remote) {
+ openpam_log(PAM_LOG_ERROR, "(pam_group) "
+ "the luser and ruser options are mutually exclusive");
+ return (PAM_SERVICE_ERR);
+ } else if (local) {
+ /* we already have the correct struct passwd */
+ } else {
+ if (!remote)
+ openpam_log(PAM_LOG_NOTICE, "(pam_group) "
+ "neither luser nor ruser specified, assuming ruser");
+ /* default / historical behavior */
+ if (pam_get_item(pamh, PAM_RUSER, &ruser) != PAM_SUCCESS ||
+ ruser == NULL || (pwd = getpwnam(ruser)) == NULL)
+ return (PAM_AUTH_ERR);
+ }
+
+ /* get regulating group */
+ if ((group = openpam_get_option(pamh, "group")) == NULL)
+ group = "wheel";
+ if ((grp = getgrnam(group)) == NULL || grp->gr_mem == NULL)
+ goto failed;
+
+ /* check if user's own primary group */
+ if (pwd->pw_gid == grp->gr_gid)
+ goto found;
+
+ /* iterate over members */
+ for (list = grp->gr_mem; list != NULL && *list != NULL; ++list)
+ if (strcmp(*list, pwd->pw_name) == 0)
+ goto found;
+
+ not_found:
+ if (openpam_get_option(pamh, "deny"))
+ return (PAM_SUCCESS);
+ return (PAM_AUTH_ERR);
+ found:
+ if (openpam_get_option(pamh, "deny"))
+ return (PAM_AUTH_ERR);
+ return (PAM_SUCCESS);
+ failed:
+ if (openpam_get_option(pamh, "fail_safe"))
+ goto found;
+ else
+ goto not_found;
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (pam_group(pamh));
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t * pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (pam_group(pamh));
+}
+
+PAM_MODULE_ENTRY("pam_group");
diff --git a/lib/libpam/modules/pam_guest/Makefile b/lib/libpam/modules/pam_guest/Makefile
new file mode 100644
index 000000000000..7128b513afbc
--- /dev/null
+++ b/lib/libpam/modules/pam_guest/Makefile
@@ -0,0 +1,5 @@
+LIB= pam_guest
+SRCS= pam_guest.c
+MAN= pam_guest.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_guest/Makefile.depend b/lib/libpam/modules/pam_guest/Makefile.depend
new file mode 100644
index 000000000000..0665960a2cd2
--- /dev/null
+++ b/lib/libpam/modules/pam_guest/Makefile.depend
@@ -0,0 +1,16 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_guest/pam_guest.8 b/lib/libpam/modules/pam_guest/pam_guest.8
new file mode 100644
index 000000000000..c626187d5b19
--- /dev/null
+++ b/lib/libpam/modules/pam_guest/pam_guest.8
@@ -0,0 +1,96 @@
+.\" Copyright (c) 2003 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS and NAI Labs, the Security Research Division of Network
+.\" Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+.\" ("CBOSS"), as part of the DARPA CHATS research program.
+.\"
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd May 26, 2003
+.Dt PAM_GUEST 8
+.Os
+.Sh NAME
+.Nm pam_guest
+.Nd Guest PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_guest
+.Op Ar arguments
+.Sh DESCRIPTION
+The guest service module for PAM allows guest logins.
+If successful, the
+.Nm
+module sets the PAM environment variable
+.Ev GUEST
+to the login name.
+The application can check this variable using
+.Xr pam_getenv 3
+to differentiate guest logins from normal logins.
+.Pp
+The following options may be passed to the
+.Nm
+module:
+.Bl -tag -width ".Cm pass_as_ruser"
+.It Cm guests Ns = Ns Ar list
+Comma-separated list of guest account names.
+The default is
+.Dq Li guest .
+A typical value for
+.Xr ftpd 8
+would be
+.Dq Li anonymous,ftp .
+.It Cm nopass
+Omits the password prompt if the target account is on the list of
+guest accounts.
+.It Cm pass_as_ruser
+The password typed in by the user is exported as the
+.Dv PAM_RUSER
+item.
+This is useful for applications like
+.Xr ftpd 8
+where guest users are encouraged to use their email address as
+password.
+.It Cm pass_is_user
+Requires the guest user to type in the guest account name as password.
+.El
+.Sh SEE ALSO
+.Xr pam 3 ,
+.Xr pam_get_item 3 ,
+.Xr pam_getenv 3 ,
+.Xr pam.conf 5
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_guest/pam_guest.c b/lib/libpam/modules/pam_guest/pam_guest.c
new file mode 100644
index 000000000000..c3ef07fc189a
--- /dev/null
+++ b/lib/libpam/modules/pam_guest/pam_guest.c
@@ -0,0 +1,114 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/cdefs.h>
+#include <string.h>
+
+#define PAM_SM_AUTH
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/openpam.h>
+
+#define DEFAULT_GUESTS "guest"
+
+static int
+lookup(const char *str, const char *list)
+{
+ const char *next;
+ size_t len;
+
+ len = strlen(str);
+ while (*list != '\0') {
+ while (*list == ',')
+ ++list;
+ if ((next = strchr(list, ',')) == NULL)
+ next = strchr(list, '\0');
+ if (next - list == (ptrdiff_t)len &&
+ strncmp(list, str, len) == 0)
+ return (1);
+ list = next;
+ }
+ return (0);
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ const char *authtok, *guests, *user;
+ int err, is_guest;
+
+ /* get target account */
+ if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || user == NULL)
+ return (PAM_AUTH_ERR);
+
+ /* get list of guest logins */
+ if ((guests = openpam_get_option(pamh, "guests")) == NULL)
+ guests = DEFAULT_GUESTS;
+
+ /* check if the target account is on the list */
+ is_guest = lookup(user, guests);
+
+ /* check password */
+ if (!openpam_get_option(pamh, "nopass")) {
+ err = pam_get_authtok(pamh, PAM_AUTHTOK, &authtok, NULL);
+ if (err != PAM_SUCCESS)
+ return (err);
+ if (openpam_get_option(pamh, "pass_is_user") &&
+ strcmp(user, authtok) != 0)
+ return (PAM_AUTH_ERR);
+ if (openpam_get_option(pamh, "pass_as_ruser"))
+ pam_set_item(pamh, PAM_RUSER, authtok);
+ }
+
+ /* done */
+ if (is_guest) {
+ pam_setenv(pamh, "GUEST", user, 1);
+ return (PAM_SUCCESS);
+ }
+ return (PAM_AUTH_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t * pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_guest");
diff --git a/lib/libpam/modules/pam_krb5/Makefile b/lib/libpam/modules/pam_krb5/Makefile
new file mode 100644
index 000000000000..7634930a7202
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/Makefile
@@ -0,0 +1,92 @@
+# Copyright 2001 FreeBSD, Inc.
+# 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, this list of conditions and the following disclaimer.
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <src.opts.mk>
+
+.if ${MK_MITKRB5} != "no"
+SRCDIR= ${SRCTOP}/contrib/pam-krb5
+.PATH: ${SRCDIR}/module \
+ ${SRCDIR}/portable \
+ ${SRCDIR}/pam-util \
+ ${SRCDIR}
+
+PACKAGE= kerberos
+LIB= pam_krb5
+LIBADD= com_err krb5
+
+SRCS= account.c \
+ alt-auth.c \
+ args.c \
+ auth.c \
+ cache.c \
+ context.c \
+ dummy.c \
+ fast.c \
+ krb5-extra.c \
+ logging.c \
+ pam-util_options.c \
+ module_options.c \
+ pam_syslog.c \
+ pam_vsyslog.c \
+ password.c \
+ prompting.c \
+ public.c \
+ setcred.c \
+ support.c \
+ vector.c
+
+MAN= pam-krb5.8
+MLINKS= pam-krb5.8 pam_krb5.8
+
+CFLAGS= -I${SRCDIR} \
+ -I${.CURDIR} \
+ -fno-strict-aliasing \
+ -DHAVE_CONFIG_H
+
+WARNS?= 3
+
+CLEANFILES= pam-util_options.c module_options.c
+
+pam-util_options.c: .PHONY
+ cp ${SRCDIR}/pam-util/options.c pam-util_options.c
+
+module_options.c: .PHONY
+ cp ${SRCDIR}/module/options.c module_options.c
+.else
+PACKAGE= kerberos
+
+LIB= pam_krb5
+SRCS= pam_krb5.c
+MAN= pam_krb5.8
+.if defined(_FREEFALL_CONFIG)
+CFLAGS+=-D_FREEFALL_CONFIG
+WARNS?= 3
+.endif
+
+LIBADD+= krb5
+
+.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_krb5/Makefile.depend b/lib/libpam/modules/pam_krb5/Makefile.depend
new file mode 100644
index 000000000000..05183339e3a9
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/Makefile.depend
@@ -0,0 +1,19 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ kerberos5/lib/libasn1 \
+ kerberos5/lib/libkrb5 \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcom_err \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_krb5/config.h b/lib/libpam/modules/pam_krb5/config.h
new file mode 100644
index 000000000000..75695eef66a1
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/config.h
@@ -0,0 +1,412 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the `asprintf' function. */
+#define HAVE_ASPRINTF 1
+
+/* Define to 1 if you have the declaration of `krb5_kt_free_entry', and to 0
+ if you don't. */
+#define HAVE_DECL_KRB5_KT_FREE_ENTRY 1
+
+/* Define to 1 if you have the declaration of `reallocarray', and to 0 if you
+ don't. */
+#define HAVE_DECL_REALLOCARRAY 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <et/com_err.h> header file. */
+/* #undef HAVE_ET_COM_ERR_H */
+
+/* Define to 1 if you have the `explicit_bzero' function. */
+#define HAVE_EXPLICIT_BZERO 1
+
+/* Define to 1 if you have the <hx509_err.h> header file. */
+/* #undef HAVE_HX509_ERR_H */
+
+/* Define to 1 if you have the <ibm_svc/krb5_svc.h> header file. */
+/* #undef HAVE_IBM_SVC_KRB5_SVC_H */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+#define HAVE_ISSETUGID 1
+
+/* Define to 1 if you have the <k5profile.h> header file. */
+/* #undef HAVE_K5PROFILE_H */
+
+/* Define to enable kadmin client features. */
+#define HAVE_KADM5CLNT 1
+
+/* Define to 1 if you have the `kadm5_init_krb5_context' function. */
+#define HAVE_KADM5_INIT_KRB5_CONTEXT 1
+
+/* Define to 1 if you have the `kadm5_init_with_skey_ctx' function. */
+/* #undef HAVE_KADM5_INIT_WITH_SKEY_CTX */
+
+/* Define to 1 if you have the <kadm5/kadm5_err.h> header file. */
+#define HAVE_KADM5_KADM5_ERR_H 1
+
+/* Define to 1 if you have the <kerberosv5/com_err.h> header file. */
+/* #undef HAVE_KERBEROSV5_COM_ERR_H */
+
+/* Define to 1 if you have the <kerberosv5/krb5.h> header file. */
+/* #undef HAVE_KERBEROSV5_KRB5_H */
+
+/* Define to enable Kerberos features. */
+#define HAVE_KRB5 1
+
+/* Define to 1 if you have the `krb5_appdefault_string' function. */
+#define HAVE_KRB5_APPDEFAULT_STRING 1
+
+/* Define to 1 if you have the `krb5_cc_get_full_name' function. */
+#define HAVE_KRB5_CC_GET_FULL_NAME 1
+
+/* Define to 1 if you have the `krb5_data_free' function. */
+/* #undef HAVE_KRB5_DATA_FREE */
+
+/* Define to 1 if you have the `krb5_free_default_realm' function. */
+#define HAVE_KRB5_FREE_DEFAULT_REALM 1
+
+/* Define to 1 if you have the `krb5_free_error_message' function. */
+#define HAVE_KRB5_FREE_ERROR_MESSAGE 1
+
+/* Define to 1 if you have the `krb5_free_string' function. */
+#define HAVE_KRB5_FREE_STRING 1
+
+/* Define to 1 if you have the `krb5_get_error_message' function. */
+#define HAVE_KRB5_GET_ERROR_MESSAGE 1
+
+/* Define to 1 if you have the `krb5_get_error_string' function. */
+/* #undef HAVE_KRB5_GET_ERROR_STRING */
+
+/* Define to 1 if you have the `krb5_get_err_txt' function. */
+/* #undef HAVE_KRB5_GET_ERR_TXT */
+
+/* Define to 1 if you have the `krb5_get_init_creds_opt_alloc' function. */
+#define HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC 1
+
+/* Define to 1 if you have the `krb5_get_init_creds_opt_free' function. */
+#define HAVE_KRB5_GET_INIT_CREDS_OPT_FREE 1
+
+/* Define if krb5_get_init_creds_opt_free takes two arguments. */
+#define HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_2_ARGS 1
+
+/* Define to 1 if you have the `krb5_get_init_creds_opt_set_anonymous'
+ function. */
+#define HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ANONYMOUS 1
+
+/* Define to 1 if you have the
+ `krb5_get_init_creds_opt_set_change_password_prompt' function. */
+#define HAVE_KRB5_GET_INIT_CREDS_OPT_SET_CHANGE_PASSWORD_PROMPT 1
+
+/* Define to 1 if you have the `krb5_get_init_creds_opt_set_default_flags'
+ function. */
+/* #undef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_DEFAULT_FLAGS */
+
+/* Define to 1 if you have the `krb5_get_init_creds_opt_set_fast_ccache_name'
+ function. */
+#define HAVE_KRB5_GET_INIT_CREDS_OPT_SET_FAST_CCACHE_NAME 1
+
+/* Define to 1 if you have the `krb5_get_init_creds_opt_set_out_ccache'
+ function. */
+#define HAVE_KRB5_GET_INIT_CREDS_OPT_SET_OUT_CCACHE 1
+
+/* Define to 1 if you have the `krb5_get_init_creds_opt_set_pa' function. */
+#define HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PA 1
+
+/* Define to 1 if you have the `krb5_get_init_creds_opt_set_pkinit' function.
+ */
+/* #undef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PKINIT */
+
+/* Define if krb5_get_init_creds_opt_set_pkinit takes 9 arguments. */
+/* #undef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PKINIT_9_ARGS */
+
+/* Define to 1 if you have the `krb5_get_profile' function. */
+/* #undef HAVE_KRB5_GET_PROFILE */
+
+/* Define to 1 if you have the `krb5_get_prompt_types' function. */
+#define HAVE_KRB5_GET_PROMPT_TYPES 1
+
+/* Define to 1 if you have the <krb5.h> header file. */
+#define HAVE_KRB5_H 1
+
+/* Define if your Kerberos implementation is Heimdal. */
+/* #undef HAVE_KRB5_HEIMDAL */
+
+/* Define to 1 if you have the `krb5_init_secure_context' function. */
+#define HAVE_KRB5_INIT_SECURE_CONTEXT 1
+
+/* Define to 1 if you have the <krb5/krb5.h> header file. */
+#define HAVE_KRB5_KRB5_H 1
+
+/* Define if your Kerberos implementation is MIT. */
+#define HAVE_KRB5_MIT 1
+
+/* Define to 1 if you have the `krb5_principal_get_realm' function. */
+/* #undef HAVE_KRB5_PRINCIPAL_GET_REALM */
+
+/* Define to 1 if you have the `krb5_principal_set_comp_string' function. */
+/* #undef HAVE_KRB5_PRINCIPAL_SET_COMP_STRING */
+
+/* Define to 1 if the system has the type `krb5_realm'. */
+/* #undef HAVE_KRB5_REALM */
+
+/* Define to 1 if you have the `krb5_set_password' function. */
+#define HAVE_KRB5_SET_PASSWORD 1
+
+/* Define to 1 if you have the `krb5_set_trace_filename' function. */
+#define HAVE_KRB5_SET_TRACE_FILENAME 1
+
+/* Define to 1 if you have the `krb5_svc_get_msg' function. */
+/* #undef HAVE_KRB5_SVC_GET_MSG */
+
+/* Define to 1 if you have the `krb5_verify_init_creds_opt_init' function. */
+#define HAVE_KRB5_VERIFY_INIT_CREDS_OPT_INIT 1
+
+/* Define to 1 if you have the `krb5_xfree' function. */
+/* #undef HAVE_KRB5_XFREE */
+
+/* Define to 1 if the system has the type `long long int'. */
+#define HAVE_LONG_LONG_INT 1
+
+/* Define to 1 if you have the <minix/config.h> header file. */
+/* #undef HAVE_MINIX_CONFIG_H */
+
+/* Define to 1 if you have the `mkstemp' function. */
+#define HAVE_MKSTEMP 1
+
+/* Define to 1 if you have the `pam_getenv' function. */
+#define HAVE_PAM_GETENV 1
+
+/* Define to 1 if you have the `pam_getenvlist' function. */
+#define HAVE_PAM_GETENVLIST 1
+
+/* Define to 1 if you have the `pam_modutil_getpwnam' function. */
+/* #undef HAVE_PAM_MODUTIL_GETPWNAM */
+
+/* Define to 1 if you have the <pam/pam_appl.h> header file. */
+/* #undef HAVE_PAM_PAM_APPL_H */
+
+/* Define to 1 if you have the <pam/pam_ext.h> header file. */
+/* #undef HAVE_PAM_PAM_EXT_H */
+
+/* Define to 1 if you have the <pam/pam_modutil.h> header file. */
+/* #undef HAVE_PAM_PAM_MODUTIL_H */
+
+/* Define to 1 if you have the `pam_syslog' function. */
+/* #undef HAVE_PAM_SYSLOG */
+
+/* Define to 1 if you have the `pam_vsyslog' function. */
+/* #undef HAVE_PAM_VSYSLOG */
+
+/* Define to 1 if you have the <profile.h> header file. */
+/* #undef HAVE_PROFILE_H */
+
+/* Define to 1 if you have the `reallocarray' function. */
+#define HAVE_REALLOCARRAY 1
+
+/* Define to 1 if you have the `regcomp' function. */
+#define HAVE_REGCOMP 1
+
+/* Define to 1 if you have the <security/pam_appl.h> header file. */
+#define HAVE_SECURITY_PAM_APPL_H 1
+
+/* Define to 1 if you have the <security/pam_ext.h> header file. */
+/* #undef HAVE_SECURITY_PAM_EXT_H */
+
+/* Define to 1 if you have the <security/pam_modutil.h> header file. */
+/* #undef HAVE_SECURITY_PAM_MODUTIL_H */
+
+/* Define to 1 if the system has the type `ssize_t'. */
+#define HAVE_SSIZE_T 1
+
+/* Define to 1 if stdbool.h conforms to C99. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strndup' function. */
+#define HAVE_STRNDUP 1
+
+/* Define to 1 if you have the <sys/bittypes.h> header file. */
+/* #undef HAVE_SYS_BITTYPES_H */
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if the system has the type `unsigned long long int'. */
+#define HAVE_UNSIGNED_LONG_LONG_INT 1
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if the system has the type `_Bool'. */
+#define HAVE__BOOL 1
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#define LT_OBJDIR ".libs/"
+
+/* The name of the PAM module, used by the pam_vsyslog replacement. */
+#define MODULE_NAME "pam_krb5"
+
+/* Name of package */
+#define PACKAGE "pam-krb5"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "eagle@eyrie.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "pam-krb5"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "pam-krb5 4.11"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "pam-krb5"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "4.11"
+
+/* Define to const if PAM uses const in pam_get_item, empty otherwise. */
+#define PAM_CONST const
+
+/* Define to const if PAM uses const in pam_strerror, empty otherwise. */
+#define PAM_STRERROR_CONST const
+
+/* Define to the full path to openssl for some tests. */
+#define PATH_OPENSSL "/usr/bin/openssl"
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* Define to 1 if all of the C90 standard headers exist (not just the ones
+ required in a freestanding environment). This macro is provided for
+ backward compatibility; new code need not use it. */
+#define STDC_HEADERS 1
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable general extensions on macOS. */
+#ifndef _DARWIN_C_SOURCE
+# define _DARWIN_C_SOURCE 1
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable X/Open compliant socket functions that do not require linking
+ with -lxnet on HP-UX 11.11. */
+#ifndef _HPUX_ALT_XOPEN_SOCKET_API
+# define _HPUX_ALT_XOPEN_SOCKET_API 1
+#endif
+/* Identify the host operating system as Minix.
+ This macro does not affect the system headers' behavior.
+ A future release of Autoconf may stop defining this macro. */
+#ifndef _MINIX
+/* # undef _MINIX */
+#endif
+/* Enable general extensions on NetBSD.
+ Enable NetBSD compatibility extensions on Minix. */
+#ifndef _NETBSD_SOURCE
+# define _NETBSD_SOURCE 1
+#endif
+/* Enable OpenBSD compatibility extensions on NetBSD.
+ Oddly enough, this does nothing on OpenBSD. */
+#ifndef _OPENBSD_SOURCE
+# define _OPENBSD_SOURCE 1
+#endif
+/* Define to 1 if needed for POSIX-compatible behavior. */
+#ifndef _POSIX_SOURCE
+/* # undef _POSIX_SOURCE */
+#endif
+/* Define to 2 if needed for POSIX-compatible behavior. */
+#ifndef _POSIX_1_SOURCE
+/* # undef _POSIX_1_SOURCE */
+#endif
+/* Enable POSIX-compatible threading on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */
+#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
+# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */
+#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
+# define __STDC_WANT_IEC_60559_BFP_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */
+#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
+# define __STDC_WANT_IEC_60559_DFP_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */
+#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
+# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */
+#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
+# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */
+#ifndef __STDC_WANT_LIB_EXT2__
+# define __STDC_WANT_LIB_EXT2__ 1
+#endif
+/* Enable extensions specified by ISO/IEC 24747:2009. */
+#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
+# define __STDC_WANT_MATH_SPEC_FUNCS__ 1
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable X/Open extensions. Define to 500 only if necessary
+ to make mbstate_t available. */
+#ifndef _XOPEN_SOURCE
+/* # undef _XOPEN_SOURCE */
+#endif
+
+
+/* Version number of package */
+#define VERSION "4.11"
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
diff --git a/lib/libpam/modules/pam_krb5/pam-krb5.8 b/lib/libpam/modules/pam_krb5/pam-krb5.8
new file mode 100644
index 000000000000..3413748c7850
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam-krb5.8
@@ -0,0 +1,1025 @@
+.\" -*- mode: troff; coding: utf-8 -*-
+.\" Automatically generated by Pod::Man 5.0102 (Pod::Simple 3.45)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>.
+.ie n \{\
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds C`
+. ds C'
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\"
+.\" If the F register is >0, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.\"
+.\" Avoid warning from groff about undefined register 'F'.
+.de IX
+..
+.nr rF 0
+.if \n(.g .if rF .nr rF 1
+.if (\n(rF:(\n(.g==0)) \{\
+. if \nF \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. if !\nF==2 \{\
+. nr % 0
+. nr F 2
+. \}
+. \}
+.\}
+.rr rF
+.\" ========================================================================
+.\"
+.IX Title "PAM_KRB5 1"
+.TH PAM_KRB5 1 2025-06-05 "perl v5.40.2" "User Contributed Perl Documentation"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH NAME
+pam_krb5 \- Kerberos PAM module
+.SH SYNOPSIS
+.IX Header "SYNOPSIS"
+.Vb 4
+\& auth sufficient pam_krb5.so minimum_uid=1000
+\& session required pam_krb5.so minimum_uid=1000
+\& account required pam_krb5.so minimum_uid=1000
+\& password sufficient pam_krb5.so minimum_uid=1000
+.Ve
+.SH DESCRIPTION
+.IX Header "DESCRIPTION"
+The Kerberos service module for PAM, typically installed at
+\&\fI/lib/security/pam_krb5.so\fR, provides functionality for the four PAM
+operations: authentication, account management, session management, and
+password management. \fIpam_krb5.so\fR is a shared object that is
+dynamically loaded by the PAM subsystem as necessary, based on the system
+PAM configuration. PAM is a system for plugging in external
+authentication and session management modules so that each application
+doesn't have to know the best way to check user authentication or create a
+user session on that system. For details on how to configure PAM on your
+system, see the PAM man page, often \fBpam\fR\|(7).
+.PP
+Here are the actions of this module when called from each group:
+.IP auth 4
+.IX Item "auth"
+Provides implementations of \fBpam_authenticate()\fR and \fBpam_setcred()\fR. The
+former takes the username from the PAM session, prompts for the user's
+password (unless configured to use an already-entered password), and then
+performs a Kerberos initial authentication, storing the obtained
+credentials (if successful) in a temporary ticket cache. The latter,
+depending on the flags it is called with, either takes the contents of the
+temporary ticket cache and writes it out to a persistent ticket cache
+owned by the user or uses the temporary ticket cache to refresh an
+existing user ticket cache.
+.Sp
+Passwords as long or longer than PAM_MAX_RESP_SIZE octets (normally 512
+octets) will be rejected, since excessively long passwords can be used as
+a denial of service attack.
+.Sp
+After doing the initial authentication, the Kerberos PAM module will
+attempt to obtain tickets for a key in the local system keytab and then
+verify those tickets. Unless this step is performed, the authentication
+is vulnerable to KDC spoofing, but it requires that the system have a
+local key and that the PAM module be running as a user that can read the
+keytab file (normally \fI/etc/krb5.keytab\fR. You can point the Kerberos PAM
+module at a different keytab with the \fIkeytab\fR option. If that keytab
+cannot be read or if no keys are found in it, the default (potentially
+insecure) behavior is to skip this check. If you want to instead fail
+authentication if the obtained tickets cannot be checked, set
+\&\f(CW\*(C`verify_ap_req_nofail\*(C'\fR to true in the [libdefaults] section of
+\&\fI/etc/krb5.conf\fR. Note that this will affect applications other than
+this PAM module.
+.Sp
+By default, whenever the user is authenticated, a basic authorization
+check will also be done using \fBkrb5_kuserok()\fR. The default behavior of
+this function is to check the user's account for a \fI.k5login\fR file and,
+if one is present, ensure that the user's principal is listed in that
+file. If \fI.k5login\fR is not present, the default check is to ensure that
+the user's principal is in the default local realm and the user portion of
+the principal matches the account name (this can be changed by configuring
+a custom aname to localname mapping in \fIkrb5.conf\fR; see the Kerberos
+documentation for details). This can be customized with several
+configuration options; see below.
+.Sp
+If the username provided to PAM contains an \f(CW\*(C`@\*(C'\fR and Kerberos can,
+treating the username as a principal, map it to a local account name,
+\&\fBpam_authenticate()\fR will change the PAM user to that local account name.
+This allows users to log in with their Kerberos principal and let Kerberos
+do the mapping to an account. This can be disabled with the
+\&\fIno_update_user\fR option. Be aware, however, that this facility cannot be
+used with OpenSSH. OpenSSH will reject usernames that don't match local
+accounts before this remapping can be done and will pass an invalid
+password to the PAM module. Also be aware that several other common PAM
+modules, such as pam_securetty, expect to be able to look up the user with
+\&\fBgetpwnam()\fR and cannot be called before pam_krb5 when using this feature.
+.Sp
+When \fBpam_setcred()\fR is called to initialize a new ticket cache, the
+environment variable KRB5CCNAME is set to the path to that ticket cache.
+By default, the cache will be named \fI/tmp/krb5cc_UID_RANDOM\fR where UID is
+the user's UID and RANDOM is six randomly-chosen letters. This can be
+configured with the \fIccache\fR and \fIccache_dir\fR options.
+.Sp
+pam\-krb5 does not use the default ticket cache location or
+\&\fIdefault_cc_name\fR in the \f(CW\*(C`[libdefaults]\*(C'\fR section of \fIkrb5.conf\fR. The
+default cache location would share a cache for all sessions of the same
+user, which causes confusing behavior when the user logs out of one of
+multiple sessions.
+.Sp
+If \fBpam_setcred()\fR initializes a new ticket cache, it will also set up that
+ticket cache so that it will be deleted when the PAM session is closed.
+Normally, the calling program (\fBlogin\fR, \fBsshd\fR, etc.) will run the
+user's shell as a sub-process, wait for it to exit, and then close the PAM
+session, thereby cleaning up the user's session.
+.IP session 4
+.IX Item "session"
+Provides implementations of \fBpam_open_session()\fR, which is equivalent to
+calling \fBpam_setcred()\fR with the PAM_ESTABLISH_CRED flag, and
+\&\fBpam_close_session()\fR, which destroys the ticket cache created by
+\&\fBpam_setcred()\fR.
+.IP account 4
+.IX Item "account"
+Provides an implementation of \fBpam_acct_mgmt()\fR. All it does is do the same
+authorization check as performed by the \fBpam_authenticate()\fR implementation
+described above.
+.IP password 4
+.IX Item "password"
+Provides an implementation of \fBpam_chauthtok()\fR, which implements password
+changes. The user is prompted for their existing password (unless
+configured to use an already entered one) and the PAM module then obtains
+credentials for the special Kerberos principal \f(CW\*(C`kadmin/changepw\*(C'\fR. It
+then prompts the user for a new password, twice to ensure that the user
+entered it properly (again, unless configured to use an already entered
+password), and then does a Kerberos password change.
+.Sp
+Passwords as long or longer than PAM_MAX_RESP_SIZE octets (normally 512
+octets) will be rejected, since excessively long passwords can be used as
+a denial of service attack.
+.Sp
+Unlike the normal Unix password module, this module will allow any user to
+change any other user's password if they know the old password. Also,
+unlike the normal Unix password module, root will always be prompted for
+the old password, since root has no special status in Kerberos. (To
+change passwords in Kerberos without knowing the old password, use
+\&\fBkadmin\fR\|(8) instead.)
+.PP
+Both the account and session management calls of the Kerberos PAM module
+will return PAM_IGNORE if called in the context of a PAM session for a
+user who did not authenticate with Kerberos (a return code of \f(CW\*(C`ignore\*(C'\fR in
+the Linux PAM configuration language).
+.PP
+Note that this module assumes the network is available in order to do a
+Kerberos authentication. If the network is not available, some Kerberos
+libraries have timeouts longer than the timeout imposed by the login
+process. This means that using this module incautiously can make it
+impossible to log on to console as root. For this reason, you should
+always use the \fIignore_root\fR or \fIminimum_uid\fR options, list a local
+authentication module such as \fBpam_unix\fR first with a control field of
+\&\f(CW\*(C`sufficient\*(C'\fR so that the Kerberos PAM module will be skipped if local
+password authentication was successful.
+.PP
+This is not the same PAM module as the Kerberos PAM module available from
+Sourceforge, or the one included on Red Hat systems. It supports many of
+the same options, has some additional options, and doesn't support some of
+the options those modules do.
+.SH CONFIGURATION
+.IX Header "CONFIGURATION"
+The Kerberos PAM module takes many options, not all of which are relevant
+to every PAM group; options that are not relevant will be silently
+ignored. Any of these options can be set in the PAM configuration as
+arguments listed after \f(CW\*(C`pam_krb5.so\*(C'\fR. Some of the options can also be
+set in the system \fIkrb5.conf\fR file; if this is possible, it will be noted
+below in the option description.
+.PP
+To set a boolean option in the PAM configuration file, just give the name
+of the option in the arguments. To set an option that takes an argument,
+follow the option name with an equal sign (=) and the value, with no
+separating whitespace. Whitespace in option arguments is not supported in
+the PAM configuration.
+.PP
+To set an option for the PAM module in the system \fIkrb5.conf\fR file, put
+that option in the \f(CW\*(C`[appdefaults]\*(C'\fR section. All options must be followed
+by an equal sign (=) and a value, so for boolean options add \f(CW\*(C`= true\*(C'\fR.
+The Kerberos PAM module will look for options either at the top level of
+the \f(CW\*(C`[appdefaults]\*(C'\fR section or in a subsection named \f(CW\*(C`pam\*(C'\fR, inside or
+outside a section for the realm. For example, the following fragment of a
+\&\fIkrb5.conf\fR file would set \fIforwardable\fR to true, \fIminimum_uid\fR to
+1000, and set \fIignore_k5login\fR only if the realm is EXAMPLE.COM.
+.PP
+.Vb 8
+\& [appdefaults]
+\& forwardable = true
+\& pam = {
+\& minimum_uid = 1000
+\& EXAMPLE.COM = {
+\& ignore_k5login = true
+\& }
+\& }
+.Ve
+.PP
+For more information on the syntax of \fIkrb5.conf\fR, see \fBkrb5.conf\fR\|(5).
+Note that options that depend on the realm will be set only on the basis
+of the default realm, either as configured in \fBkrb5.conf\fR\|(5) or as set by
+the \fIrealm\fR option described below. If the user authenticates to an
+account qualified with a realm, that realm will not be used when
+determining which options will apply.
+.PP
+There is no difference to the PAM module whether options are specified at
+the top level or in a \f(CW\*(C`pam\*(C'\fR section; the \f(CW\*(C`pam\*(C'\fR section is supported in
+case there are options that should be set for the PAM module but not for
+other applications.
+.PP
+If the same option is set in \fIkrb5.conf\fR and in the PAM configuration,
+the latter takes precedent. Note, however, that due to the configuration
+syntax, there's no way to turn off a boolean option in the PAM
+configuration that was turned on in \fIkrb5.conf\fR.
+.PP
+The start of each option description is annotated with the version of
+pam\-krb5 in which that option was added with the current meaning.
+.SS Authorization
+.IX Subsection "Authorization"
+.IP alt_auth_map=<format> 4
+.IX Item "alt_auth_map=<format>"
+[3.12] This functions similarly to the \fIsearch_k5login\fR option. The
+<format> argument is used as the authentication Kerberos principal, with
+any \f(CW%s\fR in <format> replaced with the username. If the username
+contains an \f(CW\*(C`@\*(C'\fR, only the part of the username before the realm is used
+to replace \f(CW%s\fR. If <format> contains a realm, it will be used;
+otherwise, the realm of the username (if any) will be appended to the
+result. There is no quote removal.
+.Sp
+If this option is present, the default behavior is to try this alternate
+principal first and then fall back to the standard behavior if it fails.
+The primary usage is to allow alternative principals to be used for
+authentication in programs like \fBsudo\fR. Most examples will look like:
+.Sp
+.Vb 1
+\& alt_auth_map=%s/root
+.Ve
+.Sp
+which attempts authentication as the root instance of the username first
+and then falls back to the regular username (but see \fIforce_alt_auth\fR and
+\&\fIonly_alt_auth\fR).
+.Sp
+This option also allows a cheap way to attempt authentication in an
+alternative realm first and then fall back to the primary realm. A
+setting like:
+.Sp
+.Vb 1
+\& alt_auth_map=%s@EXAMPLE.COM
+.Ve
+.Sp
+will attempt authentication in the EXAMPLE.COM realm first and then fall
+back on the local default realm. This is more convenient than running the
+module multiple times with multiple default realms set with \fIrealm\fR, but
+it is very limited: only two realms can be tried, and the alternate realm
+is always tried first.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR, although
+normally it doesn't make sense to do that; normally it is used in the PAM
+options of configuration for specific programs. It is only applicable to
+the auth and account groups. If this option is set for the auth group, be
+sure to set it for the account group as well or account authorization may
+fail.
+.IP force_alt_auth 4
+.IX Item "force_alt_auth"
+[3.12] This option is used with \fIalt_auth_map\fR and forces authentication
+as the mapped principal if that principal exists in the KDC. Only if the
+KDC returns principal unknown does the Kerberos PAM module fall back to
+normal authentication. This can be used to force authentication with an
+alternate instance. If \fIalt_auth_map\fR is not set, it has no effect.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP ignore_k5login 4
+.IX Item "ignore_k5login"
+[2.0] Never look for a \fI.k5login\fR file in the user's home directory.
+Instead, only check that the Kerberos principal maps to the local account
+name. The default check is to ensure the realm matches the local realm
+and the user portion of the principal matches the local account name, but
+this can be customized by setting up an aname to localname mapping in
+\&\fIkrb5.conf\fR.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and account groups.
+.IP ignore_root 4
+.IX Item "ignore_root"
+[1.1] Do not do anything if the username is \f(CW\*(C`root\*(C'\fR. The authentication
+and password calls will silently fail (allowing that status to be ignored
+via a control of \f(CW\*(C`optional\*(C'\fR or \f(CW\*(C`sufficient\*(C'\fR), and the account and
+session calls (including pam_setcred) will return PAM_IGNORE, telling the
+PAM library to proceed as if they weren't mentioned in the PAM
+configuration. This option is supported and will remain, but normally you
+want to use \fIminimum_uid\fR instead.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR.
+.IP minimum_uid=<uid> 4
+.IX Item "minimum_uid=<uid>"
+[2.0] Do not do anything if the authenticated account name corresponds to
+a local account and that local account has a UID lower than <uid>. If
+both of those conditions are true, the authentication and password calls
+will silently fail (allowing that status to be ignored via a control of
+\&\f(CW\*(C`optional\*(C'\fR or \f(CW\*(C`sufficient\*(C'\fR), and the account and session calls
+(including pam_setcred) will return PAM_IGNORE, telling the PAM library to
+proceed as if they weren't mentioned in the PAM configuration.
+.Sp
+Using this option is highly recommended if you don't need to use Kerberos
+to authenticate password logins to the root account (which isn't
+recommended since Kerberos requires a network connection). It provides
+some defense in depth against user principals that happen to match a
+system account incorrectly authenticating as that system account.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR.
+.IP only_alt_auth 4
+.IX Item "only_alt_auth"
+[3.12] This option is used with \fIalt_auth_map\fR and forces the use of the
+mapped principal for authentication. It disables fallback to normal
+authentication in all cases and overrides \fIsearch_k5login\fR and
+\&\fIforce_alt_auth\fR. If \fIalt_auth_map\fR is not set, it has no effect and
+the standard authentication behavior is used.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP search_k5login 4
+.IX Item "search_k5login"
+[2.0] Normally, the Kerberos implementation of pam_authenticate attempts
+to obtain tickets for the authenticating username in the local realm. If
+this option is set and the local user has a \fI.k5login\fR file in their home
+directory, the module will instead open and read that \fI.k5login\fR file,
+attempting to use the supplied password to authenticate as each principal
+listed there in turn. If any of those authentications succeed, the user
+will be successfully authenticated; otherwise, authentication will fail.
+This option is useful for allowing password authentication (via console or
+\&\fBsshd\fR without GSS-API support) to shared accounts. If there is no
+\&\fI.k5login\fR file, the behavior is the same as normal. Using this option
+requires that the user's \fI.k5login\fR file be readable at the time of
+authentication.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.SS "Kerberos Behavior"
+.IX Subsection "Kerberos Behavior"
+.IP anon_fast 4
+.IX Item "anon_fast"
+[4.6] Attempt to use Flexible Authentication Secure Tunneling (FAST) by
+first authenticating as the anonymous user (WELLKNOWN/ANONYMOUS) and using
+its credentials as the FAST armor. This requires anonymous PKINIT be
+enabled for the local realm, that PKINIT be configured on the local
+system, and that the Kerberos library support FAST and anonymous PKINIT.
+.Sp
+FAST is a mechanism to protect Kerberos against password guessing attacks
+and provide other security improvements. To work, FAST requires that a
+ticket be obtained with a strong key to protect exchanges with potentially
+weaker user passwords. This option uses anonymous authentication to
+obtain that key and then uses it to protect the subsequent authentication.
+.Sp
+If anonymous PKINIT is not available or fails, FAST will not be used and
+the authentication will proceed as normal.
+.Sp
+To instead use an existing ticket cache for the FAST credentials, use
+\&\fIfast_ccache\fR instead of this option. If both \fIfast_ccache\fR and
+\&\fIanon_fast\fR are set, the ticket cache named by \fIfast_ccache\fR will be
+tried first, and the Kerberos PAM module will fall back on attempting
+anonymous PKINIT if that cache could not be used.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups.
+.Sp
+The operation is the same as if using the \fIfast_ccache\fR option, but the
+cache is created and destroyed automatically. If both \fIfast_ccache\fR and
+\&\fIanon_fast\fR options are used, the \fIfast_ccache\fR takes precedent and no
+anonymous authentication is done.
+.IP fast_ccache=<ccache_name> 4
+.IX Item "fast_ccache=<ccache_name>"
+[4.3] The same as \fIanon_fast\fR, but use an existing Kerberos ticket cache
+rather than anonymous PKINIT. This allows use of FAST with a realm that
+doesn't support PKINIT or doesn't support anonymous authentication.
+.Sp
+<ccache_name> should be a credential cache containing a ticket obtained
+using a strong key, such as the randomized key for the host principal of
+the local system. If <ccache_name> names a ticket cache that is readable
+by the authenticating process and has tickets then FAST will be attempted.
+The easiest way to use this option is to use a program like \fBk5start\fR to
+maintain a ticket cache using the host's keytab. This ticket cache should
+normally only be readable by root, so this option will not be able to
+protect authentications done as non-root users (such as screensavers).
+.Sp
+If no credentials are present in the ticket cache, or if the ticket cache
+does not exist or is not readable, FAST will not used and authentication
+will proceed as normal. However, if the credentials in that ticket cache
+are expired, authentication will fail if the KDC supports FAST.
+.Sp
+To use anonymous PKINIT to protect the FAST exchange, use the \fIanon_fast\fR
+option instead. \fIanon_fast\fR is easier to configure, since no existing
+ticket cache is required, but requires PKINIT be available and configured
+and that the local realm support anonymous authentication. If both
+\&\fIfast_ccache\fR and \fIanon_fast\fR are set, the ticket cache named by
+\&\fIfast_ccache\fR will be tried first, and the Kerberos PAM module will fall
+back on attempting anonymous PKINIT if that cache could not be used.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups.
+.IP forwardable 4
+.IX Item "forwardable"
+[1.0] Obtain forwardable tickets. If set (to either true or false,
+although it can only be set to false in \fIkrb5.conf\fR), this overrides the
+Kerberos library default set in the [libdefaults] section of \fIkrb5.conf\fR.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP keytab=<path> 4
+.IX Item "keytab=<path>"
+[3.0] Specifies the keytab to use when validating the user's credentials.
+The default is the default system keytab (normally \fI/etc/krb5.keytab\fR),
+which is usually only readable by root. Applications not running as root
+that use this PAM module for authentication may wish to point it to
+another keytab the application can read. The first principal found in the
+keytab will be used as the principal for credential verification.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP realm=<realm> 4
+.IX Item "realm=<realm>"
+[2.2] Set the default Kerberos realm and obtain credentials in that realm,
+rather than in the normal default realm for this system. If this option
+is used, it should be set for all groups being used for consistent
+results. This setting will affect authorization decisions since it
+changes the default realm. This setting will also change the service
+principal used to verify the obtained credentials to be in the specified
+realm.
+.Sp
+If you only want to set the realm assumed for user principals without
+changing the realm for authorization decisions or the service principal
+used to verify credentials, see the \fIuser_realm\fR option.
+.IP renew_lifetime=<lifetime> 4
+.IX Item "renew_lifetime=<lifetime>"
+[2.0] Obtain renewable tickets with a maximum renewable lifetime of
+<lifetime>. <lifetime> should be a Kerberos lifetime string such as
+\&\f(CW\*(C`2d4h10m\*(C'\fR or a time in minutes. If set, this overrides the Kerberos
+library default set in the [libdefaults] section of \fIkrb5.conf\fR.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP ticket_lifetime=<lifetime> 4
+.IX Item "ticket_lifetime=<lifetime>"
+[3.0] Obtain tickets with a maximum lifetime of <lifetime>. <lifetime>
+should be a Kerberos lifetime string such as \f(CW\*(C`2d4h10m\*(C'\fR or a time in
+minutes. If set, this overrides the Kerberos library default set in the
+[libdefaults] section of \fIkrb5.conf\fR.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP user_realm 4
+.IX Item "user_realm"
+[4.6] Obtain credentials in the specified realm rather than in the default
+realm for this system. If this option is used, it should be set for all
+groups being used for consistent results (although the account group
+currently doesn't care about realm). This will not change authorization
+decisions. If the obtained credentials are supposed to allow access to a
+shell account, the user will need an appropriate \fI.k5login\fR file entry or
+the system will have to have a custom aname_to_localname mapping.
+.SS "PAM Behavior"
+.IX Subsection "PAM Behavior"
+.IP clear_on_fail 4
+.IX Item "clear_on_fail"
+[3.9] When changing passwords, PAM first does a preliminary check through
+the complete password stack, and then calls each module again to do the
+password change. After that preliminary check, the order of module
+invocation is fixed. This means that even if the Kerberos password change
+fails (or if one of the other password changes in the stack fails), other
+password PAM modules in the stack will still be called even if the failing
+module is marked required or requisite. When using multiple password PAM
+modules to synchronize passwords between multiple systems when they
+change, this behavior can cause unwanted differences between the
+environments.
+.Sp
+Setting this option provides a way to work around this behavior. If this
+option is set and a Kerberos password change is attempted and fails (due
+to network errors or password strength checking on the KDC, for example),
+this module will clear the stored password in the PAM stack. This will
+force any subsequent modules that have \fIuse_authtok\fR set to fail so that
+those environments won't get out of sync with the password in Kerberos.
+The Kerberos PAM module will not meddle with the stored password if it
+skips the user due to configuration such as minimum_uid.
+.Sp
+Unfortunately, setting this option interferes with other desirable PAM
+configurations, such as attempting to change the password in Kerberos
+first and falling back on the local Unix password database if that fails.
+It therefore isn't the default. Turn it on (and list pam_krb5 first after
+pam_cracklib if used) when synchronizing passwords between multiple
+environments.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the password group.
+.IP debug 4
+.IX Item "debug"
+[1.0] Log more verbose trace and debugging information to syslog at
+LOG_DEBUG priority, including entry and exit from each of the external PAM
+interfaces (except pam_close_session).
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR.
+.IP defer_pwchange 4
+.IX Item "defer_pwchange"
+[3.11] By default, pam\-krb5 lets the Kerberos library handle prompting for
+a password change if an account's password is expired during the auth
+group. If this fails, \fBpam_authenticate()\fR returns an error.
+.Sp
+According to the PAM standard, this is not the correct way to handle
+expired passwords. Instead, \fBpam_authenticate()\fR should return success
+without attempting a password change, and then \fBpam_acct_mgmt()\fR should
+return PAM_NEW_AUTHTOK_REQD, at which point the calling application is
+responsible for either rejecting the authentication or calling
+\&\fBpam_chauthtok()\fR. However, following the standard requires that all
+applications call \fBpam_acct_mgmt()\fR and check its return status; otherwise,
+expired accounts may be able to successfully authenticate. Many
+applications do not do this.
+.Sp
+If this option is set, pam\-krb5 uses the fully correct PAM mechanism for
+handling expired accounts instead of failing in \fBpam_authenticate()\fR. Due
+to the security risk of widespread broken applications, be very careful
+about enabling this option. It should normally only be turned on to solve
+a specific problem (such as using Solaris Kerberos libraries that don't
+support prompting for password changes during authentication), and then
+only for specific applications known to call \fBpam_acct_mgmt()\fR and check its
+return status properly.
+.Sp
+This option is only supported when pam\-krb5 is built with MIT Kerberos.
+If built against Heimdal, this option does nothing and normal expired
+password change handling still happens. (Heimdal is missing the required
+API to implement this option, at least as of version 1.6.)
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP fail_pwchange 4
+.IX Item "fail_pwchange"
+[4.2] By default, pam\-krb5 lets the Kerberos library handle prompting for
+a password change if an account's password is expired during the auth
+group. If this option is set, expired passwords are instead treated as an
+authentication failure identical to an incorrect password. Also see
+\&\fIdefer_pwchange\fR and \fIforce_pwchange\fR.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP force_pwchange 4
+.IX Item "force_pwchange"
+[3.11] If this option is set and authentication fails with a Kerberos
+error indicating the user's password is expired, attempt to immediately
+change their password during the authenticate step. Under normal
+circumstances, this is unnecessary. Most Kerberos libraries will do this
+for you, and setting this option will prompt the user twice to change
+their password if the first attempt (done by the Kerberos library) fails.
+However, some system Kerberos libraries (such as Solaris's) have password
+change prompting disabled in the Kerberos library; on those systems, you
+can set this option to simulate the normal library behavior.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP no_update_user 4
+.IX Item "no_update_user"
+[4.7] Normally, if pam\-krb5 is able to canonicalize the principal to a
+local name using \fBkrb5_aname_to_localname()\fR or similar calls, it changes
+the PAM_USER variable for this PAM session to the canonicalized local
+name. Setting this option disables this behavior and leaves PAM_USER set
+to the initial authentication identity.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP silent 4
+.IX Item "silent"
+[1.0] Don't show messages and errors from Kerberos, such as warnings of
+expiring passwords, to the user via the prompter. This is equivalent to
+the behavior when the application passes in PAM_SILENT, but can be set in
+the PAM configuration.
+.Sp
+This option is only applicable to the auth and password groups.
+.IP trace=<log\-file> 4
+.IX Item "trace=<log-file>"
+[4.6] Enables Kerberos library trace logging to the specified log file if
+it is supported by the Kerberos library. This is intended for temporary
+debugging. The specified file will be appended to without further
+security checks, so do not specify a file in a publicly writable directory
+like \fI/tmp\fR.
+.SS PKINIT
+.IX Subsection "PKINIT"
+.IP pkinit_anchors=<anchors> 4
+.IX Item "pkinit_anchors=<anchors>"
+[3.0] When doing PKINIT authentication, use <anchors> as the client trust
+anchors. This is normally a reference to a file containing the trusted
+certificate authorities. This option is only used if \fItry_pkinit\fR or
+\&\fIuse_pkinit\fR are set.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups.
+.IP pkinit_prompt 4
+.IX Item "pkinit_prompt"
+[3.0] Before attempting PKINIT authentication, prompt the user to insert a
+smart card. You may want to set this option for programs such as
+\&\fBgnome-screensaver\fR that call PAM as soon as the mouse is touched and
+don't give the user an opportunity to enter the smart card first. Any
+information entered at the first prompt is ignored. If \fItry_pkinit\fR is
+set, a user who wishes to use a password instead can just press Enter and
+then enter their password as normal. This option is only used if
+\&\fItry_pkinit\fR or \fIuse_pkinit\fR are set.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups.
+.IP pkinit_user=<userid> 4
+.IX Item "pkinit_user=<userid>"
+[3.0] When doing PKINIT authentication, use <userid> as the user ID. The
+value of this string is highly dependent on the type of PKINIT
+implementation you're using, but will generally be something like:
+.Sp
+.Vb 1
+\& PKCS11:/usr/lib/pkcs11/lib/soft\-pkcs11.so
+.Ve
+.Sp
+to specify the module to use with a smart card. It may also point to a
+user certificate or to other types of user IDs. See the Kerberos library
+documentation for more details. This option is only used if \fItry_pkinit\fR
+or \fIuse_pkinit\fR are set.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups.
+.IP preauth_opt=<option> 4
+.IX Item "preauth_opt=<option>"
+[3.3] Sets a preauth option (currently only applicable when built with MIT
+Kerberos). <option> is either a key/value pair with the key separated
+from the value by \f(CW\*(C`=\*(C'\fR or a boolean option (in which case it's turned on).
+In \fIkrb5.conf\fR, multiple options should be separated by whitespace. In
+the PAM configuration, this option can be given multiple times to set
+multiple options. In either case, <option> may not contain whitespace.
+.Sp
+The primary use of this option, at least in the near future, will be to
+set options for the MIT Kerberos PKINIT support. For the full list of
+possible options, see the PKINIT plugin documentation. At the time of
+this writing, \f(CW\*(C`X509_user_identity\*(C'\fR is equivalent to \fIpkinit_user\fR and
+\&\f(CW\*(C`X509_anchors\*(C'\fR is equivalent to \fIpkinit_anchors\fR. \f(CW\*(C`flag_DSA_PROTOCOL\*(C'\fR
+can only be set via this option.
+.Sp
+Any settings made with this option are applied after the \fIpkinit_anchors\fR
+and \fIpkinit_user\fR options, so if an equivalent setting is made via
+\&\fIpreauth_opt\fR, it will probably override the other setting.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups. Note that there is no way to
+remove a setting made in \fIkrb5.conf\fR using the PAM configuration, but
+options set in the PAM configuration are applied after options set in
+\&\fIkrb5.conf\fR and therefore may override earlier settings.
+.IP try_pkinit 4
+.IX Item "try_pkinit"
+[3.0] Attempt PKINIT authentication before trying a regular password. You
+will probably also need to set the \fIpkinit_user\fR configuration option.
+If PKINIT fails, the PAM module will fall back on regular password
+authentication. This option is currently only supported if pam\-krb5 was
+built against Heimdal 0.8rc1 or later or MIT Kerberos 1.6.3 or later.
+.Sp
+If this option is set and pam\-krb5 is built against MIT Kerberos, and
+PKINIT fails and the module falls back to password authentication, the
+user's password will not be stored in the PAM stack for subsequent
+modules. This is a bug in the interaction between the module and MIT
+Kerberos that requires some reworking of the PKINIT authentication method
+to fix.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups.
+.IP use_pkinit 4
+.IX Item "use_pkinit"
+[3.0, 4.9 for MIT Kerberos] Require PKINIT authentication. You will
+probably also need to set the \fIpkinit_user\fR configuration option. If
+PKINIT fails, authentication will fail. This option is only supported if
+pam\-krb5 was built against Heimdal 0.8rc1 or later or MIT Kerberos 1.12 or
+later.
+.Sp
+Be aware that, with MIT Kerberos, this option is implemented by using a
+responder without a prompter, and thus any informational messages from the
+Kerberos libraries or KDC during authentication will not be displayed.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups.
+.SS Prompting
+.IX Subsection "Prompting"
+.IP banner=<banner> 4
+.IX Item "banner=<banner>"
+[3.0] By default, the prompts when a user changes their password are:
+.Sp
+.Vb 3
+\& Current Kerberos password:
+\& Enter new Kerberos password:
+\& Retype new Kerberos password:
+.Ve
+.Sp
+The string "Kerberos" is inserted so that users aren't confused about
+which password they're changing. Setting this option replaces the word
+"Kerberos" with whatever this option is set to. Setting this option to
+the empty string removes the word before "password:" entirely.
+.Sp
+If set in the PAM configuration, <banner> may not contain whitespace. If
+you want a value containing whitespace, set it in \fIkrb5.conf\fR.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the password group.
+.IP expose_account 4
+.IX Item "expose_account"
+[3.0] By default, the Kerberos PAM module password prompt is simply
+"Password:". This avoids leaking any information about the system realm
+or account to principal conversions. If this option is set, the string
+"for <principal>" is added before the colon, where <principal> is the
+user's principal. This string is also added before the colon on prompts
+when changing the user's password.
+.Sp
+Enabling this option with ChallengeResponseAuthentication enabled in
+OpenSSH may cause problems for some ssh clients that only recognize
+"Password:" as a prompt. This option is automatically disabled if
+\&\fIsearch_k5login\fR is enabled since the principal displayed would be
+inaccurate.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups.
+.IP force_first_pass 4
+.IX Item "force_first_pass"
+[4.0] Use the password obtained by a previous authentication or password
+module to authenticate the user without prompting the user again. If no
+previous module obtained the user's password, fail without prompting the
+user. Also see \fItry_first_pass\fR and \fIuse_first_pass\fR for weaker
+versions of this option.
+.Sp
+This option is only applicable to the auth and password groups. For the
+password group, it applies only to the old password. See \fIuse_authtok\fR
+for a similar setting for the new password.
+.IP no_prompt 4
+.IX Item "no_prompt"
+[4.6] Never prompt for the current password. Instead, pass in a NULL
+password to the Kerberos library and let the Kerberos library do the
+prompting. This may be needed if, for example, the Kerberos library is
+configured to use other authentication mechanisms than passwords and needs
+full control over the prompting process.
+.Sp
+The major disadvantage of this option is that it means the PAM module will
+never see the user's password and therefore cannot save it in the PAM
+module data for any subsequent modules. In other words, this option
+cannot be used if another module is in the stack behind the Kerberos PAM
+module and wants to use \fIuse_first_pass\fR. The Kerberos library also
+usually includes the principal in the prompt, and therefore this option
+implies behavior similar to \fIexpose_account\fR. Similar to
+\&\fIexpose_account\fR, this can cause problems with OpenSSH if
+ChallengeResponseAuthentication is enabled, since clients may not
+recognize password prompts other than "Password:".
+.Sp
+Using this option with \fIsearch_k5login\fR would result in a password prompt
+for every principal listed in the user's \fI.k5login\fR file. This is
+probably not desired behavior, although it's not prohibited by the module.
+.Sp
+This option is only applicable to the auth and password groups. For the
+password group, it applies only to the authentication process; the user
+will still be prompted for a new password.
+.IP prompt_principal 4
+.IX Item "prompt_principal"
+[3.6] Before prompting for the user's password (or using the previously
+entered password, if \fItry_first_pass\fR, \fIuse_first_pass\fR, or
+\&\fIforce_first_pass\fR are set), prompt the user for the Kerberos principal
+to use for authentication. This allows the user to authenticate with a
+different principal than the one corresponding to the local username,
+provided that either a \fI.k5login\fR file or local Kerberos principal to
+account mapping authorize that principal to access the local account.
+.Sp
+Be cautious when using this configuration option and don't use it with
+OpenSSH PasswordAuthentication, only ChallengeResponseAuthentication.
+Some PAM-enabled applications expect PAM modules to only prompt for
+passwords and may even blindly give the password to the first prompt, no
+matter what it is. Such applications, in combination with this option,
+may expose the user's password in log messages and Kerberos requests.
+.IP try_first_pass 4
+.IX Item "try_first_pass"
+[1.0] If the authentication module isn't the first on the stack, and a
+previous module obtained the user's password, use that password to
+authenticate the user without prompting them again. If that
+authentication fails, fall back on prompting the user for their password.
+This option has no effect if the authentication module is first in the
+stack or if no previous module obtained the user's password. Also see
+\&\fIuse_first_pass\fR and \fIforce_first_pass\fR for stronger versions of this
+option.
+.Sp
+This option is only applicable to the auth and password groups. For the
+password group, it applies only to the old password.
+.IP use_authtok 4
+.IX Item "use_authtok"
+[4.0] Use the new password obtained by a previous password module when
+changing passwords rather than prompting for the new password. If the new
+password isn't available, fail. This can be used to require passwords be
+checked by another, prior module, such as \fBpam_cracklib\fR.
+.Sp
+This option is only applicable to the password group.
+.IP use_first_pass 4
+.IX Item "use_first_pass"
+[1.0] Use the password obtained by a previous authentication module to
+authenticate the user without prompting the user again. If no previous
+module obtained the user's password for either an authentication or
+password change, fall back on prompting the user. If a previous module
+did obtain the user's password but authentication with that password
+fails, fail without further prompting the user. Also see
+\&\fItry_first_pass\fR and \fIforce_first_pass\fR for other versions of this
+option.
+.Sp
+This option is only applicable to the auth and password groups. For the
+password group, it applies only to the old password. See \fIuse_authtok\fR
+for a similar setting for the new password.
+.SS "Ticket Caches"
+.IX Subsection "Ticket Caches"
+.IP ccache=<pattern> 4
+.IX Item "ccache=<pattern>"
+[2.0] Use <pattern> as the pattern for creating credential cache names.
+<pattern> must be in the form <type>:<residual> where <type> and the
+following colon are optional if a file cache should be used. The special
+token \f(CW%u\fR, anywhere in <pattern>, is replaced with the user's numeric
+UID. The special token \f(CW%p\fR, anywhere in <pattern>, is replaced with the
+current process ID.
+.Sp
+If <pattern> ends in the literal string \f(CW\*(C`XXXXXX\*(C'\fR (six X's), that string
+will be replaced by randomly generated characters and the ticket cache
+will be created using \fBmkstemp\fR\|(3). This is strongly recommended if
+<pattern> points to a world-writable directory.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and session groups.
+.IP ccache_dir=<directory> 4
+.IX Item "ccache_dir=<directory>"
+[1.2] Store both the temporary ticket cache used during authentication and
+user ticket caches in <directory> instead of in \fI/tmp\fR. The algorithm
+for generating the ticket cache name is otherwise unchanged. <directory>
+may be prefixed with \f(CW\*(C`FILE:\*(C'\fR to make the cache type unambiguous (and this
+may be required on systems that use a cache type other than file as the
+default).
+.Sp
+Be aware that pam_krb5 creates and stores a temporary ticket cache file
+owned by root during the login process. If you set \fIccache\fR above to
+avoid using the system \fI/tmp\fR directory for user ticket caches, you may
+also want to set \fIccache_dir\fR to move those temporary caches to some
+other location. This will allow pam_krb5 to continue working even if the
+system \fI/tmp\fR directory is full.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and session groups.
+.IP no_ccache 4
+.IX Item "no_ccache"
+[1.0] Do not create a ticket cache after authentication. This option
+shouldn't be set in general, but is useful as part of the PAM
+configuration for a particular service that uses PAM for authentication
+but isn't creating user sessions and doesn't want the overhead of ever
+writing the user credentials to disk. When using this option, the
+application should only call \fBpam_authenticate()\fR; other functions like
+\&\fBpam_setcred()\fR, \fBpam_start_session()\fR, and \fBpam_acct_mgmt()\fR don't make sense
+with this option. Don't use this option if the application needs PAM
+account and session management calls.
+.Sp
+This option is only applicable to the auth group.
+.IP retain_after_close 4
+.IX Item "retain_after_close"
+[2.3] Normally, the user's ticket cache is destroyed when either \fBpam_end()\fR
+or \fBpam_close_session()\fR is called by the authenticating application so that
+ticket caches aren't left behind after the user logs out. In some cases,
+however, this isn't desirable. (On Solaris 8, for instance, the default
+behavior means login will destroy the ticket cache before running the
+user's shell.) If this option is set, the PAM module will never destroy
+the user's ticket cache. If you set this, you may want to call
+\&\fBkdestroy\fR in the shell's logout configuration or run a temporary file
+removal program to avoid accumulating hundreds of ticket caches in
+\&\fI/tmp\fR.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and session groups.
+.SH ENVIRONMENT
+.IX Header "ENVIRONMENT"
+.IP KRB5CCNAME 4
+.IX Item "KRB5CCNAME"
+Set by \fBpam_setcred()\fR with the PAM_ESTABLISH_CRED option, and therefore
+also by \fBpam_open_session()\fR, to point to the new credential cache for the
+user. See the \fIccache\fR and \fIccache_dir\fR options. By default, the cache
+name will be prefixed with \f(CW\*(C`FILE:\*(C'\fR to make the cache type unambiguous.
+.IP PAM_KRB5CCNAME 4
+.IX Item "PAM_KRB5CCNAME"
+Set by \fBpam_authenticate()\fR to point to the temporary ticket cache used for
+authentication (unless the \fIno_ccache\fR option was given). \fBpam_setcred()\fR
+then uses that environment variable to locate the temporary cache even if
+it was not called in the same PAM session as \fBpam_authenticate()\fR (a problem
+with \fBsshd\fR running in some modes). This environment variable is only
+used internal to the PAM module.
+.SH FILES
+.IX Header "FILES"
+.IP \fI/tmp/krb5cc_UID_RANDOM\fR 4
+.IX Item "/tmp/krb5cc_UID_RANDOM"
+The default credential cache name. UID is the decimal UID of the local
+user and RANDOM is a random six-character string. The pattern may be
+changed with the \fIccache\fR option and the directory with the \fIccache_dir\fR
+option.
+.IP \fI/tmp/krb5cc_pam_RANDOM\fR 4
+.IX Item "/tmp/krb5cc_pam_RANDOM"
+The credential cache name used for the temporary credential cache created
+by \fBpam_authenticate()\fR. This cache is removed again when the PAM session
+is ended or when \fBpam_setcred()\fR is called and will normally not be
+user-visible. RANDOM is a random six-character string.
+.IP \fI~/.k5login\fR 4
+.IX Item "~/.k5login"
+File containing Kerberos principals that are allowed access to that
+account.
+.SH BUGS
+.IX Header "BUGS"
+If \fItry_pkinit\fR is set and pam\-krb5 is built with MIT Kerberos, the
+user's password is not saved in the PAM data if PKINIT fails and the
+module falls back to password authentication.
+.SH CAVEATS
+.IX Header "CAVEATS"
+Be sure to list this module in the session group as well as the auth group
+when using it for interactive logins. Otherwise, some applications (such
+as OpenSSH) will not set up the user's ticket cache correctly.
+.PP
+The Kerberos library, via pam\-krb5, will prompt the user to change their
+password if their password is expired, but when using OpenSSH, this will
+only work when ChallengeResponseAuthentication is enabled. Unless this
+option is enabled, OpenSSH doesn't pass PAM messages to the user and can
+only respond to a simple password prompt.
+.PP
+If you are using MIT Kerberos, be aware that users whose passwords are
+expired will not be prompted to change their password unless the KDC
+configuration for your realm in [realms] in krb5.conf contains a
+master_kdc setting or, if using DNS SRV records, you have a DNS entry for
+_kerberos\-master as well as _kerberos.
+.PP
+\&\fBpam_authenticate()\fR returns failure when called for an ignored account,
+requiring the system administrator to use \f(CW\*(C`optional\*(C'\fR or \f(CW\*(C`sufficient\*(C'\fR to
+ignore the module and move on to the next module. It's arguably more
+correct to return PAM_IGNORE, which causes the module to be ignored as if
+it weren't in the configuration, but this increases the risk of
+inadvertent security holes when listing pam\-krb5 as the only
+authentication module.
+.PP
+This module treats the empty password as an authentication failure
+rather than attempting to use that password to avoid unwanted prompting
+behavior in the Kerberos libraries. If you have a Kerberos principal that
+intentionally has an empty password, it won't work with this module.
+.PP
+This module will not refresh an existing ticket cache if called with an
+effective UID or GID different than the real UID or GID, since refreshing
+an existing ticket cache requires trusting the KRB5CCNAME environment
+variable and the environment should not be trusted in a setuid context.
+.PP
+Old versions of OpenSSH are known to call pam_authenticate followed by
+pam_setcred(PAM_REINITIALIZE_CRED) without first calling pam_open_session,
+thereby requesting that an existing ticket cache be renewed (similar to
+what a screensaver would want) rather than requesting a new ticket cache
+be created. Since this behavior is indistinguishable at the PAM level
+from a screensaver, pam\-krb5 when used with these old versions of OpenSSH
+will refresh the ticket cache of the OpenSSH daemon rather than setting up
+a new ticket cache for the user. The resulting ticket cache will have the
+correct permissions, but will not be named correctly or referenced in the
+user's environment and will be overwritten by the next user login. The
+best solution to this problem is to upgrade OpenSSH. I'm not sure exactly
+when this problem was fixed, but at the very least OpenSSH 4.3 and later
+do not exhibit it.
+.SH AUTHOR
+.IX Header "AUTHOR"
+pam\-krb5 was originally written by Frank Cusack. Andres Salomon made
+extensive modifications, and then Russ Allbery <eagle@eyrie.org> adopted
+it and made even more extensive modifications. Russ Allbery currently
+maintains the module.
+.SH "COPYRIGHT AND LICENSE"
+.IX Header "COPYRIGHT AND LICENSE"
+Copyright 2005\-2010, 2014, 2020 Russ Allbery <eagle@eyrie.org>
+.PP
+Copyright 2008\-2014 The Board of Trustees of the Leland Stanford Junior
+University
+.PP
+Copying and distribution of this file, with or without modification, are
+permitted in any medium without royalty provided the copyright notice and
+this notice are preserved. This file is offered as-is, without any
+warranty.
+.PP
+SPDX-License-Identifier: FSFAP
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+\&\fBkadmin\fR\|(8), \fBkdestroy\fR\|(1), \fBkrb5.conf\fR\|(5), \fBpam\fR\|(7), \fBpasswd\fR\|(1), \fBsyslog\fR\|(3)
+.PP
+The current version of this module is available from its web page at
+<https://www.eyrie.org/~eagle/software/pam\-krb5/>.
diff --git a/lib/libpam/modules/pam_krb5/pam_krb5.8 b/lib/libpam/modules/pam_krb5/pam_krb5.8
new file mode 100644
index 000000000000..7c1770961272
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam_krb5.8
@@ -0,0 +1,235 @@
+.\"
+.\" $Id: pam_krb5.5,v 1.5 2000/01/05 00:59:56 fcusack Exp $
+.Dd May 3, 2010
+.Dt PAM_KRB5 8
+.Os
+.Sh NAME
+.Nm pam_krb5
+.Nd Kerberos 5 PAM module
+.Sh SYNOPSIS
+.Pa /usr/lib/pam_krb5.so
+.Sh DESCRIPTION
+The Kerberos 5 service module for PAM, typically
+.Pa /usr/lib/pam_krb5.so ,
+provides functionality for three PAM categories:
+authentication,
+account management,
+and password management.
+It also provides null functions for session management.
+The
+.Pa pam_krb5.so
+module is a shared object
+that can be dynamically loaded to provide
+the necessary functionality upon demand.
+Its path is specified in the
+PAM configuration file.
+.Ss Kerberos 5 Authentication Module
+The Kerberos 5 authentication component
+provides functions to verify the identity of a user
+.Pq Fn pam_sm_authenticate
+and to set user specific credentials
+.Pq Fn pam_sm_setcred .
+.Fn pam_sm_authenticate
+converts the supplied username into a Kerberos principal,
+by appending the default local realm name.
+It also supports usernames with explicit realm names.
+If a realm name is supplied, then upon a successful return, it
+changes the username by mapping the principal name into a local username
+(calling
+.Fn krb5_aname_to_localname ) .
+This typically just means
+the realm name is stripped.
+.Pp
+It prompts the user for a password and obtains a new Kerberos TGT for
+the principal.
+The TGT is verified by obtaining a service
+ticket for the local host.
+.Pp
+When prompting for the current password, the authentication
+module will use the prompt
+.Dq Li "Password for <principal>:" .
+.Pp
+The
+.Fn pam_sm_setcred
+function stores the newly acquired credentials in a credentials cache,
+and sets the environment variable
+.Ev KRB5CCNAME
+appropriately.
+The credentials cache should be destroyed by the user at logout with
+.Xr kdestroy 1 .
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include
+reasons why the user's
+authentication attempt was declined.
+.It Cm use_first_pass
+If the authentication module is not the first in the stack,
+and a previous module obtained the user's password, that password is
+used to authenticate the user.
+If this fails, the authentication
+module returns failure without prompting the user for a password.
+This option has no effect if the authentication module is
+the first in the stack, or if no previous modules obtained the
+user's password.
+.It Cm try_first_pass
+This option is similar to the
+.Cm use_first_pass
+option, except that if the previously obtained password fails, the
+user is prompted for another password.
+.It Cm forwardable
+Obtain forwardable Kerberos credentials for the user.
+.It Cm no_ccache
+Do not save the obtained credentials in a credentials cache.
+This is a
+useful option if the authentication module is used for services such
+as ftp or pop, where the user would not be able to destroy them.
+[This
+is not a recommendation to use the module for those services.]
+.It Cm ccache Ns = Ns Ar name
+Use
+.Ar name
+as the credentials cache.
+.Ar name
+must be in the form
+.Ar type : Ns Ar residual .
+The special tokens
+.Ql %u ,
+to designate the decimal UID of the user;
+and
+.Ql %p ,
+to designate the current process ID; can be used in
+.Ar name .
+.It Cm allow_kdc_spoof
+Allow
+.Nm
+to succeed even if there is no host or service key available in a
+keytab to authenticate the Kerberos KDC's ticket.
+If there is no such key, for example on a host with no keytabs,
+.Nm
+will fail immediately without prompting the user.
+.Pp
+.Sy Warning :
+If the host has not been configured with a keytab from the KDC, setting
+this option makes it vulnerable to malicious KDCs, e.g. via DNS
+flooding, because
+.Nm
+has no way to distinguish the legitimate KDC from a spoofed KDC.
+.It Cm no_user_check
+Do not verify if a user exists on the local system. This option implies the
+.Cm no_ccache
+option because there is no secure local uid/gid for the cache file.
+.El
+.Ss Kerberos 5 Account Management Module
+The Kerberos 5 account management component
+provides a function to perform account management,
+.Fn pam_sm_acct_mgmt .
+The function verifies that the authenticated principal is allowed
+to login to the local user account by calling
+.Fn krb5_kuserok
+(which checks the user's
+.Pa .k5login
+file).
+.Ss Kerberos 5 Password Management Module
+The Kerberos 5 password management component
+provides a function to change passwords
+.Pq Fn pam_sm_chauthtok .
+The username supplied (the
+user running the
+.Xr passwd 1
+command, or the username given as an argument) is mapped into
+a Kerberos principal name, using the same technique as in
+the authentication module.
+Note that if a realm name was
+explicitly supplied during authentication, but not during
+a password change, the mapping
+done by the password management module may not result in the
+same principal as was used for authentication.
+.Pp
+Unlike when
+changing a
+.Ux
+password, the password management module will
+allow any user to change any principal's password (if the user knows
+the principal's old password, of course).
+Also unlike
+.Ux ,
+root
+is always prompted for the principal's old password.
+.Pp
+The password management module uses the same heuristics as
+.Xr kpasswd 1
+to determine how to contact the Kerberos password server.
+.Pp
+The following options may be passed to the password management
+module:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm use_first_pass
+If the password management module is not the first in the stack,
+and a previous module obtained the user's old password, that password is
+used to authenticate the user.
+If this fails, the password
+management
+module returns failure without prompting the user for the old password.
+If successful, the new password entered to the previous module is also
+used as the new Kerberos password.
+If the new password fails,
+the password management module returns failure without
+prompting the user for a new password.
+.It Cm try_first_pass
+This option is similar to the
+.Cm use_first_pass
+option, except that if the previously obtained old or new passwords fail,
+the user is prompted for them.
+.El
+.Ss Kerberos 5 Session Management Module
+The Kerberos 5 session management component
+provides functions to initiate
+.Pq Fn pam_sm_open_session
+and terminate
+.Pq Fn pam_sm_close_session
+sessions.
+Since session management is not defined under Kerberos 5,
+both of these functions simply return success.
+They are provided
+only because of the naming conventions for PAM modules.
+.Sh ENVIRONMENT
+.Bl -tag -width "KRB5CCNAME"
+.It Ev KRB5CCNAME
+Location of the credentials cache.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /tmp/krb5cc_ Ns Ar uid" -compact
+.It Pa /tmp/krb5cc_ Ns Ar uid
+default credentials cache
+.Ar ( uid
+is the decimal UID of the user).
+.It Pa $HOME/.k5login
+file containing Kerberos principals that are allowed access.
+.El
+.Sh SEE ALSO
+.Xr kdestroy 1 ,
+.Xr passwd 1 ,
+.Xr pam 3 ,
+.Xr syslog 3 ,
+.Xr pam.conf 5
+.Sh NOTES
+Applications should not call
+.Fn pam_authenticate
+more than once between calls to
+.Fn pam_start
+and
+.Fn pam_end
+when using the Kerberos 5 PAM module.
diff --git a/lib/libpam/modules/pam_krb5/pam_krb5.c b/lib/libpam/modules/pam_krb5/pam_krb5.c
new file mode 100644
index 000000000000..e13c1b794d5b
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam_krb5.c
@@ -0,0 +1,1076 @@
+/*-
+ * This pam_krb5 module contains code that is:
+ * Copyright (c) Derrick J. Brashear, 1996. All rights reserved.
+ * Copyright (c) Frank Cusack, 1999-2001. All rights reserved.
+ * Copyright (c) Jacques A. Vidrine, 2000-2001. All rights reserved.
+ * Copyright (c) Nicolas Williams, 2001. All rights reserved.
+ * Copyright (c) Perot Systems Corporation, 2001. All rights reserved.
+ * Copyright (c) Mark R V Murray, 2001. All rights reserved.
+ * Copyright (c) Networks Associates Technology, Inc., 2002-2005.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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
+ * notices, 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 <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <krb5.h>
+#include <com_err.h>
+#ifdef MK_MITKRB5
+/* For MIT KRB5 only. */
+#include <k5-int.h>
+#endif
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_PASSWORD
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+#include <security/openpam.h>
+
+#define COMPAT_HEIMDAL
+/* #define COMPAT_MIT */
+
+static int verify_krb_v5_tgt_begin(krb5_context, char *, int,
+ const char **, krb5_principal *, char[static BUFSIZ]);
+static int verify_krb_v5_tgt(krb5_context, krb5_ccache, char *, int,
+ const char *, krb5_principal, char[static BUFSIZ]);
+static void verify_krb_v5_tgt_cleanup(krb5_context, int,
+ const char *, krb5_principal, char[static BUFSIZ]);
+static void cleanup_cache(pam_handle_t *, void *, int);
+static const char *compat_princ_component(krb5_context, krb5_principal, int);
+static void compat_free_data_contents(krb5_context, krb5_data *);
+
+#define USER_PROMPT "Username: "
+#define PASSWORD_PROMPT "Password:"
+#define NEW_PASSWORD_PROMPT "New Password:"
+
+#define PAM_OPT_CCACHE "ccache"
+#define PAM_OPT_DEBUG "debug"
+#define PAM_OPT_FORWARDABLE "forwardable"
+#define PAM_OPT_NO_CCACHE "no_ccache"
+#define PAM_OPT_NO_USER_CHECK "no_user_check"
+#define PAM_OPT_REUSE_CCACHE "reuse_ccache"
+#define PAM_OPT_NO_USER_CHECK "no_user_check"
+#define PAM_OPT_ALLOW_KDC_SPOOF "allow_kdc_spoof"
+
+#define PAM_LOG_KRB5_ERR(ctx, rv, fmt, ...) \
+ do { \
+ const char *krb5msg = krb5_get_error_message(ctx, rv); \
+ PAM_LOG(fmt ": %s", ##__VA_ARGS__, krb5msg); \
+ krb5_free_error_message(ctx, krb5msg); \
+ } while (0)
+
+/*
+ * authentication management
+ */
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ krb5_error_code krbret;
+ krb5_context krbctx;
+ int debug;
+ const char *auth_service;
+ krb5_principal auth_princ;
+ char auth_phost[BUFSIZ];
+ krb5_creds creds;
+ krb5_principal princ;
+ krb5_ccache ccache;
+ krb5_get_init_creds_opt *opts;
+ struct passwd *pwd;
+ int retval;
+ const void *ccache_data;
+ const char *user, *pass;
+ const void *sourceuser, *service;
+ char *principal, *princ_name, *ccache_name, luser[32], *srvdup;
+
+ retval = pam_get_user(pamh, &user, USER_PROMPT);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Got user: %s", user);
+
+ retval = pam_get_item(pamh, PAM_RUSER, &sourceuser);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Got ruser: %s", (const char *)sourceuser);
+
+ service = NULL;
+ pam_get_item(pamh, PAM_SERVICE, &service);
+ if (service == NULL)
+ service = "unknown";
+
+ PAM_LOG("Got service: %s", (const char *)service);
+
+ if ((srvdup = strdup(service)) == NULL) {
+ retval = PAM_BUF_ERR;
+ goto cleanup6;
+ }
+
+ krbret = krb5_init_context(&krbctx);
+ if (krbret != 0) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ retval = PAM_SERVICE_ERR;
+ goto cleanup5;
+ }
+
+ PAM_LOG("Context initialised");
+
+ debug = openpam_get_option(pamh, PAM_OPT_DEBUG) ? 1 : 0;
+ krbret = verify_krb_v5_tgt_begin(krbctx, srvdup, debug,
+ &auth_service, &auth_princ, auth_phost);
+ if (krbret != 0) { /* failed to find key */
+ /* Keytab or service key does not exist */
+ /*
+ * Give up now because we can't authenticate the KDC
+ * with a keytab, unless the administrator asked to
+ * have the traditional behaviour of being vulnerable
+ * to spoofed KDCs.
+ */
+ if (!openpam_get_option(pamh, PAM_OPT_ALLOW_KDC_SPOOF)) {
+ retval = PAM_SERVICE_ERR;
+ goto cleanup4;
+ }
+ }
+
+ krbret = krb5_cc_register(krbctx, &krb5_mcc_ops, FALSE);
+ if (krbret != 0 && krbret != KRB5_CC_TYPE_EXISTS) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ retval = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+
+ PAM_LOG("Done krb5_cc_register()");
+
+ /* Get principal name */
+ if (openpam_get_option(pamh, PAM_OPT_AUTH_AS_SELF))
+ asprintf(&principal, "%s/%s", (const char *)sourceuser, user);
+ else
+ principal = strdup(user);
+
+ PAM_LOG("Created principal: %s", principal);
+
+ krbret = krb5_parse_name(krbctx, principal, &princ);
+ free(principal);
+ if (krbret != 0) {
+ PAM_LOG_KRB5_ERR(krbctx, krbret, "Error krb5_parse_name()");
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ retval = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+
+ PAM_LOG("Done krb5_parse_name()");
+
+ /* Now convert the principal name into something human readable */
+ princ_name = NULL;
+ krbret = krb5_unparse_name(krbctx, princ, &princ_name);
+ if (krbret != 0) {
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_unparse_name()");
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ PAM_LOG("Got principal: %s", princ_name);
+
+ /* Get password */
+ retval = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, PASSWORD_PROMPT);
+ if (retval != PAM_SUCCESS)
+ goto cleanup2;
+
+ PAM_LOG("Got password");
+
+ if (openpam_get_option(pamh, PAM_OPT_NO_USER_CHECK))
+ PAM_LOG("Skipping local user check");
+ else {
+
+ /* Verify the local user exists (AFTER getting the password) */
+ if (strchr(user, '@')) {
+ /* get a local account name for this principal */
+ krbret = krb5_aname_to_localname(krbctx, princ,
+ sizeof(luser), luser);
+ if (krbret != 0) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_aname_to_localname()");
+ retval = PAM_USER_UNKNOWN;
+ goto cleanup2;
+ }
+
+ retval = pam_set_item(pamh, PAM_USER, luser);
+ if (retval != PAM_SUCCESS)
+ goto cleanup2;
+
+ PAM_LOG("PAM_USER Redone");
+ }
+
+ if (!openpam_get_option(pamh, PAM_OPT_NO_USER_CHECK)) {
+ pwd = getpwnam(user);
+ if (pwd == NULL) {
+ retval = PAM_USER_UNKNOWN;
+ goto cleanup2;
+ }
+ }
+
+ PAM_LOG("Done getpwnam()");
+ }
+
+ /* Initialize credentials request options. */
+ krbret = krb5_get_init_creds_opt_alloc(krbctx, &opts);
+ if (krbret != 0) {
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_get_init_creds_opt_alloc()");
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ krb5_get_init_creds_opt_set_default_flags(krbctx,
+ service, NULL, opts);
+
+ if (openpam_get_option(pamh, PAM_OPT_FORWARDABLE))
+ krb5_get_init_creds_opt_set_forwardable(opts, 1);
+
+ PAM_LOG("Credential options initialised");
+
+ /* Get a TGT */
+ memset(&creds, 0, sizeof(krb5_creds));
+ krbret = krb5_get_init_creds_password(krbctx, &creds, princ,
+ pass, NULL, pamh, 0, NULL, opts);
+ krb5_get_init_creds_opt_free(krbctx, opts);
+ if (krbret != 0) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_get_init_creds_password()");
+ retval = PAM_AUTH_ERR;
+ goto cleanup2;
+ }
+
+ PAM_LOG("Got TGT");
+
+ /* Generate a temporary cache */
+ krbret = krb5_cc_new_unique(krbctx, krb5_cc_type_memory, NULL, &ccache);
+ if (krbret != 0) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_cc_new_unique()");
+ retval = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+ krbret = krb5_cc_initialize(krbctx, ccache, princ);
+ if (krbret != 0) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_cc_initialize()");
+ retval = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+ krbret = krb5_cc_store_cred(krbctx, ccache, &creds);
+ if (krbret != 0) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_cc_store_cred()");
+ krb5_cc_destroy(krbctx, ccache);
+ retval = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+
+ PAM_LOG("Credentials stashed");
+
+ /* Verify them */
+ krbret = verify_krb_v5_tgt(krbctx, ccache, srvdup,
+ debug,
+ auth_service, auth_princ, auth_phost);
+ free(srvdup);
+ srvdup = NULL;
+ if (krbret == -1) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ krb5_cc_destroy(krbctx, ccache);
+ retval = PAM_AUTH_ERR;
+ goto cleanup;
+ }
+
+ PAM_LOG("Credentials stash verified");
+
+ retval = pam_get_data(pamh, "ccache", &ccache_data);
+ if (retval == PAM_SUCCESS) {
+ krb5_cc_destroy(krbctx, ccache);
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ retval = PAM_AUTH_ERR;
+ goto cleanup;
+ }
+
+ PAM_LOG("Credentials stash not pre-existing");
+
+ asprintf(&ccache_name, "%s:%s", krb5_cc_get_type(krbctx,
+ ccache), krb5_cc_get_name(krbctx, ccache));
+ if (ccache_name == NULL) {
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ retval = PAM_BUF_ERR;
+ goto cleanup;
+ }
+ retval = pam_set_data(pamh, "ccache", ccache_name, cleanup_cache);
+ if (retval != 0) {
+ krb5_cc_destroy(krbctx, ccache);
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ retval = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+
+ PAM_LOG("Credentials stash saved");
+
+cleanup:
+ krb5_free_cred_contents(krbctx, &creds);
+ PAM_LOG("Done cleanup");
+cleanup2:
+ krb5_free_principal(krbctx, princ);
+ if (princ_name)
+ free(princ_name);
+ PAM_LOG("Done cleanup2");
+
+cleanup3:
+ krb5_free_context(krbctx);
+
+ PAM_LOG("Done cleanup3");
+
+cleanup4:
+ verify_krb_v5_tgt_cleanup(krbctx, debug,
+ auth_service, auth_princ, auth_phost);
+ PAM_LOG("Done cleanup4");
+
+cleanup5:
+ if (srvdup != NULL)
+ free(srvdup);
+ PAM_LOG("Done cleanup5");
+
+cleanup6:
+ if (retval != PAM_SUCCESS)
+ PAM_VERBOSE_ERROR("Kerberos 5 refuses you");
+ PAM_LOG("Done cleanup6");
+
+ return (retval);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh, int flags,
+ int argc __unused, const char *argv[] __unused)
+{
+#ifdef _FREEFALL_CONFIG
+ return (PAM_SUCCESS);
+#else
+
+ krb5_error_code krbret;
+ krb5_context krbctx;
+ krb5_principal princ;
+ krb5_creds creds;
+ krb5_ccache ccache_temp, ccache_perm;
+ krb5_cc_cursor cursor;
+ struct passwd *pwd = NULL;
+ int retval;
+ const char *cache_name, *q;
+ const void *user;
+ const void *cache_data;
+ char *cache_name_buf = NULL, *p;
+
+ uid_t euid;
+ gid_t egid;
+
+ if (flags & PAM_DELETE_CRED)
+ return (PAM_SUCCESS);
+
+ if (flags & PAM_REFRESH_CRED)
+ return (PAM_SUCCESS);
+
+ if (flags & PAM_REINITIALIZE_CRED)
+ return (PAM_SUCCESS);
+
+ if (!(flags & PAM_ESTABLISH_CRED))
+ return (PAM_SERVICE_ERR);
+
+ /* If a persistent cache isn't desired, stop now. */
+ if (openpam_get_option(pamh, PAM_OPT_NO_CCACHE) ||
+ openpam_get_option(pamh, PAM_OPT_NO_USER_CHECK))
+ return (PAM_SUCCESS);
+
+ PAM_LOG("Establishing credentials");
+
+ /* Get username */
+ retval = pam_get_item(pamh, PAM_USER, &user);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Got user: %s", (const char *)user);
+
+ krbret = krb5_init_context(&krbctx);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_init_context() failed");
+ return (PAM_SERVICE_ERR);
+ }
+
+ PAM_LOG("Context initialised");
+
+ euid = geteuid(); /* Usually 0 */
+ egid = getegid();
+
+ PAM_LOG("Got euid, egid: %d %d", euid, egid);
+
+ /* Retrieve the temporary cache */
+ retval = pam_get_data(pamh, "ccache", &cache_data);
+ if (retval != PAM_SUCCESS) {
+ retval = PAM_CRED_UNAVAIL;
+ goto cleanup3;
+ }
+ krbret = krb5_cc_resolve(krbctx, cache_data, &ccache_temp);
+ if (krbret != 0) {
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_cc_resolve(\"%s\")", (const char *)cache_data);
+ retval = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+
+ /* Get the uid. This should exist. */
+ pwd = getpwnam(user);
+ if (pwd == NULL) {
+ retval = PAM_USER_UNKNOWN;
+ goto cleanup3;
+ }
+
+ PAM_LOG("Done getpwnam()");
+
+ /* Avoid following a symlink as root */
+ if (setegid(pwd->pw_gid)) {
+ retval = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+ if (seteuid(pwd->pw_uid)) {
+ retval = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+
+ PAM_LOG("Done setegid() & seteuid()");
+
+ /* Get the cache name */
+ cache_name = openpam_get_option(pamh, PAM_OPT_CCACHE);
+ if (cache_name == NULL) {
+ asprintf(&cache_name_buf, "FILE:/tmp/krb5cc_%d", pwd->pw_uid);
+ cache_name = cache_name_buf;
+ }
+
+ p = calloc(PATH_MAX + 16, sizeof(char));
+ q = cache_name;
+
+ if (p == NULL) {
+ PAM_LOG("Error malloc(): failure");
+ retval = PAM_BUF_ERR;
+ goto cleanup3;
+ }
+ cache_name = p;
+
+ /* convert %u and %p */
+ while (*q) {
+ if (*q == '%') {
+ q++;
+ if (*q == 'u') {
+ sprintf(p, "%d", pwd->pw_uid);
+ p += strlen(p);
+ }
+ else if (*q == 'p') {
+ sprintf(p, "%d", getpid());
+ p += strlen(p);
+ }
+ else {
+ /* Not a special token */
+ *p++ = '%';
+ q--;
+ }
+ q++;
+ }
+ else {
+ *p++ = *q++;
+ }
+ }
+
+ PAM_LOG("Got cache_name: %s", cache_name);
+
+ /* Initialize the new ccache */
+ krbret = krb5_cc_get_principal(krbctx, ccache_temp, &princ);
+ if (krbret != 0) {
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_cc_get_principal()");
+ retval = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+ krbret = krb5_cc_resolve(krbctx, cache_name, &ccache_perm);
+ if (krbret != 0) {
+ PAM_LOG_KRB5_ERR(krbctx, krbret, "Error krb5_cc_resolve()");
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ krbret = krb5_cc_initialize(krbctx, ccache_perm, princ);
+ if (krbret != 0) {
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_cc_initialize()");
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ PAM_LOG("Cache initialised");
+
+ /* Prepare for iteration over creds */
+ krbret = krb5_cc_start_seq_get(krbctx, ccache_temp, &cursor);
+ if (krbret != 0) {
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_cc_start_seq_get()");
+ krb5_cc_destroy(krbctx, ccache_perm);
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ PAM_LOG("Prepared for iteration");
+
+ /* Copy the creds (should be two of them) */
+ while (krb5_cc_next_cred(krbctx, ccache_temp, &cursor, &creds) == 0) {
+ krbret = krb5_cc_store_cred(krbctx, ccache_perm, &creds);
+ if (krbret != 0) {
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_cc_store_cred()");
+ krb5_cc_destroy(krbctx, ccache_perm);
+ krb5_free_cred_contents(krbctx, &creds);
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ krb5_free_cred_contents(krbctx, &creds);
+ PAM_LOG("Iteration");
+ }
+ krb5_cc_end_seq_get(krbctx, ccache_temp, &cursor);
+
+ PAM_LOG("Done iterating");
+
+ if (strstr(cache_name, "FILE:") == cache_name) {
+ if (chown(&cache_name[5], pwd->pw_uid, pwd->pw_gid) == -1) {
+ PAM_LOG("Error chown(): %s", strerror(errno));
+ krb5_cc_destroy(krbctx, ccache_perm);
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ PAM_LOG("Done chown()");
+
+ if (chmod(&cache_name[5], (S_IRUSR | S_IWUSR)) == -1) {
+ PAM_LOG("Error chmod(): %s", strerror(errno));
+ krb5_cc_destroy(krbctx, ccache_perm);
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ PAM_LOG("Done chmod()");
+ }
+
+ krb5_cc_close(krbctx, ccache_perm);
+
+ PAM_LOG("Cache closed");
+
+ retval = pam_setenv(pamh, "KRB5CCNAME", cache_name, 1);
+ if (retval != PAM_SUCCESS) {
+ PAM_LOG("Error pam_setenv(): %s", pam_strerror(pamh, retval));
+ krb5_cc_destroy(krbctx, ccache_perm);
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ PAM_LOG("Environment done: KRB5CCNAME=%s", cache_name);
+
+cleanup2:
+ krb5_free_principal(krbctx, princ);
+ PAM_LOG("Done cleanup2");
+cleanup3:
+ krb5_free_context(krbctx);
+ PAM_LOG("Done cleanup3");
+
+ seteuid(euid);
+ setegid(egid);
+
+ PAM_LOG("Done seteuid() & setegid()");
+
+ if (cache_name_buf != NULL)
+ free(cache_name_buf);
+
+ return (retval);
+#endif
+}
+
+/*
+ * account management
+ */
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ krb5_error_code krbret;
+ krb5_context krbctx;
+ krb5_ccache ccache;
+ krb5_principal princ;
+ int retval;
+ const void *user;
+ const void *ccache_name;
+
+ retval = pam_get_item(pamh, PAM_USER, &user);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Got user: %s", (const char *)user);
+
+ retval = pam_get_data(pamh, "ccache", &ccache_name);
+ if (retval != PAM_SUCCESS)
+ return (PAM_SUCCESS);
+
+ PAM_LOG("Got credentials");
+
+ krbret = krb5_init_context(&krbctx);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_init_context() failed");
+ return (PAM_PERM_DENIED);
+ }
+
+ PAM_LOG("Context initialised");
+
+ krbret = krb5_cc_resolve(krbctx, (const char *)ccache_name, &ccache);
+ if (krbret != 0) {
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_cc_resolve(\"%s\")", (const char *)ccache_name);
+ krb5_free_context(krbctx);
+ return (PAM_PERM_DENIED);
+ }
+
+ PAM_LOG("Got ccache %s", (const char *)ccache_name);
+
+
+ krbret = krb5_cc_get_principal(krbctx, ccache, &princ);
+ if (krbret != 0) {
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_cc_get_principal()");
+ retval = PAM_PERM_DENIED;
+ goto cleanup;
+ }
+
+ PAM_LOG("Got principal");
+
+ if (krb5_kuserok(krbctx, princ, (const char *)user))
+ retval = PAM_SUCCESS;
+ else
+ retval = PAM_PERM_DENIED;
+ krb5_free_principal(krbctx, princ);
+
+ PAM_LOG("Done kuserok()");
+
+cleanup:
+ krb5_free_context(krbctx);
+ PAM_LOG("Done cleanup");
+
+ return (retval);
+
+}
+
+/*
+ * password management
+ */
+PAM_EXTERN int
+pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc __unused, const char *argv[] __unused)
+{
+ krb5_error_code krbret;
+ krb5_context krbctx;
+ krb5_creds creds;
+ krb5_principal princ;
+ krb5_get_init_creds_opt *opts;
+ krb5_data result_code_string, result_string;
+ int result_code, retval;
+ const char *pass;
+ const void *user;
+ char *princ_name, *passdup;
+
+ if (!(flags & PAM_UPDATE_AUTHTOK))
+ return (PAM_AUTHTOK_ERR);
+
+ retval = pam_get_item(pamh, PAM_USER, &user);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Got user: %s", (const char *)user);
+
+ krbret = krb5_init_context(&krbctx);
+ if (krbret != 0) {
+ PAM_LOG("Error krb5_init_context() failed");
+ return (PAM_SERVICE_ERR);
+ }
+
+ PAM_LOG("Context initialised");
+
+ /* Get principal name */
+ krbret = krb5_parse_name(krbctx, (const char *)user, &princ);
+ if (krbret != 0) {
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_parse_name()");
+ retval = PAM_USER_UNKNOWN;
+ goto cleanup3;
+ }
+
+ /* Now convert the principal name into something human readable */
+ princ_name = NULL;
+ krbret = krb5_unparse_name(krbctx, princ, &princ_name);
+ if (krbret != 0) {
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_unparse_name()");
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ PAM_LOG("Got principal: %s", princ_name);
+
+ /* Get password */
+ retval = pam_get_authtok(pamh, PAM_OLDAUTHTOK, &pass, PASSWORD_PROMPT);
+ if (retval != PAM_SUCCESS)
+ goto cleanup2;
+
+ PAM_LOG("Got password");
+
+ /* Initialize credentials request options. */
+ krbret = krb5_get_init_creds_opt_alloc(krbctx, &opts);
+ if (krbret != 0) {
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_get_init_creds_opt_alloc()");
+ PAM_VERBOSE_ERROR("Kerberos 5 error");
+ retval = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ PAM_LOG("Credentials options initialised");
+
+ memset(&creds, 0, sizeof(krb5_creds));
+ krbret = krb5_get_init_creds_password(krbctx, &creds, princ,
+ pass, NULL, pamh, 0, "kadmin/changepw", opts);
+ krb5_get_init_creds_opt_free(krbctx, opts);
+ if (krbret != 0) {
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_get_init_creds_password()");
+ retval = PAM_AUTH_ERR;
+ goto cleanup2;
+ }
+
+ PAM_LOG("Credentials established");
+
+ /* Now get the new password */
+ for (;;) {
+ retval = pam_get_authtok(pamh,
+ PAM_AUTHTOK, &pass, NEW_PASSWORD_PROMPT);
+ if (retval != PAM_TRY_AGAIN)
+ break;
+ pam_error(pamh, "Mismatch; try again, EOF to quit.");
+ }
+ if (retval != PAM_SUCCESS)
+ goto cleanup;
+
+ PAM_LOG("Got new password");
+
+ /* Change it */
+ if ((passdup = strdup(pass)) == NULL) {
+ retval = PAM_BUF_ERR;
+ goto cleanup;
+ }
+ krbret = krb5_set_password(krbctx, &creds, passdup, NULL,
+ &result_code, &result_code_string, &result_string);
+ free(passdup);
+ if (krbret != 0) {
+ PAM_LOG_KRB5_ERR(krbctx, krbret,
+ "Error krb5_change_password()");
+ retval = PAM_AUTHTOK_ERR;
+ goto cleanup;
+ }
+ if (result_code) {
+ PAM_LOG("Error krb5_change_password(): (result_code)");
+ retval = PAM_AUTHTOK_ERR;
+ goto cleanup;
+ }
+
+ PAM_LOG("Password changed");
+
+ if (result_string.data)
+ free(result_string.data);
+ if (result_code_string.data)
+ free(result_code_string.data);
+
+cleanup:
+ krb5_free_cred_contents(krbctx, &creds);
+ PAM_LOG("Done cleanup");
+cleanup2:
+ krb5_free_principal(krbctx, princ);
+ if (princ_name)
+ free(princ_name);
+ PAM_LOG("Done cleanup2");
+
+cleanup3:
+ krb5_free_context(krbctx);
+
+ PAM_LOG("Done cleanup3");
+
+ return (retval);
+}
+
+PAM_MODULE_ENTRY("pam_krb5");
+
+/*
+ * This routine with some modification is from the MIT V5B6 appl/bsd/login.c
+ * Modified by Sam Hartman <hartmans@mit.edu> to support PAM services
+ * for Debian.
+ *
+ * Verify the Kerberos ticket-granting ticket just retrieved for the
+ * user. If the Kerberos server doesn't respond, assume the user is
+ * trying to fake us out (since we DID just get a TGT from what is
+ * supposedly our KDC). If the host/<host> service is unknown (i.e.,
+ * the local keytab doesn't have it), and we cannot find another
+ * service we do have, let her in.
+ *
+ * Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
+ */
+/* ARGSUSED */
+static int
+verify_krb_v5_tgt_begin(krb5_context context, char *pam_service, int debug,
+ const char **servicep, krb5_principal *princp __unused, char phost[static BUFSIZ])
+{
+ krb5_error_code retval;
+ krb5_principal princ;
+ krb5_keyblock *keyblock;
+ const char *services[3], **service;
+
+ *servicep = NULL;
+
+ if (debug)
+ openlog("pam_krb5", LOG_PID, LOG_AUTHPRIV);
+
+ /* If possible we want to try and verify the ticket we have
+ * received against a keytab. We will try multiple service
+ * principals, including at least the host principal and the PAM
+ * service principal. The host principal is preferred because access
+ * to that key is generally sufficient to compromise root, while the
+ * service key for this PAM service may be less carefully guarded.
+ * It is important to check the keytab first before the KDC so we do
+ * not get spoofed by a fake KDC.
+ */
+ services[0] = "host";
+ services[1] = pam_service;
+ services[2] = NULL;
+ keyblock = NULL;
+ retval = -1;
+ for (service = &services[0]; *service != NULL; service++) {
+ retval = krb5_sname_to_principal(context, NULL, *service,
+ KRB5_NT_SRV_HST, &princ);
+ if (retval != 0) {
+ if (debug) {
+ const char *msg = krb5_get_error_message(
+ context, retval);
+ syslog(LOG_DEBUG,
+ "pam_krb5: verify_krb_v5_tgt(): %s: %s",
+ "krb5_sname_to_principal()", msg);
+ krb5_free_error_message(context, msg);
+ }
+ return -1;
+ }
+
+ /* Extract the name directly. */
+ strncpy(phost, compat_princ_component(context, princ, 1),
+ BUFSIZ);
+ phost[BUFSIZ - 1] = '\0';
+
+ /*
+ * Do we have service/<host> keys?
+ * (use default/configured keytab, kvno IGNORE_VNO to get the
+ * first match, and ignore enctype.)
+ */
+ retval = krb5_kt_read_service_key(context, NULL, princ, 0, 0,
+ &keyblock);
+ if (retval != 0)
+ continue;
+ break;
+ }
+ if (keyblock)
+ krb5_free_keyblock(context, keyblock);
+
+ return (retval);
+}
+
+static int
+verify_krb_v5_tgt(krb5_context context, krb5_ccache ccache,
+ char *pam_service __unused, int debug,
+ const char *service, krb5_principal princ, char phost[static BUFSIZ])
+{
+ krb5_error_code retval;
+ krb5_auth_context auth_context = NULL;
+ krb5_data packet;
+
+ if (service == NULL)
+ return (0); /* uncertain, can't authenticate KDC */
+
+ packet.data = 0;
+
+ /* Talk to the kdc and construct the ticket. */
+ auth_context = NULL;
+ retval = krb5_mk_req(context, &auth_context, 0, service, phost,
+ NULL, ccache, &packet);
+ if (auth_context) {
+ krb5_auth_con_free(context, auth_context);
+ auth_context = NULL; /* setup for rd_req */
+ }
+ if (retval) {
+ if (debug) {
+ const char *msg = krb5_get_error_message(context,
+ retval);
+ syslog(LOG_DEBUG,
+ "pam_krb5: verify_krb_v5_tgt(): %s: %s",
+ "krb5_mk_req()", msg);
+ krb5_free_error_message(context, msg);
+ }
+ retval = -1;
+ goto cleanup;
+ }
+
+ /* Try to use the ticket. */
+ retval = krb5_rd_req(context, &auth_context, &packet, princ, NULL,
+ NULL, NULL);
+ if (retval) {
+ if (debug) {
+ const char *msg = krb5_get_error_message(context,
+ retval);
+ syslog(LOG_DEBUG,
+ "pam_krb5: verify_krb_v5_tgt(): %s: %s",
+ "krb5_rd_req()", msg);
+ krb5_free_error_message(context, msg);
+ }
+ retval = -1;
+ }
+ else
+ retval = 1;
+
+cleanup:
+ if (packet.data)
+ compat_free_data_contents(context, &packet);
+ return (retval);
+}
+
+static void
+verify_krb_v5_tgt_cleanup(krb5_context context, int debug,
+ const char *service, krb5_principal princ, char phost[static BUFSIZ] __unused)
+{
+
+ if (service)
+ krb5_free_principal(context, princ);
+ if (debug)
+ closelog();
+
+}
+
+/* Free the memory for cache_name. Called by pam_end() */
+/* ARGSUSED */
+static void
+cleanup_cache(pam_handle_t *pamh __unused, void *data, int pam_end_status __unused)
+{
+ krb5_context krbctx;
+ krb5_ccache ccache;
+ krb5_error_code krbret;
+
+ if (krb5_init_context(&krbctx))
+ return;
+
+ krbret = krb5_cc_resolve(krbctx, data, &ccache);
+ if (krbret == 0)
+ krb5_cc_destroy(krbctx, ccache);
+ krb5_free_context(krbctx);
+ free(data);
+}
+
+#ifdef COMPAT_HEIMDAL
+#ifdef COMPAT_MIT
+#error This cannot be MIT and Heimdal compatible!
+#endif
+#endif
+
+#ifndef COMPAT_HEIMDAL
+#ifndef COMPAT_MIT
+#error One of COMPAT_MIT and COMPAT_HEIMDAL must be specified!
+#endif
+#endif
+
+#ifdef COMPAT_HEIMDAL
+/* ARGSUSED */
+static const char *
+compat_princ_component(krb5_context context __unused, krb5_principal princ, int n)
+{
+ return princ->name.name_string.val[n];
+}
+
+/* ARGSUSED */
+static void
+compat_free_data_contents(krb5_context context __unused, krb5_data * data)
+{
+ krb5_xfree(data->data);
+}
+#endif
+
+#ifdef COMPAT_MIT
+static const char *
+compat_princ_component(krb5_context context, krb5_principal princ, int n)
+{
+ return krb5_princ_component(context, princ, n)->data;
+}
+
+static void
+compat_free_data_contents(krb5_context context, krb5_data * data)
+{
+ krb5_free_data_contents(context, data);
+}
+#endif
diff --git a/lib/libpam/modules/pam_ksu/Makefile b/lib/libpam/modules/pam_ksu/Makefile
new file mode 100644
index 000000000000..953ca23d1416
--- /dev/null
+++ b/lib/libpam/modules/pam_ksu/Makefile
@@ -0,0 +1,45 @@
+# Copyright 2002 FreeBSD, Inc.
+# 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, this list of conditions and the following disclaimer.
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+#
+
+PACKAGE= kerberos
+
+.include <src.opts.mk>
+
+LIB= pam_ksu
+SRCS= pam_ksu.c
+MAN= pam_ksu.8
+WARNS?= 3
+
+LIBADD+= krb5
+
+.if ${MK_MITKRB5} != "no"
+WARNS= 2
+CFLAGS+= -I${SRCTOP}/crypto/krb5/src/include
+CFLAGS+= -I${SRCTOP}/krb5/include
+CFLAGS+= -include ${SRCTOP}/crypto/krb5/src/include/k5-int.h
+CFLAGS+= -DMK_MITKRB5=yes
+.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_ksu/Makefile.depend b/lib/libpam/modules/pam_ksu/Makefile.depend
new file mode 100644
index 000000000000..37648d1e6ef7
--- /dev/null
+++ b/lib/libpam/modules/pam_ksu/Makefile.depend
@@ -0,0 +1,18 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ kerberos5/lib/libasn1 \
+ kerberos5/lib/libkrb5 \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_ksu/pam_ksu.8 b/lib/libpam/modules/pam_ksu/pam_ksu.8
new file mode 100644
index 000000000000..ace570ea5b5b
--- /dev/null
+++ b/lib/libpam/modules/pam_ksu/pam_ksu.8
@@ -0,0 +1,120 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2001 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" This software was developed for the FreeBSD Project by ThinkSec AS and
+.\" NAI Labs, the Security Research Division of Network Associates, Inc.
+.\" under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
+.\" DARPA CHATS research program.
+.\"
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd May 15, 2002
+.Dt PAM_KSU 8
+.Os
+.Sh NAME
+.Nm pam_ksu
+.Nd Kerberos 5 SU PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_ksu
+.Op Ar options
+.Sh DESCRIPTION
+The Kerberos 5 SU authentication service module for PAM,
+.Nm
+for only one PAM category: authentication.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li auth
+feature.
+The module is specifically designed to be used with the
+.Xr su 1
+utility.
+.\" It also provides a null function for session management.
+.Ss Kerberos 5 SU Authentication Module
+The Kerberos 5 SU authentication component provides functions to verify
+the identity of a user
+.Pq Fn pam_sm_authenticate ,
+and determine whether or not the user is authorized to obtain the
+privileges of the target account.
+If the target account is
+.Dq root ,
+then the Kerberos 5 principal used
+for authentication and authorization will be the
+.Dq root
+instance of
+the current user, e.g.\&
+.Dq Li user/root@REAL.M .
+Otherwise, the principal will simply be the current user's default
+principal, e.g.\&
+.Dq Li user@REAL.M .
+.Pp
+The user is prompted for a password if necessary.
+Authorization is performed
+by comparing the Kerberos 5 principal with those listed in the
+.Pa .k5login
+file in the target account's home directory
+(e.g.\&
+.Pa /root/.k5login
+for root).
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm use_first_pass
+If the authentication module
+is not the first in the stack,
+and a previous module
+obtained the user's password,
+that password is used
+to authenticate the user.
+If this fails,
+the authentication module returns failure
+without prompting the user for a password.
+This option has no effect
+if the authentication module
+is the first in the stack,
+or if no previous modules
+obtained the user's password.
+.It Cm try_first_pass
+This option is similar to the
+.Cm use_first_pass
+option,
+except that if the previously obtained password fails,
+the user is prompted for another password.
+.El
+.Sh SEE ALSO
+.Xr su 1 ,
+.Xr pam 3 ,
+.Xr syslog 3 ,
+.Xr pam.conf 5
diff --git a/lib/libpam/modules/pam_ksu/pam_ksu.c b/lib/libpam/modules/pam_ksu/pam_ksu.c
new file mode 100644
index 000000000000..04c276a423d3
--- /dev/null
+++ b/lib/libpam/modules/pam_ksu/pam_ksu.c
@@ -0,0 +1,307 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2002 Jacques A. Vidrine <nectar@FreeBSD.org>
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/param.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <krb5.h>
+
+#define PAM_SM_AUTH
+#define PAM_SM_CRED
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+static const char superuser[] = "root";
+
+static long get_su_principal(krb5_context, const char *, const char *,
+ char **, krb5_principal *);
+static int auth_krb5(pam_handle_t *, krb5_context, const char *,
+ krb5_principal);
+
+#ifdef MK_MITKRB5
+/* For MIT KRB5 only. */
+
+/*
+ * XXX This entire module will need to be rewritten when heimdal
+ * XXX compatidibility is no longer needed.
+ */
+#define KRB5_DEFAULT_CCFILE_ROOT "/tmp/krb5cc_"
+#define KRB5_DEFAULT_CCROOT "FILE:" KRB5_DEFAULT_CCFILE_ROOT
+
+typedef char *heim_general_string;
+typedef heim_general_string Realm;
+typedef Realm krb5_realm;
+typedef const char *krb5_const_realm;
+
+static krb5_error_code
+krb5_make_principal(krb5_context context, krb5_principal *principal,
+ krb5_const_realm realm, ...)
+{
+ krb5_realm temp_realm = NULL;
+ krb5_error_code rc;
+ va_list ap;
+
+ if (realm == NULL) {
+ if ((rc = krb5_get_default_realm(context, &temp_realm)))
+ return (rc);
+ realm=temp_realm;
+ }
+ va_start(ap, realm);
+
+ rc = krb5_build_principal_alloc_va(context, principal, strlen(realm),
+ realm, ap);
+ va_end(ap);
+ if (temp_realm)
+ free(temp_realm);
+ return (rc);
+}
+#endif
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ krb5_context context;
+ krb5_principal su_principal;
+ const char *user;
+ const void *ruser;
+ char *su_principal_name;
+ long rv;
+ int pamret;
+
+ pamret = pam_get_user(pamh, &user, NULL);
+ if (pamret != PAM_SUCCESS)
+ return (pamret);
+ PAM_LOG("Got user: %s", user);
+ pamret = pam_get_item(pamh, PAM_RUSER, &ruser);
+ if (pamret != PAM_SUCCESS)
+ return (pamret);
+ PAM_LOG("Got ruser: %s", (const char *)ruser);
+ rv = krb5_init_context(&context);
+ if (rv != 0) {
+ const char *msg = krb5_get_error_message(context, rv);
+ PAM_LOG("krb5_init_context failed: %s", msg);
+ krb5_free_error_message(context, msg);
+ return (PAM_SERVICE_ERR);
+ }
+ rv = get_su_principal(context, user, ruser, &su_principal_name, &su_principal);
+ if (rv != 0)
+ return (PAM_AUTH_ERR);
+ PAM_LOG("kuserok: %s -> %s", su_principal_name, user);
+ rv = krb5_kuserok(context, su_principal, user);
+ pamret = rv ? auth_krb5(pamh, context, su_principal_name, su_principal) : PAM_AUTH_ERR;
+ free(su_principal_name);
+ krb5_free_principal(context, su_principal);
+ krb5_free_context(context);
+ return (pamret);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int ac __unused, const char *av[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+/* Authenticate using Kerberos 5.
+ * pamh -- The PAM handle.
+ * context -- An initialized krb5_context.
+ * su_principal_name -- The target principal name, used only for password prompts.
+ * If NULL, the password prompts will not include a principal
+ * name.
+ * su_principal -- The target krb5_principal.
+ * Note that a valid keytab in the default location with a host entry
+ * must be available, and that the PAM application must have sufficient
+ * privileges to access it.
+ * Returns PAM_SUCCESS if authentication was successful, or an appropriate
+ * PAM error code if it was not.
+ */
+static int
+auth_krb5(pam_handle_t *pamh, krb5_context context, const char *su_principal_name,
+ krb5_principal su_principal)
+{
+ krb5_creds creds;
+ krb5_get_init_creds_opt *gic_opt;
+ krb5_verify_init_creds_opt vic_opt;
+ const char *pass;
+ char *prompt;
+ long rv;
+ int pamret;
+
+ prompt = NULL;
+ krb5_verify_init_creds_opt_init(&vic_opt);
+ if (su_principal_name != NULL)
+ (void)asprintf(&prompt, "Password for %s:", su_principal_name);
+ else
+ (void)asprintf(&prompt, "Password:");
+ if (prompt == NULL)
+ return (PAM_BUF_ERR);
+ pass = NULL;
+ pamret = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, prompt);
+ free(prompt);
+ if (pamret != PAM_SUCCESS)
+ return (pamret);
+ rv = krb5_get_init_creds_opt_alloc(context, &gic_opt);
+ if (rv != 0) {
+ const char *msg = krb5_get_error_message(context, rv);
+ PAM_LOG("krb5_get_init_creds_opt_alloc: %s", msg);
+ krb5_free_error_message(context, msg);
+ return (PAM_AUTH_ERR);
+ }
+ rv = krb5_get_init_creds_password(context, &creds, su_principal,
+ pass, NULL, NULL, 0, NULL, gic_opt);
+ krb5_get_init_creds_opt_free(context, gic_opt);
+ if (rv != 0) {
+ const char *msg = krb5_get_error_message(context, rv);
+ PAM_LOG("krb5_get_init_creds_password: %s", msg);
+ krb5_free_error_message(context, msg);
+ return (PAM_AUTH_ERR);
+ }
+ krb5_verify_init_creds_opt_set_ap_req_nofail(&vic_opt, 1);
+ rv = krb5_verify_init_creds(context, &creds, NULL, NULL, NULL,
+ &vic_opt);
+ krb5_free_cred_contents(context, &creds);
+ if (rv != 0) {
+ const char *msg = krb5_get_error_message(context, rv);
+ PAM_LOG("krb5_verify_init_creds: %s", msg);
+ krb5_free_error_message(context, msg);
+ return (PAM_AUTH_ERR);
+ }
+ return (PAM_SUCCESS);
+}
+
+/* Determine the target principal given the current user and the target user.
+ * context -- An initialized krb5_context.
+ * target_user -- The target username.
+ * current_user -- The current username.
+ * su_principal_name -- (out) The target principal name.
+ * su_principal -- (out) The target krb5_principal.
+ * When the target user is `root', the target principal will be a `root
+ * instance', e.g. `luser/root@REA.LM'. Otherwise, the target principal
+ * will simply be the current user's default principal name. Note that
+ * in any case, if KRB5CCNAME is set and a credentials cache exists, the
+ * principal name found there will be the `starting point', rather than
+ * the ruser parameter.
+ *
+ * Returns 0 for success, or a com_err error code on failure.
+ */
+static long
+get_su_principal(krb5_context context, const char *target_user, const char *current_user,
+ char **su_principal_name, krb5_principal *su_principal)
+{
+ krb5_principal default_principal;
+ krb5_ccache ccache;
+ char *principal_name, *ccname, *p;
+ long rv;
+ uid_t euid, ruid;
+
+ *su_principal = NULL;
+ default_principal = NULL;
+ /* Unless KRB5CCNAME was explicitly set, we won't really be able
+ * to look at the credentials cache since krb5_cc_default will
+ * look at getuid().
+ */
+ ruid = getuid();
+ euid = geteuid();
+ rv = seteuid(ruid);
+ if (rv != 0)
+ return (errno);
+ p = getenv("KRB5CCNAME");
+ if (p != NULL)
+ ccname = strdup(p);
+ else
+ (void)asprintf(&ccname, "%s%lu", KRB5_DEFAULT_CCROOT, (unsigned long)ruid);
+ if (ccname == NULL)
+ return (errno);
+ rv = krb5_cc_resolve(context, ccname, &ccache);
+ free(ccname);
+ if (rv == 0) {
+ rv = krb5_cc_get_principal(context, ccache, &default_principal);
+ krb5_cc_close(context, ccache);
+ if (rv != 0)
+ default_principal = NULL; /* just to be safe */
+ }
+ rv = seteuid(euid);
+ if (rv != 0)
+ return (errno);
+ if (default_principal == NULL) {
+ rv = krb5_make_principal(context, &default_principal, NULL, current_user, NULL);
+ if (rv != 0) {
+ PAM_LOG("Could not determine default principal name.");
+ return (rv);
+ }
+ }
+ /* Now that we have some principal, if the target account is
+ * `root', then transform it into a `root' instance, e.g.
+ * `user@REA.LM' -> `user/root@REA.LM'.
+ */
+ rv = krb5_unparse_name(context, default_principal, &principal_name);
+ krb5_free_principal(context, default_principal);
+ if (rv != 0) {
+ const char *msg = krb5_get_error_message(context, rv);
+ PAM_LOG("krb5_unparse_name: %s", msg);
+ krb5_free_error_message(context, msg);
+ return (rv);
+ }
+ PAM_LOG("Default principal name: %s", principal_name);
+ if (strcmp(target_user, superuser) == 0) {
+ p = strrchr(principal_name, '@');
+ if (p == NULL) {
+ PAM_LOG("malformed principal name `%s'", principal_name);
+ free(principal_name);
+ return (rv);
+ }
+ *p++ = '\0';
+ *su_principal_name = NULL;
+ (void)asprintf(su_principal_name, "%s/%s@%s", principal_name, superuser, p);
+ free(principal_name);
+ } else
+ *su_principal_name = principal_name;
+
+ if (*su_principal_name == NULL)
+ return (errno);
+ rv = krb5_parse_name(context, *su_principal_name, &default_principal);
+ if (rv != 0) {
+ const char *msg = krb5_get_error_message(context, rv);
+ PAM_LOG("krb5_parse_name `%s': %s", *su_principal_name, msg);
+ krb5_free_error_message(context, msg);
+ free(*su_principal_name);
+ return (rv);
+ }
+ PAM_LOG("Target principal name: %s", *su_principal_name);
+ *su_principal = default_principal;
+ return (0);
+}
+
+PAM_MODULE_ENTRY("pam_ksu");
diff --git a/lib/libpam/modules/pam_lastlog/Makefile b/lib/libpam/modules/pam_lastlog/Makefile
new file mode 100644
index 000000000000..1abf6f2b6304
--- /dev/null
+++ b/lib/libpam/modules/pam_lastlog/Makefile
@@ -0,0 +1,32 @@
+# Copyright 2001 Mark R V Murray
+# 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, this list of conditions and the following disclaimer.
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+#
+
+PACKAGE= runtime
+
+LIB= pam_lastlog
+SRCS= pam_lastlog.c
+MAN= pam_lastlog.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_lastlog/Makefile.depend b/lib/libpam/modules/pam_lastlog/Makefile.depend
new file mode 100644
index 000000000000..0665960a2cd2
--- /dev/null
+++ b/lib/libpam/modules/pam_lastlog/Makefile.depend
@@ -0,0 +1,16 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_lastlog/pam_lastlog.8 b/lib/libpam/modules/pam_lastlog/pam_lastlog.8
new file mode 100644
index 000000000000..e924016151fa
--- /dev/null
+++ b/lib/libpam/modules/pam_lastlog/pam_lastlog.8
@@ -0,0 +1,99 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2001 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS and NAI Labs, the Security Research Division of Network
+.\" Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+.\" ("CBOSS"), as part of the DARPA CHATS research program.
+.\"
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd January 21, 2010
+.Dt PAM_LASTLOG 8
+.Os
+.Sh NAME
+.Nm pam_lastlog
+.Nd login accounting PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_lastlog
+.Op Ar options
+.Sh DESCRIPTION
+The login accounting service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+session management.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li session
+feature.
+.Ss Login Accounting Session Management Module
+The login accounting session management component provides functions
+to initiate
+.Pq Fn pam_sm_open_session
+and terminate
+.Pq Fn pam_sm_close_session
+sessions.
+The
+.Fn pam_sm_open_session
+function records the session in the user accounting database.
+The
+.Fn pam_sm_close_session
+function does nothing.
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm no_warn"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+.It Cm no_fail
+Ignore I/O failures.
+.El
+.Sh SEE ALSO
+.Xr last 1 ,
+.Xr w 1 ,
+.Xr getutxent 3 ,
+.Xr pam 3 ,
+.Xr ulog_login 3 ,
+.Xr ulog_logout 3 ,
+.Xr pam.conf 5 ,
+.Xr lastlogin 8
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the FreeBSD Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_lastlog/pam_lastlog.c b/lib/libpam/modules/pam_lastlog/pam_lastlog.c
new file mode 100644
index 000000000000..e631723f6e76
--- /dev/null
+++ b/lib/libpam/modules/pam_lastlog/pam_lastlog.c
@@ -0,0 +1,180 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2001 Mark R V Murray
+ * All rights reserved.
+ * Copyright (c) 2001 Networks Associates Technology, Inc.
+ * All rights reserved.
+ * Copyright (c) 2004 Joe R. Doupnik
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/cdefs.h>
+#define _BSD_SOURCE
+
+#include <sys/time.h>
+
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <utmpx.h>
+
+#define PAM_SM_SESSION
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#define PAM_UTMPX_ID "utmpx_id"
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh, int flags,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct utmpx *utx, utl;
+ time_t t;
+ const char *user;
+ const void *rhost, *tty;
+ char *id;
+ int pam_err;
+
+ pam_err = pam_get_user(pamh, &user, NULL);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+ if (user == NULL)
+ return (PAM_SERVICE_ERR);
+ PAM_LOG("Got user: %s", user);
+
+ pam_err = pam_get_item(pamh, PAM_RHOST, &rhost);
+ if (pam_err != PAM_SUCCESS) {
+ PAM_LOG("No PAM_RHOST");
+ goto err;
+ }
+ pam_err = pam_get_item(pamh, PAM_TTY, &tty);
+ if (pam_err != PAM_SUCCESS) {
+ PAM_LOG("No PAM_TTY");
+ goto err;
+ }
+ if (tty == NULL) {
+ PAM_LOG("No PAM_TTY");
+ pam_err = PAM_SERVICE_ERR;
+ goto err;
+ }
+ /* Strip /dev/ component. */
+ if (strncmp(tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+ tty = (const char *)tty + sizeof(_PATH_DEV) - 1;
+
+ if ((flags & PAM_SILENT) == 0) {
+ if (setutxdb(UTXDB_LASTLOGIN, NULL) != 0) {
+ PAM_LOG("Failed to open lastlogin database");
+ } else {
+ utx = getutxuser(user);
+ if (utx != NULL && utx->ut_type == USER_PROCESS) {
+ t = utx->ut_tv.tv_sec;
+ if (*utx->ut_host != '\0')
+ pam_info(pamh, "Last login: %.*s from %s",
+ 24 - 5, ctime(&t), utx->ut_host);
+ else
+ pam_info(pamh, "Last login: %.*s on %s",
+ 24 - 5, ctime(&t), utx->ut_line);
+ }
+ endutxent();
+ }
+ }
+
+ id = malloc(sizeof utl.ut_id);
+ if (id == NULL) {
+ pam_err = PAM_SERVICE_ERR;
+ goto err;
+ }
+ arc4random_buf(id, sizeof utl.ut_id);
+
+ pam_err = pam_set_data(pamh, PAM_UTMPX_ID, id, openpam_free_data);
+ if (pam_err != PAM_SUCCESS) {
+ free(id);
+ goto err;
+ }
+
+ memset(&utl, 0, sizeof utl);
+ utl.ut_type = USER_PROCESS;
+ memcpy(utl.ut_id, id, sizeof utl.ut_id);
+ strncpy(utl.ut_user, user, sizeof utl.ut_user);
+ strncpy(utl.ut_line, tty, sizeof utl.ut_line);
+ if (rhost != NULL)
+ strncpy(utl.ut_host, rhost, sizeof utl.ut_host);
+ utl.ut_pid = getpid();
+ gettimeofday(&utl.ut_tv, NULL);
+ pututxline(&utl);
+
+ return (PAM_SUCCESS);
+
+err:
+ if (openpam_get_option(pamh, "no_fail"))
+ return (PAM_SUCCESS);
+ return (pam_err);
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct utmpx utl;
+ const void *id;
+ int pam_err;
+
+ pam_err = pam_get_data(pamh, PAM_UTMPX_ID, (const void **)&id);
+ if (pam_err != PAM_SUCCESS)
+ goto err;
+
+ memset(&utl, 0, sizeof utl);
+ utl.ut_type = DEAD_PROCESS;
+ memcpy(utl.ut_id, id, sizeof utl.ut_id);
+ utl.ut_pid = getpid();
+ gettimeofday(&utl.ut_tv, NULL);
+ pututxline(&utl);
+
+ return (PAM_SUCCESS);
+
+ err:
+ if (openpam_get_option(pamh, "no_fail"))
+ return (PAM_SUCCESS);
+ return (pam_err);
+}
+
+PAM_MODULE_ENTRY("pam_lastlog");
diff --git a/lib/libpam/modules/pam_login_access/Makefile b/lib/libpam/modules/pam_login_access/Makefile
new file mode 100644
index 000000000000..43c025336354
--- /dev/null
+++ b/lib/libpam/modules/pam_login_access/Makefile
@@ -0,0 +1,32 @@
+# Copyright 2001 Mark R V Murray
+# 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, this list of conditions and the following disclaimer.
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+#
+
+PACKAGE= runtime
+
+LIB= pam_login_access
+SRCS= pam_login_access.c login_access.c
+MAN= login.access.5 pam_login_access.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_login_access/Makefile.depend b/lib/libpam/modules/pam_login_access/Makefile.depend
new file mode 100644
index 000000000000..0665960a2cd2
--- /dev/null
+++ b/lib/libpam/modules/pam_login_access/Makefile.depend
@@ -0,0 +1,16 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_login_access/login.access.5 b/lib/libpam/modules/pam_login_access/login.access.5
new file mode 100644
index 000000000000..c63b136fb1d8
--- /dev/null
+++ b/lib/libpam/modules/pam_login_access/login.access.5
@@ -0,0 +1,66 @@
+.\"
+.Dd January 30, 2020
+.Dt LOGIN.ACCESS 5
+.Os
+.Sh NAME
+.Nm login.access
+.Nd login access control table
+.Sh SYNOPSIS
+.Pa /etc/login.access
+.Sh DESCRIPTION
+The
+.Nm
+file specifies (user, host) combinations and/or (user, tty)
+combinations for which a login will be either accepted or refused.
+.Pp
+When someone logs in, the
+.Nm
+is scanned for the first entry that
+matches the (user, host) combination, or, in case of non-networked
+logins, the first entry that matches the (user, tty) combination.
+The
+permissions field of that table entry determines whether the login will
+be accepted or refused.
+.Pp
+Each line of the login access control table has three fields separated by a
+.Ql \&:
+character:
+.Ar permission : Ns Ar users : Ns Ar origins
+.Pp
+The first field should be a "+" (access granted) or "-" (access denied)
+character.
+.Pp
+The second field should be a list of one or more login names,
+group names, or ALL (always matches).
+Group names must be enclosed in
+parentheses if the pam module specification for
+.Pa pam_login_access
+specifies the
+.Pa nodefgroup
+option.
+Otherwise, group names will only match if no usernames match.
+.Pp
+The third field should be a list
+of one or more tty names (for non-networked logins), host names, domain
+names (begin with "."), host addresses, internet network numbers (end
+with "."), ALL (always matches) or LOCAL (matches any string that does
+not contain a "." character).
+If you run NIS you can use @netgroupname
+in host or user patterns.
+.Pp
+The EXCEPT operator makes it possible to write very compact rules.
+.Pp
+The group file is searched only when a name does not match that of the
+logged-in user.
+Only groups are matched in which users are explicitly
+listed: the program does not look at a user's primary group id value.
+.Sh FILES
+.Bl -tag -width /etc/login.access -compact
+.It Pa /etc/login.access
+login access control table
+.El
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr pam_login_access 8
+.Sh AUTHORS
+.An Guido van Rooij
diff --git a/lib/libpam/modules/pam_login_access/login_access.c b/lib/libpam/modules/pam_login_access/login_access.c
new file mode 100644
index 000000000000..1fbb644e2055
--- /dev/null
+++ b/lib/libpam/modules/pam_login_access/login_access.c
@@ -0,0 +1,294 @@
+ /*
+ * This module implements a simple but effective form of login access
+ * control based on login names and on host (or domain) names, internet
+ * addresses (or network numbers), or on terminal line names in case of
+ * non-networked logins. Diagnostics are reported through syslog(3).
+ *
+ * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "%Z% %M% %I% %E% %U%";
+#endif
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <ctype.h>
+#include <errno.h>
+#include <grp.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "pam_login_access.h"
+
+ /* Constants to be used in assignments only, not in comparisons... */
+
+#define YES 1
+#define NO 0
+
+static int from_match(const char *, const char *, struct pam_login_access_options *);
+static int list_match(char *, const char *,
+ int (*)(const char *, const char *,
+ struct pam_login_access_options *),
+ struct pam_login_access_options *);
+static int netgroup_match(const char *, const char *, const char *);
+static int string_match(const char *, const char *);
+static int user_match(const char *, const char *, struct pam_login_access_options *);
+static int group_match(const char *, const char *);
+
+/* login_access - match username/group and host/tty with access control file */
+
+int
+login_access(const char *user, const char *from,
+ struct pam_login_access_options *login_access_opts)
+{
+ FILE *fp;
+ char line[BUFSIZ];
+ char *perm; /* becomes permission field */
+ char *users; /* becomes list of login names */
+ char *froms; /* becomes list of terminals or hosts */
+ int match = NO;
+ int end;
+ int lineno = 0; /* for diagnostics */
+ const char *fieldsep = login_access_opts->fieldsep;
+
+ /*
+ * Process the table one line at a time and stop at the first match.
+ * Blank lines and lines that begin with a '#' character are ignored.
+ * Non-comment lines are broken at the ':' character. All fields are
+ * mandatory. The first field should be a "+" or "-" character. A
+ * non-existing table means no access control.
+ */
+
+ if ((fp = fopen(login_access_opts->accessfile, "r")) != NULL) {
+ while (!match && fgets(line, sizeof(line), fp)) {
+ lineno++;
+ if (line[end = strlen(line) - 1] != '\n') {
+ syslog(LOG_ERR, "%s: line %d: missing newline or line too long",
+ login_access_opts->accessfile, lineno);
+ continue;
+ }
+ if (line[0] == '#')
+ continue; /* comment line */
+ while (end > 0 && isspace(line[end - 1]))
+ end--;
+ line[end] = 0; /* strip trailing whitespace */
+ if (line[0] == 0) /* skip blank lines */
+ continue;
+ if (!(perm = strtok(line, fieldsep))
+ || !(users = strtok((char *) 0, fieldsep))
+ || !(froms = strtok((char *) 0, fieldsep))
+ || strtok((char *) 0, fieldsep)) {
+ syslog(LOG_ERR, "%s: line %d: bad field count", login_access_opts->accessfile,
+ lineno);
+ continue;
+ }
+ if (perm[0] != '+' && perm[0] != '-') {
+ syslog(LOG_ERR, "%s: line %d: bad first field", login_access_opts->accessfile,
+ lineno);
+ continue;
+ }
+ match = (list_match(froms, from, from_match, login_access_opts)
+ && list_match(users, user, user_match, login_access_opts));
+ }
+ (void) fclose(fp);
+ } else if (errno != ENOENT) {
+ syslog(LOG_ERR, "cannot open %s: %m", login_access_opts->accessfile);
+ }
+ return (match == 0 || (line[0] == '+'));
+}
+
+/* list_match - match an item against a list of tokens with exceptions */
+
+static int
+list_match(char *list, const char *item,
+ int (*match_fn)(const char *, const char *, struct pam_login_access_options *),
+ struct pam_login_access_options *login_access_opts)
+{
+ char *tok;
+ int match = NO;
+ const char *listsep = login_access_opts->listsep;
+
+ /*
+ * Process tokens one at a time. We have exhausted all possible matches
+ * when we reach an "EXCEPT" token or the end of the list. If we do find
+ * a match, look for an "EXCEPT" list and recurse to determine whether
+ * the match is affected by any exceptions.
+ */
+
+ for (tok = strtok(list, listsep); tok != NULL; tok = strtok((char *) 0, listsep)) {
+ if (strcmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */
+ break;
+ if ((match = (*match_fn)(tok, item, login_access_opts)) != 0) /* YES */
+ break;
+ }
+ /* Process exceptions to matches. */
+
+ if (match != NO) {
+ while ((tok = strtok((char *) 0, listsep)) && strcmp(tok, "EXCEPT")) {
+ /* VOID */ ;
+ }
+ if (tok == NULL ||
+ list_match((char *) 0, item, match_fn, login_access_opts) == NO) {
+ return (match);
+ }
+ }
+ return (NO);
+}
+
+/* netgroup_match - match group against machine or user */
+
+static int
+netgroup_match(const char *group, const char *machine, const char *user)
+{
+ char domain[1024];
+ unsigned int i;
+
+ if (getdomainname(domain, sizeof(domain)) != 0 || *domain == '\0') {
+ syslog(LOG_ERR, "NIS netgroup support disabled: no NIS domain");
+ return (NO);
+ }
+
+ /* getdomainname() does not reliably terminate the string */
+ for (i = 0; i < sizeof(domain); ++i)
+ if (domain[i] == '\0')
+ break;
+ if (i == sizeof(domain)) {
+ syslog(LOG_ERR, "NIS netgroup support disabled: invalid NIS domain");
+ return (NO);
+ }
+
+ if (innetgr(group, machine, user, domain) == 1)
+ return (YES);
+ return (NO);
+}
+
+/* group_match - match a group against one token */
+
+int
+group_match(const char *tok, const char *username)
+{
+ struct group *group;
+ struct passwd *passwd;
+ gid_t *grouplist;
+ int i, ret, ngroups = NGROUPS;
+
+ if ((passwd = getpwnam(username)) == NULL)
+ return (NO);
+ errno = 0;
+ if ((group = getgrnam(tok)) == NULL) {
+ if (errno != 0)
+ syslog(LOG_ERR, "getgrnam() failed for %s: %s", username, strerror(errno));
+ else
+ syslog(LOG_NOTICE, "group not found: %s", username);
+ return (NO);
+ }
+ if ((grouplist = calloc(ngroups, sizeof(gid_t))) == NULL) {
+ syslog(LOG_ERR, "cannot allocate memory for grouplist: %s", username);
+ return (NO);
+ }
+ ret = NO;
+ if (getgrouplist(username, passwd->pw_gid, grouplist, &ngroups) != 0)
+ syslog(LOG_ERR, "getgrouplist() failed for %s", username);
+ for (i = 0; i < ngroups; i++)
+ if (grouplist[i] == group->gr_gid)
+ ret = YES;
+ free(grouplist);
+ return (ret);
+}
+
+/* user_match - match a username against one token */
+
+static int
+user_match(const char *tok, const char *string,
+ struct pam_login_access_options *login_access_opts)
+{
+ size_t stringlen;
+ char *grpstr;
+ int rc;
+
+ /*
+ * If a token has the magic value "ALL" the match always succeeds.
+ * Otherwise, return YES if the token fully matches the username, or if
+ * the token is a group that contains the username.
+ */
+
+ if (tok[0] == '@') { /* netgroup */
+ return (netgroup_match(tok + 1, (char *) 0, string));
+ } else if (tok[0] == '(' && tok[(stringlen = strlen(&tok[1]))] == ')') { /* group */
+ if ((grpstr = strndup(&tok[1], stringlen - 1)) == NULL) {
+ syslog(LOG_ERR, "cannot allocate memory for %s", string);
+ return (NO);
+ }
+ rc = group_match(grpstr, string);
+ free(grpstr);
+ return (rc);
+ } else if (string_match(tok, string)) { /* ALL or exact match */
+ return (YES);
+ } else if (login_access_opts->defgroup == true) {/* try group membership */
+ return (group_match(tok, string));
+ }
+ return (NO);
+}
+
+/* from_match - match a host or tty against a list of tokens */
+
+static int
+from_match(const char *tok, const char *string,
+ struct pam_login_access_options *login_access_opts __unused)
+{
+ int tok_len;
+ int str_len;
+
+ /*
+ * If a token has the magic value "ALL" the match always succeeds. Return
+ * YES if the token fully matches the string. If the token is a domain
+ * name, return YES if it matches the last fields of the string. If the
+ * token has the magic value "LOCAL", return YES if the string does not
+ * contain a "." character. If the token is a network number, return YES
+ * if it matches the head of the string.
+ */
+
+ if (tok[0] == '@') { /* netgroup */
+ return (netgroup_match(tok + 1, string, (char *) 0));
+ } else if (string_match(tok, string)) { /* ALL or exact match */
+ return (YES);
+ } else if (tok[0] == '.') { /* domain: match last fields */
+ if ((str_len = strlen(string)) > (tok_len = strlen(tok))
+ && strcasecmp(tok, string + str_len - tok_len) == 0)
+ return (YES);
+ } else if (strcmp(tok, "LOCAL") == 0) { /* local: no dots */
+ if (strchr(string, '.') == NULL)
+ return (YES);
+ } else if (tok[(tok_len = strlen(tok)) - 1] == '.' /* network */
+ && strncmp(tok, string, tok_len) == 0) {
+ return (YES);
+ }
+ return (NO);
+}
+
+/* string_match - match a string against one token */
+
+static int
+string_match(const char *tok, const char *string)
+{
+
+ /*
+ * If the token has the magic value "ALL" the match always succeeds.
+ * Otherwise, return YES if the token fully matches the string.
+ */
+
+ if (strcmp(tok, "ALL") == 0) { /* all: always matches */
+ return (YES);
+ } else if (strcasecmp(tok, string) == 0) { /* try exact match */
+ return (YES);
+ }
+ return (NO);
+}
diff --git a/lib/libpam/modules/pam_login_access/pam_login_access.8 b/lib/libpam/modules/pam_login_access/pam_login_access.8
new file mode 100644
index 000000000000..f4009de3af72
--- /dev/null
+++ b/lib/libpam/modules/pam_login_access/pam_login_access.8
@@ -0,0 +1,120 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2001 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS and NAI Labs, the Security Research Division of Network
+.\" Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+.\" ("CBOSS"), as part of the DARPA CHATS research program.
+.\"
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd January 30, 2020
+.Dt PAM_LOGIN_ACCESS 8
+.Os
+.Sh NAME
+.Nm pam_login_access
+.Nd login.access PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_login_access
+.Op Ar options
+.Sh DESCRIPTION
+The
+.Pa login.access
+service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+account management.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li account
+feature.
+.Ss Login.access Account Management Module
+The
+.Pa login.access
+account management component
+.Pq Fn pam_sm_acct_mgmt ,
+returns success if and only the user is allowed to login on the
+specified tty (in the case of a local login) or from the specified
+remote host (in the case of a remote login), according to the
+restrictions listed in
+.Xr login.access 5 .
+.Bl -tag -width ".Cm accessfile=pathname"
+.It Cm accessfile Ns = Ns Ar pathname
+specifies a non-standard location for the
+.Pa login.access
+configuration file
+(normally located in
+.Pa /etc/login.access ) .
+.It Cm nodefgroup
+makes tokens not enclosed in parentheses only match users, requiring groups
+to be specified in parentheses.
+Without
+.Cm nodefgroup
+user and group names are intermingled, with user entries taking precedence
+over group entries.
+This is not backwards compatible with legacy
+.Pa login.access
+configuration files.
+However this mitigates confusion between users and
+groups of the same name.
+.It Cm fieldsep Ns = Ns Ar separators
+changes the field separator from the default ":".
+More than one separator
+may be specified.
+.It Cm listsep Ns = Ns Ar separators
+changes the field separator from the default space (''), tab (\\t) and
+comma (,).
+More than one separator may be specified.
+For example, listsep=;
+will replace the default with a semicolon (;).
+This option may be useful when specifying Active Directory groupnames which
+typically contain spaces.
+.El
+.Sh SEE ALSO
+.Xr pam 3 ,
+.Xr syslog 3 ,
+.Xr login.access 5 ,
+.Xr pam.conf 5
+.Sh AUTHORS
+The
+.Xr login.access 5
+access control scheme was designed and implemented by
+.An Wietse Venema .
+.Pp
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_login_access/pam_login_access.c b/lib/libpam/modules/pam_login_access/pam_login_access.c
new file mode 100644
index 000000000000..8b4e7d8f0880
--- /dev/null
+++ b/lib/libpam/modules/pam_login_access/pam_login_access.c
@@ -0,0 +1,129 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2001 Mark R V Murray
+ * All rights reserved.
+ * Copyright (c) 2001 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/cdefs.h>
+#define _BSD_SOURCE
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <syslog.h>
+#include <unistd.h>
+
+#define PAM_SM_ACCOUNT
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+#include <security/openpam.h>
+
+#include "pam_login_access.h"
+
+#define OPT_ACCESSFILE "accessfile"
+#define OPT_NOAUDIT "noaudit"
+#define OPT_FIELDSEP "fieldsep"
+#define OPT_LISTSEP "listsep"
+#define OPT_NODEFGROUP "nodefgroup"
+
+#define _PATH_LOGACCESS "/etc/login.access"
+#define _FIELD_SEPARATOR ":"
+#define _LIST_SEPARATOR ", \t"
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct pam_login_access_options login_access_opts;
+ const void *rhost, *tty, *user;
+ char hostname[MAXHOSTNAMELEN];
+ int pam_err;
+
+ pam_err = pam_get_item(pamh, PAM_USER, &user);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ if (user == NULL)
+ return (PAM_SERVICE_ERR);
+
+ PAM_LOG("Got user: %s", (const char *)user);
+
+ pam_err = pam_get_item(pamh, PAM_RHOST, &rhost);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ pam_err = pam_get_item(pamh, PAM_TTY, &tty);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ gethostname(hostname, sizeof hostname);
+ login_access_opts.defgroup = openpam_get_option(pamh, OPT_NODEFGROUP) == NULL ? true : false;
+ login_access_opts.audit = openpam_get_option(pamh, OPT_NOAUDIT) == NULL ? true : false;
+ if ((login_access_opts.accessfile = openpam_get_option(pamh, OPT_ACCESSFILE)) == NULL)
+ login_access_opts.accessfile = _PATH_LOGACCESS;
+ if ((login_access_opts.fieldsep = openpam_get_option(pamh, OPT_FIELDSEP)) == NULL)
+ login_access_opts.fieldsep = _FIELD_SEPARATOR;
+ if ((login_access_opts.listsep = openpam_get_option(pamh, OPT_LISTSEP)) == NULL)
+ login_access_opts.listsep = _LIST_SEPARATOR;
+
+ if (rhost != NULL && *(const char *)rhost != '\0') {
+ PAM_LOG("Checking login.access for user %s from host %s",
+ (const char *)user, (const char *)rhost);
+ if (login_access(user, rhost, &login_access_opts) != 0)
+ return (PAM_SUCCESS);
+ PAM_VERBOSE_ERROR("%s is not allowed to log in from %s",
+ (const char *)user, (const char *)rhost);
+ } else if (tty != NULL && *(const char *)tty != '\0') {
+ PAM_LOG("Checking login.access for user %s on tty %s",
+ (const char *)user, (const char *)tty);
+ if (login_access(user, tty, &login_access_opts) != 0)
+ return (PAM_SUCCESS);
+ PAM_VERBOSE_ERROR("%s is not allowed to log in on %s",
+ (const char *)user, (const char *)tty);
+ } else {
+ PAM_LOG("Checking login.access for user %s",
+ (const char *)user);
+ if (login_access(user, "***unknown***", &login_access_opts) != 0)
+ return (PAM_SUCCESS);
+ PAM_VERBOSE_ERROR("%s is not allowed to log in",
+ (const char *)user);
+ }
+
+ return (PAM_AUTH_ERR);
+}
+
+PAM_MODULE_ENTRY("pam_login_access");
diff --git a/lib/libpam/modules/pam_login_access/pam_login_access.h b/lib/libpam/modules/pam_login_access/pam_login_access.h
new file mode 100644
index 000000000000..c482f1811695
--- /dev/null
+++ b/lib/libpam/modules/pam_login_access/pam_login_access.h
@@ -0,0 +1,50 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2001 Mark R V Murray
+ * All rights reserved.
+ * Copyright (c) 2001 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <stdbool.h>
+
+struct pam_login_access_options {
+ bool defgroup;
+ bool audit;
+ const char *accessfile;
+ /* Delimiters for fields and for lists of users, ttys or hosts. */
+ const char *fieldsep; /* field separator */
+ const char *listsep; /* list-element separator */
+};
+
+extern int login_access(const char *, const char *, struct pam_login_access_options *);
diff --git a/lib/libpam/modules/pam_nologin/Makefile b/lib/libpam/modules/pam_nologin/Makefile
new file mode 100644
index 000000000000..e4c3c5a35c1e
--- /dev/null
+++ b/lib/libpam/modules/pam_nologin/Makefile
@@ -0,0 +1,34 @@
+# Copyright 2001 Mark R V Murray
+# 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, this list of conditions and the following disclaimer.
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+#
+
+PACKAGE= runtime
+
+LIB= pam_nologin
+SRCS= pam_nologin.c
+MAN= pam_nologin.8
+
+LIBADD+= util
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_nologin/Makefile.depend b/lib/libpam/modules/pam_nologin/Makefile.depend
new file mode 100644
index 000000000000..dcba122adac8
--- /dev/null
+++ b/lib/libpam/modules/pam_nologin/Makefile.depend
@@ -0,0 +1,17 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+ lib/libutil \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_nologin/pam_nologin.8 b/lib/libpam/modules/pam_nologin/pam_nologin.8
new file mode 100644
index 000000000000..ff49749e50f1
--- /dev/null
+++ b/lib/libpam/modules/pam_nologin/pam_nologin.8
@@ -0,0 +1,88 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd June 10, 2007
+.Dt PAM_NOLOGIN 8
+.Os
+.Sh NAME
+.Nm pam_nologin
+.Nd NoLogin PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_nologin
+.Op Ar options
+.Sh DESCRIPTION
+The NoLogin service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+account management.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li account
+feature.
+.Ss NoLogin Account Management Module
+The NoLogin account management component,
+.Fn pam_sm_acct_mgmt ,
+verifies whether logins are administratively disabled via
+.Xr nologin 5 .
+It returns success if the user's login class has an "ignorenologin"
+capability specified in
+.Xr login.conf 5
+or the
+.Xr nologin 5
+file does not exist.
+If neither condition is met,
+then the contents of
+.Xr nologin 5
+are echoed
+before failure is returned.
+The location of
+.Xr nologin 5
+is specified by a "nologin" capability in
+.Xr login.conf 5 ,
+which defaults to
+.Pa /var/run/nologin .
+.Pp
+The following options may be passed to the module:
+.Bl -tag -width ".Cm no_warn"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include
+reasons why the user's
+login attempt was declined.
+.El
+.Sh SEE ALSO
+.Xr pam 3 ,
+.Xr syslog 3 ,
+.Xr login.conf 5 ,
+.Xr nologin 5 ,
+.Xr pam.conf 5
diff --git a/lib/libpam/modules/pam_nologin/pam_nologin.c b/lib/libpam/modules/pam_nologin/pam_nologin.c
new file mode 100644
index 000000000000..16f7ebdc2e7c
--- /dev/null
+++ b/lib/libpam/modules/pam_nologin/pam_nologin.c
@@ -0,0 +1,126 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright 2001 Mark R V Murray
+ * All rights reserved.
+ * Copyright (c) 2001 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <login_cap.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define PAM_SM_ACCOUNT
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#define _PATH_NOLOGIN "/var/run/nologin"
+
+static char nologin_def[] = _PATH_NOLOGIN;
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
+ int argc __unused, const char *argv[] __unused)
+{
+ login_cap_t *lc;
+ struct passwd *pwd;
+ struct stat st;
+ int retval, fd;
+ ssize_t ss;
+ const char *user, *nologin;
+ char *mtmp;
+
+ retval = pam_get_user(pamh, &user, NULL);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Got user: %s", user);
+
+ pwd = getpwnam(user);
+ if (pwd == NULL)
+ return (PAM_USER_UNKNOWN);
+
+ /*
+ * login_getpwclass(3) will select the "root" class by default
+ * if pwd->pw_uid is 0. That class should have "ignorenologin"
+ * capability so that super-user can bypass nologin.
+ */
+ lc = login_getpwclass(pwd);
+ if (lc == NULL) {
+ PAM_LOG("Unable to get login class for user %s", user);
+ return (PAM_SERVICE_ERR);
+ }
+
+ if (login_getcapbool(lc, "ignorenologin", 0)) {
+ login_close(lc);
+ return (PAM_SUCCESS);
+ }
+
+ nologin = login_getcapstr(lc, "nologin", nologin_def, nologin_def);
+
+ fd = open(nologin, O_RDONLY, 0);
+ if (fd < 0) {
+ login_close(lc);
+ return (PAM_SUCCESS);
+ }
+
+ PAM_LOG("Opened %s file", nologin);
+
+ if (fstat(fd, &st) == 0) {
+ mtmp = malloc(st.st_size + 1);
+ if (mtmp != NULL) {
+ ss = read(fd, mtmp, st.st_size);
+ if (ss > 0) {
+ mtmp[ss] = '\0';
+ pam_error(pamh, "%s", mtmp);
+ }
+ free(mtmp);
+ }
+ }
+
+ PAM_VERBOSE_ERROR("Administrator refusing you: %s", nologin);
+
+ close(fd);
+ login_close(lc);
+
+ return (PAM_AUTH_ERR);
+}
+
+PAM_MODULE_ENTRY("pam_nologin");
diff --git a/lib/libpam/modules/pam_passwdqc/Makefile b/lib/libpam/modules/pam_passwdqc/Makefile
new file mode 100644
index 000000000000..91ce72928a66
--- /dev/null
+++ b/lib/libpam/modules/pam_passwdqc/Makefile
@@ -0,0 +1,14 @@
+SRCDIR= ${SRCTOP}/contrib/pam_modules/pam_passwdqc
+.PATH: ${SRCDIR}
+
+LIB= pam_passwdqc
+SRCS= pam_passwdqc.c passwdqc_check.c passwdqc_random.c wordset_4k.c
+MAN= pam_passwdqc.8
+
+WARNS?= 2
+CFLAGS+= -I${SRCDIR}
+
+LIBADD+= crypt
+
+.include <bsd.lib.mk>
+
diff --git a/lib/libpam/modules/pam_passwdqc/Makefile.depend b/lib/libpam/modules/pam_passwdqc/Makefile.depend
new file mode 100644
index 000000000000..c056162bff30
--- /dev/null
+++ b/lib/libpam/modules/pam_passwdqc/Makefile.depend
@@ -0,0 +1,17 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libcrypt \
+ lib/libpam/libpam \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_passwdqc/pam_passwdqc.8 b/lib/libpam/modules/pam_passwdqc/pam_passwdqc.8
new file mode 100644
index 000000000000..755e93520427
--- /dev/null
+++ b/lib/libpam/modules/pam_passwdqc/pam_passwdqc.8
@@ -0,0 +1,265 @@
+.\" Copyright (c) 2000-2002 Solar Designer.
+.\" All rights reserved.
+.\" Copyright (c) 2001 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS and NAI Labs, the Security Research Division of Network
+.\" Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+.\" ("CBOSS"), as part of the DARPA CHATS research program.
+.\"
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd April 15, 2002
+.Dt PAM_PASSWDQC 8
+.Os
+.Sh NAME
+.Nm pam_passwdqc
+.Nd Password quality-control PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_passwdqc
+.Op Ar options
+.Sh DESCRIPTION
+The
+.Nm
+module is a simple password strength checking module for
+PAM.
+In addition to checking regular passwords, it offers support for
+passphrases and can provide randomly generated passwords.
+.Pp
+The
+.Nm
+module provides functionality for only one PAM category:
+password changing.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li password
+feature.
+.Pp
+The
+.Fn pam_chauthtok
+service function will ask the user for a new password, and verify that
+it meets certain minimum standards.
+If the chosen password is unsatisfactory, the service function returns
+.Dv PAM_AUTHTOK_ERR .
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width indent
+.It Xo
+.Sm off
+.Cm min No = Ar N0 , N1 , N2 , N3 , N4
+.Sm on
+.Xc
+.Sm off
+.Pq Cm min No = Cm disabled , No 24 , 12 , 8 , 7
+.Sm on
+The minimum allowed password lengths for different kinds of
+passwords/passphrases.
+The keyword
+.Cm disabled
+can be used to
+disallow passwords of a given kind regardless of their length.
+Each subsequent number is required to be no larger than the preceding
+one.
+.Pp
+.Ar N0
+is used for passwords consisting of characters from one character
+class only.
+The character classes are: digits, lower-case letters, upper-case
+letters, and other characters.
+There is also a special class for
+.No non- Ns Tn ASCII
+characters which could not
+be classified, but are assumed to be non-digits.
+.Pp
+.Ar N1
+is used for passwords consisting of characters from two character
+classes, which do not meet the requirements for a passphrase.
+.Pp
+.Ar N2
+is used for passphrases.
+A passphrase must consist of sufficient words (see the
+.Cm passphrase
+option below).
+.Pp
+.Ar N3
+and
+.Ar N4
+are used for passwords consisting of characters from three
+and four character classes, respectively.
+.Pp
+When calculating the number of character classes, upper-case letters
+used as the first character and digits used as the last character of a
+password are not counted.
+.Pp
+In addition to being sufficiently long, passwords are required to
+contain enough different characters for the character classes and
+the minimum length they have been checked against.
+.It Cm max Ns = Ns Ar N
+.Pq Cm max Ns = Ns 40
+The maximum allowed password length.
+This can be used to prevent users from setting passwords which may be
+too long for some system services.
+The value 8 is treated specially: if
+.Cm max
+is set to 8, passwords longer than 8 characters will not be rejected,
+but will be truncated to 8 characters for the strength checks and the
+user will be warned.
+This is for compatibility with the traditional DES password hashes,
+which truncate the password at 8 characters.
+.Pp
+It is important that you do set
+.Cm max Ns = Ns 8
+if you are using the traditional
+hashes, or some weak passwords will pass the checks.
+.It Cm passphrase Ns = Ns Ar N
+.Pq Cm passphrase Ns = Ns 3
+The number of words required for a passphrase, or 0 to disable
+passphrase support.
+.It Cm match Ns = Ns Ar N
+.Pq Cm match Ns = Ns 4
+The length of common substring required to conclude that a password is
+at least partially based on information found in a character string,
+or 0 to disable the substring search.
+Note that the password will not be rejected once a weak substring is
+found; it will instead be subjected to the usual strength requirements
+with the weak substring removed.
+.Pp
+The substring search is case-insensitive and is able to detect and
+remove a common substring spelled backwards.
+.It Xo
+.Sm off
+.Cm similar No = Cm permit | deny
+.Sm on
+.Xc
+.Pq Cm similar Ns = Ns Cm deny
+Whether a new password is allowed to be similar to the old one.
+The passwords are considered to be similar when there is a sufficiently
+long common substring and the new password with the substring removed
+would be weak.
+.It Xo
+.Sm off
+.Cm random No = Ar N Op , Cm only
+.Sm on
+.Xc
+.Pq Cm random Ns = Ns 42
+The size of randomly-generated passwords in bits, or 0 to disable this
+feature.
+Passwords that contain the offered randomly-generated string will be
+allowed regardless of other possible restrictions.
+.Pp
+The
+.Cm only
+modifier can be used to disallow user-chosen passwords.
+.It Xo
+.Sm off
+.Cm enforce No = Cm none | users | everyone
+.Sm on
+.Xc
+.Pq Cm enforce Ns = Ns Cm everyone
+The module can be configured to warn of weak passwords only, but not
+actually enforce strong passwords.
+The
+.Cm users
+setting will enforce strong passwords for non-root users only.
+.It Cm non-unix
+Normally,
+.Nm
+uses
+.Xr getpwnam 3
+to obtain the user's personal login information and use that during
+the password strength checks.
+This behavior can be disabled with the
+.Cm non-unix
+option.
+.It Cm retry Ns = Ns Ar N
+.Pq Cm retry Ns = Ns 3
+The number of times the module will ask for a new password if the user
+fails to provide a sufficiently strong password and enter it twice the
+first time.
+.It Cm ask_oldauthtok Ns Op = Ns Cm update
+Ask for the old password as well.
+Normally,
+.Nm
+leaves this task for subsequent modules.
+With no argument, the
+.Cm ask_oldauthtok
+option will cause
+.Nm
+to ask for the old password during the preliminary check phase.
+If the
+.Cm ask_oldauthtok
+option is specified with the
+.Cm update
+argument,
+.Nm
+will do that during the update phase.
+.It Cm check_oldauthtok
+This tells
+.Nm
+to validate the old password before giving a
+new password prompt.
+Normally, this task is left for subsequent modules.
+.Pp
+The primary use for this option is when
+.Cm ask_oldauthtok Ns = Ns Cm update
+is also specified, in which case no other modules gets a chance to ask
+for and validate the password.
+Of course, this will only work with
+.Ux
+passwords.
+.It Cm use_first_pass , use_authtok
+Use the new password obtained by modules stacked before
+.Nm .
+This disables user interaction within
+.Nm .
+The only difference between
+.Cm use_first_pass
+and
+.Cm use_authtok
+is that the former is incompatible with
+.Cm ask_oldauthtok .
+.El
+.Sh SEE ALSO
+.Xr getpwnam 3 ,
+.Xr pam 3 ,
+.Xr pam.conf 5
+.Sh AUTHORS
+The
+.Nm
+module was written by
+.An Solar Designer Aq Mt solar@openwall.com .
+This manual page, derived from the author's documentation, was written
+for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_permit/Makefile b/lib/libpam/modules/pam_permit/Makefile
new file mode 100644
index 000000000000..5606fe1cf75a
--- /dev/null
+++ b/lib/libpam/modules/pam_permit/Makefile
@@ -0,0 +1,30 @@
+# Copyright 1999 Max Khon.
+# 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, this list of conditions and the following disclaimer.
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+#
+
+LIB= pam_permit
+SRCS= pam_permit.c
+MAN= pam_permit.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_permit/Makefile.depend b/lib/libpam/modules/pam_permit/Makefile.depend
new file mode 100644
index 000000000000..a8b8ddf9d074
--- /dev/null
+++ b/lib/libpam/modules/pam_permit/Makefile.depend
@@ -0,0 +1,15 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_permit/pam_permit.8 b/lib/libpam/modules/pam_permit/pam_permit.8
new file mode 100644
index 000000000000..270eaee8361d
--- /dev/null
+++ b/lib/libpam/modules/pam_permit/pam_permit.8
@@ -0,0 +1,73 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd July 7, 2001
+.Dt PAM_PERMIT 8
+.Os
+.Sh NAME
+.Nm pam_permit
+.Nd Promiscuous PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_permit
+.Op Ar options
+.Sh DESCRIPTION
+The Promiscuous authentication service module for PAM,
+.Nm
+provides functionality for all the PAM categories:
+authentication,
+account management,
+session management and
+password management.
+In terms of the
+.Ar module-type
+parameter, these are the
+.Dq Li auth ,
+.Dq Li account ,
+.Dq Li session ,
+and
+.Dq Li password
+features.
+.Pp
+The Promiscuous module
+will universally allow all requests.
+It is primarily of use during testing,
+and to silence
+.Dq noisy
+PAM-enabled applications.
+.Pp
+The following options may be passed to the module:
+.Bl -tag -width ".Cm debug"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.El
+.Sh SEE ALSO
+.Xr pam 3 ,
+.Xr syslog 3 ,
+.Xr pam.conf 5
diff --git a/lib/libpam/modules/pam_permit/pam_permit.c b/lib/libpam/modules/pam_permit/pam_permit.c
new file mode 100644
index 000000000000..9dfc76ce5cf2
--- /dev/null
+++ b/lib/libpam/modules/pam_permit/pam_permit.c
@@ -0,0 +1,93 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright 2001 Mark R V Murray
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/cdefs.h>
+#include <stddef.h>
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_SESSION
+#define PAM_SM_PASSWORD
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ const char *user;
+ int r;
+
+ if ((r = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS)
+ return (r);
+
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_chauthtok(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_permit");
diff --git a/lib/libpam/modules/pam_radius/Makefile b/lib/libpam/modules/pam_radius/Makefile
new file mode 100644
index 000000000000..ab39fedcee04
--- /dev/null
+++ b/lib/libpam/modules/pam_radius/Makefile
@@ -0,0 +1,33 @@
+# Copyright 1998 Juniper Networks, Inc.
+# 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, this list of conditions and the following disclaimer.
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+#
+
+LIB= pam_radius
+SRCS= pam_radius.c
+MAN= pam_radius.8
+WARNS?= 3
+
+LIBADD+= radius
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_radius/Makefile.depend b/lib/libpam/modules/pam_radius/Makefile.depend
new file mode 100644
index 000000000000..1e4d327901e8
--- /dev/null
+++ b/lib/libpam/modules/pam_radius/Makefile.depend
@@ -0,0 +1,17 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+ lib/libradius \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_radius/pam_radius.8 b/lib/libpam/modules/pam_radius/pam_radius.8
new file mode 100644
index 000000000000..abc916dcfff6
--- /dev/null
+++ b/lib/libpam/modules/pam_radius/pam_radius.8
@@ -0,0 +1,148 @@
+.\"-
+.\" Copyright (c) 1992, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\" Copyright (c) 1999 Andrzej Bialecki <abial@FreeBSD.org>
+.\" All rights reserved.
+.\" Copyright (c) 2018 The University of Oslo
+.\" All rights reserved.
+.\"
+.\" This code is derived from software donated to Berkeley by
+.\" Jan-Simon Pendry.
+.\"
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.Dd May 16, 2018
+.Dt PAM_RADIUS 8
+.Os
+.Sh NAME
+.Nm pam_radius
+.Nd RADIUS authentication PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_radius
+.Op Ar options
+.Sh DESCRIPTION
+The
+.Nm
+module provides authentication services based
+upon the RADIUS (Remote Authentication Dial In User Service) protocol
+for the PAM (Pluggable Authentication Module) framework.
+.Pp
+The
+.Nm
+module accepts these optional parameters:
+.Bl -tag -width Fl
+.It Cm use_first_pass
+causes
+.Nm
+to use a previously entered password instead of prompting for a new one.
+If no password has been entered then authentication fails.
+.It Cm try_first_pass
+causes
+.Nm
+to use a previously entered password, if one is available.
+If no
+password has been entered,
+.Nm
+prompts for one as usual.
+.It Cm echo_pass
+causes echoing to be left on if
+.Nm
+prompts for a password.
+.It Cm conf Ns = Ns Ar pathname
+specifies a non-standard location for the RADIUS client configuration file
+(normally located in
+.Pa /etc/radius.conf ) .
+.It Cm nas_id Ns = Ns Ar identifier
+specifies a NAS identifier to send instead of the hostname.
+.It Cm nas_ipaddr Ns Op No = Ns Ar address
+specifies a NAS IP address to be sent.
+If option is present, but there is no value provided then IP address
+corresponding to the current hostname will be used.
+.It Cm template_user Ns = Ns Ar username
+specifies a user whose
+.Xr passwd 5
+entry will be used as a template to create the session environment
+if the supplied username does not exist in local password database.
+The user
+will be authenticated with the supplied username and password, but his
+credentials to the system will be presented as the ones for
+.Ar username ,
+i.e., his login class, home directory, resource limits, etc.\& will be set to ones
+defined for
+.Ar username .
+.Pp
+If this option is omitted, and there is no username
+in the system databases equal to the supplied one (as determined by call to
+.Xr getpwnam 3 ) ,
+the authentication will fail.
+.It Cm no_reply_message
+suppress printing of the contents of any
+.Cm Reply-Message
+attributes found in
+.Cm Access-Accept
+and
+.Cm Access-Reject
+responses.
+These are normally conveyed to the user as either informational or
+error messages, depending on whether the access request was accepted
+or rejected.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include reasons why the user's authentication attempt
+was declined.
+.El
+.Sh FILES
+.Bl -tag -width /etc/radius.conf -compact
+.It Pa /etc/radius.conf
+The standard RADIUS client configuration file for
+.Nm
+.El
+.Sh SEE ALSO
+.Xr pam 3 ,
+.Xr passwd 5 ,
+.Xr radius.conf 5
+.Sh HISTORY
+The
+.Nm
+module first appeared in
+.Fx 3.1 .
+The
+.Nm
+manual page first appeared in
+.Fx 3.3 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+manual page was written by
+.An Andrzej Bialecki Aq Mt abial@FreeBSD.org .
+.Pp
+The
+.Nm
+module was written by
+.An John D. Polstra Aq Mt jdp@FreeBSD.org .
diff --git a/lib/libpam/modules/pam_radius/pam_radius.c b/lib/libpam/modules/pam_radius/pam_radius.c
new file mode 100644
index 000000000000..027916b38138
--- /dev/null
+++ b/lib/libpam/modules/pam_radius/pam_radius.c
@@ -0,0 +1,417 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright 1998 Juniper Networks, Inc.
+ * All rights reserved.
+ * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ * Copyright (c) 2015-2018 The University of Oslo
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/param.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <radlib.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define PAM_SM_AUTH
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#define PAM_OPT_CONF "conf"
+#define PAM_OPT_TEMPLATE_USER "template_user"
+#define PAM_OPT_NAS_ID "nas_id"
+#define PAM_OPT_NAS_IPADDR "nas_ipaddr"
+#define PAM_OPT_NO_REPLYMSG "no_reply_message"
+
+#define MAX_CHALLENGE_MSGS 10
+#define PASSWORD_PROMPT "RADIUS Password:"
+
+static int build_access_request(struct rad_handle *, const char *,
+ const char *, const char *, const char *, const char *,
+ const void *, size_t);
+static int do_accept(pam_handle_t *, struct rad_handle *);
+static int do_challenge(pam_handle_t *, struct rad_handle *,
+ const char *, const char *, const char *, const char *);
+
+/*
+ * Construct an access request, but don't send it. Returns 0 on success,
+ * -1 on failure.
+ */
+static int
+build_access_request(struct rad_handle *radh, const char *user,
+ const char *pass, const char *nas_id, const char *nas_ipaddr,
+ const char *rhost, const void *state, size_t state_len)
+{
+ int error;
+ char host[MAXHOSTNAMELEN];
+ struct sockaddr_in *haddr;
+ struct addrinfo hints;
+ struct addrinfo *res;
+
+ if (rad_create_request(radh, RAD_ACCESS_REQUEST) == -1) {
+ syslog(LOG_CRIT, "rad_create_request: %s", rad_strerror(radh));
+ return (-1);
+ }
+ if (nas_id == NULL ||
+ (nas_ipaddr != NULL && strlen(nas_ipaddr) == 0)) {
+ if (gethostname(host, sizeof host) != -1) {
+ if (nas_id == NULL)
+ nas_id = host;
+ if (nas_ipaddr != NULL && strlen(nas_ipaddr) == 0)
+ nas_ipaddr = host;
+ }
+ }
+ if ((user != NULL &&
+ rad_put_string(radh, RAD_USER_NAME, user) == -1) ||
+ (pass != NULL &&
+ rad_put_string(radh, RAD_USER_PASSWORD, pass) == -1) ||
+ (nas_id != NULL &&
+ rad_put_string(radh, RAD_NAS_IDENTIFIER, nas_id) == -1)) {
+ syslog(LOG_CRIT, "rad_put_string: %s", rad_strerror(radh));
+ return (-1);
+ }
+ if (nas_ipaddr != NULL) {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ if (getaddrinfo(nas_ipaddr, NULL, &hints, &res) == 0 &&
+ res != NULL && res->ai_family == AF_INET) {
+ haddr = (struct sockaddr_in *)res->ai_addr;
+ error = rad_put_addr(radh, RAD_NAS_IP_ADDRESS,
+ haddr->sin_addr);
+ freeaddrinfo(res);
+ if (error == -1) {
+ syslog(LOG_CRIT, "rad_put_addr: %s",
+ rad_strerror(radh));
+ return (-1);
+ }
+ }
+ }
+ if (rhost != NULL &&
+ rad_put_string(radh, RAD_CALLING_STATION_ID, rhost) == -1) {
+ syslog(LOG_CRIT, "rad_put_string: %s", rad_strerror(radh));
+ return (-1);
+ }
+ if (state != NULL &&
+ rad_put_attr(radh, RAD_STATE, state, state_len) == -1) {
+ syslog(LOG_CRIT, "rad_put_attr: %s", rad_strerror(radh));
+ return (-1);
+ }
+ if (rad_put_int(radh, RAD_SERVICE_TYPE, RAD_AUTHENTICATE_ONLY) == -1) {
+ syslog(LOG_CRIT, "rad_put_int: %s", rad_strerror(radh));
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+do_accept(pam_handle_t *pamh, struct rad_handle *radh)
+{
+ int attrtype;
+ const void *attrval;
+ size_t attrlen;
+ char *s;
+
+ while ((attrtype = rad_get_attr(radh, &attrval, &attrlen)) > 0) {
+ switch (attrtype) {
+ case RAD_USER_NAME:
+ if ((s = rad_cvt_string(attrval, attrlen)) == NULL)
+ goto enomem;
+ pam_set_item(pamh, PAM_USER, s);
+ free(s);
+ break;
+ case RAD_REPLY_MESSAGE:
+ if ((s = rad_cvt_string(attrval, attrlen)) == NULL)
+ goto enomem;
+ if (!openpam_get_option(pamh, PAM_OPT_NO_REPLYMSG))
+ pam_info(pamh, "%s", s);
+ free(s);
+ break;
+ default:
+ PAM_LOG("%s(): ignoring RADIUS attribute %d",
+ __func__, attrtype);
+ }
+ }
+ if (attrtype == -1) {
+ syslog(LOG_CRIT, "rad_get_attr: %s", rad_strerror(radh));
+ return (-1);
+ }
+ return (0);
+enomem:
+ syslog(LOG_CRIT, "%s(): out of memory", __func__);
+ return (-1);
+}
+
+static int
+do_reject(pam_handle_t *pamh, struct rad_handle *radh)
+{
+ int attrtype;
+ const void *attrval;
+ size_t attrlen;
+ char *s;
+
+ while ((attrtype = rad_get_attr(radh, &attrval, &attrlen)) > 0) {
+ switch (attrtype) {
+ case RAD_REPLY_MESSAGE:
+ if ((s = rad_cvt_string(attrval, attrlen)) == NULL)
+ goto enomem;
+ if (!openpam_get_option(pamh, PAM_OPT_NO_REPLYMSG))
+ pam_error(pamh, "%s", s);
+ free(s);
+ break;
+ default:
+ PAM_LOG("%s(): ignoring RADIUS attribute %d",
+ __func__, attrtype);
+ }
+ }
+ if (attrtype < 0) {
+ syslog(LOG_CRIT, "rad_get_attr: %s", rad_strerror(radh));
+ return (-1);
+ }
+ return (0);
+enomem:
+ syslog(LOG_CRIT, "%s(): out of memory", __func__);
+ return (-1);
+}
+
+static int
+do_challenge(pam_handle_t *pamh, struct rad_handle *radh, const char *user,
+ const char *nas_id, const char *nas_ipaddr, const char *rhost)
+{
+ int retval;
+ int attrtype;
+ const void *attrval;
+ size_t attrlen;
+ const void *state;
+ size_t statelen;
+ struct pam_message msgs[MAX_CHALLENGE_MSGS];
+ const struct pam_message *msg_ptrs[MAX_CHALLENGE_MSGS];
+ struct pam_response *resp;
+ int num_msgs;
+ const void *item;
+ const struct pam_conv *conv;
+
+ state = NULL;
+ statelen = 0;
+ num_msgs = 0;
+ while ((attrtype = rad_get_attr(radh, &attrval, &attrlen)) > 0) {
+ switch (attrtype) {
+
+ case RAD_STATE:
+ state = attrval;
+ statelen = attrlen;
+ break;
+
+ case RAD_REPLY_MESSAGE:
+ if (num_msgs >= MAX_CHALLENGE_MSGS) {
+ syslog(LOG_CRIT,
+ "Too many RADIUS challenge messages");
+ return (PAM_SERVICE_ERR);
+ }
+ msgs[num_msgs].msg = rad_cvt_string(attrval, attrlen);
+ if (msgs[num_msgs].msg == NULL) {
+ syslog(LOG_CRIT,
+ "rad_cvt_string: out of memory");
+ return (PAM_SERVICE_ERR);
+ }
+ msgs[num_msgs].msg_style = PAM_TEXT_INFO;
+ msg_ptrs[num_msgs] = &msgs[num_msgs];
+ num_msgs++;
+ break;
+ }
+ }
+ if (attrtype == -1) {
+ syslog(LOG_CRIT, "rad_get_attr: %s", rad_strerror(radh));
+ return (PAM_SERVICE_ERR);
+ }
+ if (num_msgs == 0) {
+ msgs[num_msgs].msg = strdup("(null RADIUS challenge): ");
+ if (msgs[num_msgs].msg == NULL) {
+ syslog(LOG_CRIT, "Out of memory");
+ return (PAM_SERVICE_ERR);
+ }
+ msgs[num_msgs].msg_style = PAM_TEXT_INFO;
+ msg_ptrs[num_msgs] = &msgs[num_msgs];
+ num_msgs++;
+ }
+ msgs[num_msgs-1].msg_style = PAM_PROMPT_ECHO_ON;
+ if ((retval = pam_get_item(pamh, PAM_CONV, &item)) != PAM_SUCCESS) {
+ syslog(LOG_CRIT, "do_challenge: cannot get PAM_CONV");
+ return (retval);
+ }
+ conv = (const struct pam_conv *)item;
+ if ((retval = conv->conv(num_msgs, msg_ptrs, &resp,
+ conv->appdata_ptr)) != PAM_SUCCESS)
+ return (retval);
+ if (build_access_request(radh, user, resp[num_msgs-1].resp, nas_id,
+ nas_ipaddr, rhost, state, statelen) == -1)
+ return (PAM_SERVICE_ERR);
+ memset(resp[num_msgs-1].resp, 0, strlen(resp[num_msgs-1].resp));
+ free(resp[num_msgs-1].resp);
+ free(resp);
+ while (num_msgs > 0)
+ free(msgs[--num_msgs].msg);
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct rad_handle *radh;
+ const char *user, *pass;
+ const void *rhost, *tmpuser;
+ const char *conf_file, *template_user, *nas_id, *nas_ipaddr;
+ int retval;
+ int e;
+
+ conf_file = openpam_get_option(pamh, PAM_OPT_CONF);
+ template_user = openpam_get_option(pamh, PAM_OPT_TEMPLATE_USER);
+ nas_id = openpam_get_option(pamh, PAM_OPT_NAS_ID);
+ nas_ipaddr = openpam_get_option(pamh, PAM_OPT_NAS_IPADDR);
+ pam_get_item(pamh, PAM_RHOST, &rhost);
+
+ retval = pam_get_user(pamh, &user, NULL);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Got user: %s", user);
+
+ retval = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, PASSWORD_PROMPT);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Got password");
+
+ radh = rad_open();
+ if (radh == NULL) {
+ syslog(LOG_CRIT, "rad_open failed");
+ return (PAM_SERVICE_ERR);
+ }
+
+ PAM_LOG("Radius opened");
+
+ if (rad_config(radh, conf_file) == -1) {
+ syslog(LOG_ALERT, "rad_config: %s", rad_strerror(radh));
+ rad_close(radh);
+ return (PAM_SERVICE_ERR);
+ }
+
+ PAM_LOG("Radius config file read");
+
+ if (build_access_request(radh, user, pass, nas_id, nas_ipaddr, rhost,
+ NULL, 0) == -1) {
+ rad_close(radh);
+ return (PAM_SERVICE_ERR);
+ }
+
+ PAM_LOG("Radius build access done");
+
+ for (;;) {
+ switch (rad_send_request(radh)) {
+
+ case RAD_ACCESS_ACCEPT:
+ e = do_accept(pamh, radh);
+ rad_close(radh);
+ if (e == -1)
+ return (PAM_SERVICE_ERR);
+ if (template_user != NULL) {
+
+ PAM_LOG("Trying template user: %s",
+ template_user);
+
+ /*
+ * If the given user name doesn't exist in
+ * the local password database, change it
+ * to the value given in the "template_user"
+ * option.
+ */
+ retval = pam_get_item(pamh, PAM_USER, &tmpuser);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+ if (getpwnam(tmpuser) == NULL) {
+ pam_set_item(pamh, PAM_USER,
+ template_user);
+ PAM_LOG("Using template user");
+ }
+
+ }
+ return (PAM_SUCCESS);
+
+ case RAD_ACCESS_REJECT:
+ retval = do_reject(pamh, radh);
+ rad_close(radh);
+ PAM_VERBOSE_ERROR("Radius rejection");
+ return (PAM_AUTH_ERR);
+
+ case RAD_ACCESS_CHALLENGE:
+ retval = do_challenge(pamh, radh, user, nas_id,
+ nas_ipaddr, rhost);
+ if (retval != PAM_SUCCESS) {
+ rad_close(radh);
+ return (retval);
+ }
+ break;
+
+ case -1:
+ syslog(LOG_CRIT, "rad_send_request: %s",
+ rad_strerror(radh));
+ rad_close(radh);
+ PAM_VERBOSE_ERROR("Radius failure");
+ return (PAM_AUTHINFO_UNAVAIL);
+
+ default:
+ syslog(LOG_CRIT,
+ "rad_send_request: unexpected return value");
+ rad_close(radh);
+ PAM_VERBOSE_ERROR("Radius error");
+ return (PAM_SERVICE_ERR);
+ }
+ }
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_radius");
diff --git a/lib/libpam/modules/pam_rhosts/Makefile b/lib/libpam/modules/pam_rhosts/Makefile
new file mode 100644
index 000000000000..4cd25fe5dfa5
--- /dev/null
+++ b/lib/libpam/modules/pam_rhosts/Makefile
@@ -0,0 +1,5 @@
+LIB= pam_rhosts
+SRCS= pam_rhosts.c
+MAN= pam_rhosts.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_rhosts/Makefile.depend b/lib/libpam/modules/pam_rhosts/Makefile.depend
new file mode 100644
index 000000000000..0665960a2cd2
--- /dev/null
+++ b/lib/libpam/modules/pam_rhosts/Makefile.depend
@@ -0,0 +1,16 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_rhosts/pam_rhosts.8 b/lib/libpam/modules/pam_rhosts/pam_rhosts.8
new file mode 100644
index 000000000000..1f9716b9a0ca
--- /dev/null
+++ b/lib/libpam/modules/pam_rhosts/pam_rhosts.8
@@ -0,0 +1,93 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2001 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS and NAI Labs, the Security Research Division of Network
+.\" Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+.\" ("CBOSS"), as part of the DARPA CHATS research program.
+.\"
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd December 5, 2001
+.Dt PAM_RHOSTS 8
+.Os
+.Sh NAME
+.Nm pam_rhosts
+.Nd Rhosts PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_rhosts
+.Op Ar options
+.Sh DESCRIPTION
+The rhosts authentication service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+authentication.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li auth
+feature.
+.Ss Rhosts Authentication Module
+The Rhosts authentication component
+.Pq Fn pam_sm_authenticate ,
+returns success if and only if the target user's UID is not 0 and the
+remote host and user are listed in
+.Pa /etc/hosts.equiv
+or in the target user's
+.Pa ~/.rhosts .
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm allow_root"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include reasons why the user's authentication attempt
+was declined.
+.It Cm allow_root
+do not automatically fail if the target user's UID is 0.
+.El
+.Sh SEE ALSO
+.Xr pam 3 ,
+.Xr hosts.equiv 5 ,
+.Xr pam.conf 5
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_rhosts/pam_rhosts.c b/lib/libpam/modules/pam_rhosts/pam_rhosts.c
new file mode 100644
index 000000000000..597fb47e95c8
--- /dev/null
+++ b/lib/libpam/modules/pam_rhosts/pam_rhosts.c
@@ -0,0 +1,95 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2002 Danny Braniss
+ * All rights reserved.
+ * Copyright (c) 2001,2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/cdefs.h>
+#include <pwd.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+
+#define PAM_SM_AUTH
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#define OPT_ALLOW_ROOT "allow_root"
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct passwd *pw;
+ const char *user;
+ const void *ruser, *rhost;
+ int err, superuser;
+
+ err = pam_get_user(pamh, &user, NULL);
+ if (err != PAM_SUCCESS)
+ return (err);
+
+ if ((pw = getpwnam(user)) == NULL)
+ return (PAM_USER_UNKNOWN);
+ if (pw->pw_uid == 0 &&
+ openpam_get_option(pamh, OPT_ALLOW_ROOT) == NULL)
+ return (PAM_AUTH_ERR);
+
+ err = pam_get_item(pamh, PAM_RUSER, &ruser);
+ if (err != PAM_SUCCESS)
+ return (PAM_AUTH_ERR);
+
+ err = pam_get_item(pamh, PAM_RHOST, &rhost);
+ if (err != PAM_SUCCESS)
+ return (PAM_AUTH_ERR);
+
+ superuser = (strcmp(user, "root") == 0);
+ err = ruserok(rhost, superuser, ruser, user);
+ if (err != 0)
+ return (PAM_AUTH_ERR);
+
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_rhosts");
diff --git a/lib/libpam/modules/pam_rootok/Makefile b/lib/libpam/modules/pam_rootok/Makefile
new file mode 100644
index 000000000000..668eeef7f7d9
--- /dev/null
+++ b/lib/libpam/modules/pam_rootok/Makefile
@@ -0,0 +1,30 @@
+# Copyright 2001 Mark R V Murray
+# 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, this list of conditions and the following disclaimer.
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+#
+
+LIB= pam_rootok
+SRCS= pam_rootok.c
+MAN= pam_rootok.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_rootok/Makefile.depend b/lib/libpam/modules/pam_rootok/Makefile.depend
new file mode 100644
index 000000000000..a8b8ddf9d074
--- /dev/null
+++ b/lib/libpam/modules/pam_rootok/Makefile.depend
@@ -0,0 +1,15 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_rootok/pam_rootok.8 b/lib/libpam/modules/pam_rootok/pam_rootok.8
new file mode 100644
index 000000000000..fd0a6dd3791f
--- /dev/null
+++ b/lib/libpam/modules/pam_rootok/pam_rootok.8
@@ -0,0 +1,73 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd July 8, 2001
+.Dt PAM_ROOTOK 8
+.Os
+.Sh NAME
+.Nm pam_rootok
+.Nd RootOK PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_rootok
+.Op Ar options
+.Sh DESCRIPTION
+The RootOK authentication service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+authentication.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li auth
+feature.
+It also provides a null function for session management.
+.Ss RootOK Authentication Module
+The RootOK authentication component
+.Pq Fn pam_sm_authenticate ,
+always returns success for the superuser;
+i.e.,
+if
+.Xr getuid 2
+returns 0.
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm no_warn"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include
+reasons why the user's
+authentication attempt was declined.
+.El
+.Sh SEE ALSO
+.Xr getuid 2 ,
+.Xr pam 3 ,
+.Xr pam.conf 5
diff --git a/lib/libpam/modules/pam_rootok/pam_rootok.c b/lib/libpam/modules/pam_rootok/pam_rootok.c
new file mode 100644
index 000000000000..d267d267ef27
--- /dev/null
+++ b/lib/libpam/modules/pam_rootok/pam_rootok.c
@@ -0,0 +1,73 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2001 Mark R V Murray
+ * All rights reserved.
+ * Copyright (c) 2001 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/cdefs.h>
+#define _BSD_SOURCE
+
+#include <unistd.h>
+#include <syslog.h>
+
+#define PAM_SM_AUTH
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ if (getuid() == 0)
+ return (PAM_SUCCESS);
+
+ PAM_VERBOSE_ERROR("Refused; not superuser");
+ PAM_LOG("User is not superuser");
+
+ return (PAM_AUTH_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_rootok");
diff --git a/lib/libpam/modules/pam_securetty/Makefile b/lib/libpam/modules/pam_securetty/Makefile
new file mode 100644
index 000000000000..3a36a37b543c
--- /dev/null
+++ b/lib/libpam/modules/pam_securetty/Makefile
@@ -0,0 +1,32 @@
+# Copyright 2001 Mark R V Murray
+# 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, this list of conditions and the following disclaimer.
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+#
+
+PACKAGE= runtime
+
+LIB= pam_securetty
+SRCS= pam_securetty.c
+MAN= pam_securetty.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_securetty/Makefile.depend b/lib/libpam/modules/pam_securetty/Makefile.depend
new file mode 100644
index 000000000000..0665960a2cd2
--- /dev/null
+++ b/lib/libpam/modules/pam_securetty/Makefile.depend
@@ -0,0 +1,16 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_securetty/pam_securetty.8 b/lib/libpam/modules/pam_securetty/pam_securetty.8
new file mode 100644
index 000000000000..582389cf101d
--- /dev/null
+++ b/lib/libpam/modules/pam_securetty/pam_securetty.8
@@ -0,0 +1,90 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2002 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS and NAI Labs, the Security Research Division of Network
+.\" Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+.\" ("CBOSS"), as part of the DARPA CHATS research program.
+.\"
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd July 8, 2001
+.Dt PAM_SECURETTY 8
+.Os
+.Sh NAME
+.Nm pam_securetty
+.Nd SecureTTY PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_securetty
+.Op Ar options
+.Sh DESCRIPTION
+The SecureTTY service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+account management.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li account
+feature.
+It also provides null functions for authentication and session
+management.
+.Ss SecureTTY Account Management Module
+The SecureTTY account management component
+.Pq Fn pam_sm_acct_mgmt ,
+returns failure if the user is attempting to authenticate as superuser,
+and the process is attached to an insecure TTY.
+In all other cases, the module returns success.
+.Pp
+A TTY is considered secure if it is listed in
+.Pa /etc/ttys
+and has the
+.Dv TTY_SECURE
+flag set.
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm no_warn"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include
+reasons why the user's
+authentication attempt was declined.
+.El
+.Sh SEE ALSO
+.Xr getttynam 3 ,
+.Xr pam 3 ,
+.Xr syslog 3 ,
+.Xr pam.conf 5 ,
+.Xr ttys 5
diff --git a/lib/libpam/modules/pam_securetty/pam_securetty.c b/lib/libpam/modules/pam_securetty/pam_securetty.c
new file mode 100644
index 000000000000..4f05961e2737
--- /dev/null
+++ b/lib/libpam/modules/pam_securetty/pam_securetty.c
@@ -0,0 +1,95 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2001 Mark R V Murray
+ * All rights reserved.
+ * Copyright (c) 2001 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <ttyent.h>
+#include <string.h>
+
+#define PAM_SM_ACCOUNT
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#define TTY_PREFIX "/dev/"
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct passwd *pwd;
+ struct ttyent *ty;
+ const char *user;
+ const void *tty;
+ int pam_err;
+
+ pam_err = pam_get_user(pamh, &user, NULL);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+ if (user == NULL || (pwd = getpwnam(user)) == NULL)
+ return (PAM_SERVICE_ERR);
+
+ PAM_LOG("Got user: %s", user);
+
+ /* If the user is not root, secure ttys do not apply */
+ if (pwd->pw_uid != 0)
+ return (PAM_SUCCESS);
+
+ pam_err = pam_get_item(pamh, PAM_TTY, &tty);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ PAM_LOG("Got TTY: %s", (const char *)tty);
+
+ /* Ignore any "/dev/" on the PAM_TTY item */
+ if (tty != NULL && strncmp(TTY_PREFIX, tty, sizeof(TTY_PREFIX)) == 0) {
+ PAM_LOG("WARNING: PAM_TTY starts with " TTY_PREFIX);
+ tty = (const char *)tty + sizeof(TTY_PREFIX) - 1;
+ }
+
+ if (tty != NULL && (ty = getttynam(tty)) != NULL &&
+ (ty->ty_status & TTY_SECURE) != 0)
+ return (PAM_SUCCESS);
+
+ PAM_VERBOSE_ERROR("Not on secure TTY");
+ return (PAM_AUTH_ERR);
+}
+
+PAM_MODULE_ENTRY("pam_securetty");
diff --git a/lib/libpam/modules/pam_self/Makefile b/lib/libpam/modules/pam_self/Makefile
new file mode 100644
index 000000000000..0a58728fea52
--- /dev/null
+++ b/lib/libpam/modules/pam_self/Makefile
@@ -0,0 +1,32 @@
+# Copyright 2001 Mark R V Murray
+# 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, this list of conditions and the following disclaimer.
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+#
+
+PACKAGE= runtime
+
+LIB= pam_self
+SRCS= pam_self.c
+MAN= pam_self.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_self/Makefile.depend b/lib/libpam/modules/pam_self/Makefile.depend
new file mode 100644
index 000000000000..a8b8ddf9d074
--- /dev/null
+++ b/lib/libpam/modules/pam_self/Makefile.depend
@@ -0,0 +1,15 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_self/pam_self.8 b/lib/libpam/modules/pam_self/pam_self.8
new file mode 100644
index 000000000000..f875d671286b
--- /dev/null
+++ b/lib/libpam/modules/pam_self/pam_self.8
@@ -0,0 +1,94 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2001 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed for the FreeBSD Project by
+.\" ThinkSec AS and NAI Labs, the Security Research Division of Network
+.\" Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+.\" ("CBOSS"), as part of the DARPA CHATS research program.
+.\"
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd December 5, 2001
+.Dt PAM_SELF 8
+.Os
+.Sh NAME
+.Nm pam_self
+.Nd Self PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_self
+.Op Ar options
+.Sh DESCRIPTION
+The Self authentication service module for PAM,
+.Nm
+provides functionality for only one PAM category:
+authentication.
+In terms of the
+.Ar module-type
+parameter, this is the
+.Dq Li auth
+feature.
+.Ss Self Authentication Module
+The Self authentication component
+.Pq Fn pam_sm_authenticate ,
+returns success if and only if the target user's user ID is identical
+with the current real user ID.
+If the current real user ID is zero, authentication will fail,
+unless the
+.Cm allow_root
+option was specified.
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm allow_root"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include reasons why the user's authentication attempt
+was declined.
+.It Cm allow_root
+do not automatically fail if the current real user ID is 0.
+.El
+.Sh SEE ALSO
+.Xr getuid 2 ,
+.Xr pam 3 ,
+.Xr pam.conf 5
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
diff --git a/lib/libpam/modules/pam_self/pam_self.c b/lib/libpam/modules/pam_self/pam_self.c
new file mode 100644
index 000000000000..fceb6466d8fb
--- /dev/null
+++ b/lib/libpam/modules/pam_self/pam_self.c
@@ -0,0 +1,89 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2001 Mark R V Murray
+ * All rights reserved.
+ * Copyright (c) 2001,2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/cdefs.h>
+#define _BSD_SOURCE
+
+#include <pwd.h>
+#include <unistd.h>
+#include <syslog.h>
+
+#define PAM_SM_AUTH
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#define OPT_ALLOW_ROOT "allow_root"
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct passwd *pwd;
+ const char *luser;
+ int pam_err;
+ uid_t uid;
+
+ pam_err = pam_get_user(pamh, &luser, NULL);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+ if (luser == NULL || (pwd = getpwnam(luser)) == NULL)
+ return (PAM_AUTH_ERR);
+
+ uid = getuid();
+ if (uid == 0 && !openpam_get_option(pamh, OPT_ALLOW_ROOT))
+ return (PAM_AUTH_ERR);
+
+ if (uid == (uid_t)pwd->pw_uid)
+ return (PAM_SUCCESS);
+
+ PAM_VERBOSE_ERROR("Refused; source and target users differ");
+
+ return (PAM_AUTH_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_self");
diff --git a/lib/libpam/modules/pam_ssh/Makefile b/lib/libpam/modules/pam_ssh/Makefile
new file mode 100644
index 000000000000..6652244a84af
--- /dev/null
+++ b/lib/libpam/modules/pam_ssh/Makefile
@@ -0,0 +1,18 @@
+# PAM module for SSH
+
+SSHDIR= ${SRCTOP}/crypto/openssh
+
+LIB= pam_ssh
+MAN= pam_ssh.8
+SRCS= pam_ssh.c
+PACKAGE= ssh
+
+WARNS?= 5
+CFLAGS+= -I${SSHDIR} -include ssh_namespace.h
+SRCS+= ssh_namespace.h
+
+LIBADD= ssh
+
+.include <bsd.lib.mk>
+
+.PATH: ${SSHDIR}
diff --git a/lib/libpam/modules/pam_ssh/Makefile.depend b/lib/libpam/modules/pam_ssh/Makefile.depend
new file mode 100644
index 000000000000..7cba2082bc24
--- /dev/null
+++ b/lib/libpam/modules/pam_ssh/Makefile.depend
@@ -0,0 +1,18 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+ secure/lib/libcrypto \
+ secure/lib/libssh \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_ssh/pam_ssh.8 b/lib/libpam/modules/pam_ssh/pam_ssh.8
new file mode 100644
index 000000000000..3ef44d8b687b
--- /dev/null
+++ b/lib/libpam/modules/pam_ssh/pam_ssh.8
@@ -0,0 +1,157 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" Copyright (c) 2001-2003 Networks Associates Technology, Inc.
+.\" Copyright (c) 2004-2011 Dag-Erling Smørgrav
+.\" All rights reserved.
+.\"
+.\" This software was developed for the FreeBSD Project by ThinkSec AS and
+.\" NAI Labs, the Security Research Division of Network Associates, Inc.
+.\" under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
+.\" DARPA CHATS research program.
+.\"
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd October 7, 2011
+.Dt PAM_SSH 8
+.Os
+.Sh NAME
+.Nm pam_ssh
+.Nd authentication and session management with SSH private keys
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_ssh
+.Op Ar options
+.Sh DESCRIPTION
+The
+SSH
+authentication service module for PAM,
+.Nm
+provides functionality for two PAM categories:
+authentication
+and session management.
+In terms of the
+.Ar module-type
+parameter, they are the
+.Dq Li auth
+and
+.Dq Li session
+features.
+.Ss SSH Authentication Module
+The
+SSH
+authentication component
+provides a function to verify the identity of a user
+.Pq Fn pam_sm_authenticate ,
+by prompting the user for a passphrase and verifying that it can
+decrypt the target user's SSH key using that passphrase.
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm use_first_pass
+If the authentication module
+is not the first in the stack,
+and a previous module
+obtained the user's password,
+that password is used
+to authenticate the user.
+If this fails,
+the authentication module returns failure
+without prompting the user for a password.
+This option has no effect
+if the authentication module
+is the first in the stack,
+or if no previous modules
+obtained the user's password.
+.It Cm try_first_pass
+This option is similar to the
+.Cm use_first_pass
+option,
+except that if the previously obtained password fails,
+the user is prompted for another password.
+.It Cm nullok
+Normally, keys with no passphrase are ignored for authentication
+purposes.
+If this option is set, keys with no passphrase will be taken into
+consideration, allowing the user to log in with a blank password.
+.El
+.Ss SSH Session Management Module
+The
+SSH
+session management component
+provides functions to initiate
+.Pq Fn pam_sm_open_session
+and terminate
+.Pq Fn pam_sm_close_session
+sessions.
+The
+.Fn pam_sm_open_session
+function starts an SSH agent,
+passing it any private keys it decrypted
+during the authentication phase,
+and sets the environment variables
+the agent specifies.
+The
+.Fn pam_sm_close_session
+function kills the previously started SSH agent
+by sending it a
+.Dv SIGTERM .
+.Pp
+The following options may be passed to the session management module:
+.Bl -tag -width ".Cm want_agent"
+.It Cm want_agent
+Start an agent even if no keys were decrypted during the
+authentication phase.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa $HOME/.ssh/id_ed25519" -compact
+.It Pa $HOME/.ssh/id_rsa
+SSH2 RSA key
+.It Pa $HOME/.ssh/id_dsa
+SSH2 DSA key
+.It Pa $HOME/.ssh/id_ecdsa
+SSH2 ECDSA key
+.It Pa $HOME/.ssh/id_ed25519
+SSH2 Ed25519 key
+.El
+.Sh SEE ALSO
+.Xr ssh-agent 1 ,
+.Xr pam 3 ,
+.Xr pam.conf 5
+.Sh AUTHORS
+The
+.Nm
+module was originally written by
+.An -nosplit
+.An Andrew J. Korty Aq Mt ajk@iu.edu .
+The current implementation was developed for the
+.Fx
+Project by
+ThinkSec AS and NAI Labs, the Security Research Division of Network
+Associates, Inc.\& under DARPA/SPAWAR contract N66001-01-C-8035
+.Pq Dq CBOSS ,
+as part of the DARPA CHATS research program.
+This manual page was written by
+.An Mark R V Murray Aq Mt markm@FreeBSD.org .
diff --git a/lib/libpam/modules/pam_ssh/pam_ssh.c b/lib/libpam/modules/pam_ssh/pam_ssh.c
new file mode 100644
index 000000000000..157908b6b910
--- /dev/null
+++ b/lib/libpam/modules/pam_ssh/pam_ssh.c
@@ -0,0 +1,442 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * Copyright (c) 2004-2011 Dag-Erling Smørgrav
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS and
+ * NAI Labs, the Security Research Division of Network Associates, Inc.
+ * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
+ * DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/param.h>
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#define PAM_SM_AUTH
+#define PAM_SM_SESSION
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/openpam.h>
+
+#include <openssl/evp.h>
+
+#define __bounded__(x, y, z)
+#include "authfd.h"
+#include "authfile.h"
+#include "sshkey.h"
+
+#define ssh_add_identity(auth, key, comment) \
+ ssh_add_identity_constrained(auth, key, comment, 0, 0, 0, NULL, NULL, 0)
+
+extern char **environ;
+
+struct pam_ssh_key {
+ struct sshkey *key;
+ char *comment;
+};
+
+static const char *pam_ssh_prompt = "SSH passphrase: ";
+static const char *pam_ssh_have_keys = "pam_ssh_have_keys";
+
+static const char *pam_ssh_keyfiles[] = {
+ ".ssh/id_rsa", /* SSH2 RSA key */
+ ".ssh/id_dsa", /* SSH2 DSA key */
+ ".ssh/id_ecdsa", /* SSH2 ECDSA key */
+ ".ssh/id_ed25519", /* SSH2 Ed25519 key */
+ NULL
+};
+
+static const char *pam_ssh_agent = "/usr/bin/ssh-agent";
+static char str_ssh_agent[] = "ssh-agent";
+static char str_dash_s[] = "-s";
+static char *const pam_ssh_agent_argv[] = { str_ssh_agent, str_dash_s, NULL };
+static char *const pam_ssh_agent_envp[] = { NULL };
+
+/*
+ * Attempts to load a private key from the specified file in the specified
+ * directory, using the specified passphrase. If successful, returns a
+ * struct pam_ssh_key containing the key and its comment.
+ */
+static struct pam_ssh_key *
+pam_ssh_load_key(const char *dir, const char *kfn, const char *passphrase,
+ int nullok)
+{
+ char fn[PATH_MAX];
+ struct pam_ssh_key *psk;
+ struct sshkey *key;
+ char *comment;
+ int ret;
+
+ if (snprintf(fn, sizeof(fn), "%s/%s", dir, kfn) > (int)sizeof(fn))
+ return (NULL);
+ /*
+ * If the key is unencrypted, OpenSSL ignores the passphrase, so
+ * it will seem like the user typed in the right one. This allows
+ * a user to circumvent nullok by providing a dummy passphrase.
+ * Verify that the key really *is* encrypted by trying to load it
+ * with an empty passphrase, and if the key is not encrypted,
+ * accept only an empty passphrase.
+ */
+ ret = sshkey_load_private(fn, "", &key, &comment);
+ if (ret == 0 && !(*passphrase == '\0' && nullok)) {
+ sshkey_free(key);
+ return (NULL);
+ }
+ if (ret != 0)
+ ret = sshkey_load_private(fn, passphrase, &key, &comment);
+ if (ret != 0) {
+ openpam_log(PAM_LOG_DEBUG, "failed to load key from %s", fn);
+ return (NULL);
+ }
+
+ openpam_log(PAM_LOG_DEBUG, "loaded '%s' from %s", comment, fn);
+ if ((psk = malloc(sizeof(*psk))) == NULL) {
+ sshkey_free(key);
+ free(comment);
+ return (NULL);
+ }
+ psk->key = key;
+ psk->comment = comment;
+ return (psk);
+}
+
+/*
+ * Wipes a private key and frees the associated resources.
+ */
+static void
+pam_ssh_free_key(pam_handle_t *pamh __unused,
+ void *data, int pam_err __unused)
+{
+ struct pam_ssh_key *psk;
+
+ psk = data;
+ sshkey_free(psk->key);
+ free(psk->comment);
+ free(psk);
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ const char **kfn, *passphrase, *user;
+ const void *item;
+ struct passwd *pwd;
+ struct pam_ssh_key *psk;
+ int nkeys, nullok, pam_err, pass;
+
+ nullok = (openpam_get_option(pamh, "nullok") != NULL);
+
+ /* PEM is not loaded by default */
+ OpenSSL_add_all_algorithms();
+
+ /* get user name and home directory */
+ pam_err = pam_get_user(pamh, &user, NULL);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+ pwd = getpwnam(user);
+ if (pwd == NULL)
+ return (PAM_USER_UNKNOWN);
+ if (pwd->pw_dir == NULL)
+ return (PAM_AUTH_ERR);
+
+ nkeys = 0;
+ pass = (pam_get_item(pamh, PAM_AUTHTOK, &item) == PAM_SUCCESS &&
+ item != NULL);
+ load_keys:
+ /* get passphrase */
+ pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
+ &passphrase, pam_ssh_prompt);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ /* switch to user credentials */
+ pam_err = openpam_borrow_cred(pamh, pwd);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ /* try to load keys from all keyfiles we know of */
+ for (kfn = pam_ssh_keyfiles; *kfn != NULL; ++kfn) {
+ psk = pam_ssh_load_key(pwd->pw_dir, *kfn, passphrase, nullok);
+ if (psk != NULL) {
+ pam_set_data(pamh, *kfn, psk, pam_ssh_free_key);
+ ++nkeys;
+ }
+ }
+
+ /* switch back to arbitrator credentials */
+ openpam_restore_cred(pamh);
+
+ /*
+ * If we tried an old token and didn't get anything, and
+ * try_first_pass was specified, try again after prompting the
+ * user for a new passphrase.
+ */
+ if (nkeys == 0 && pass == 1 &&
+ openpam_get_option(pamh, "try_first_pass") != NULL) {
+ pam_set_item(pamh, PAM_AUTHTOK, NULL);
+ pass = 0;
+ goto load_keys;
+ }
+
+ /* no keys? */
+ if (nkeys == 0)
+ return (PAM_AUTH_ERR);
+
+ pam_set_data(pamh, pam_ssh_have_keys, NULL, NULL);
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+/*
+ * Parses a line from ssh-agent's output.
+ */
+static void
+pam_ssh_process_agent_output(pam_handle_t *pamh, FILE *f)
+{
+ char *line, *p, *key, *val;
+ size_t len;
+
+ while ((line = fgetln(f, &len)) != NULL) {
+ if (len < 4 || strncmp(line, "SSH_", 4) != 0)
+ continue;
+
+ /* find equal sign at end of key */
+ for (p = key = line; p < line + len; ++p)
+ if (*p == '=')
+ break;
+ if (p == line + len || *p != '=')
+ continue;
+ *p = '\0';
+
+ /* find semicolon at end of value */
+ for (val = ++p; p < line + len; ++p)
+ if (*p == ';')
+ break;
+ if (p == line + len || *p != ';')
+ continue;
+ *p = '\0';
+
+ /* store key-value pair in environment */
+ openpam_log(PAM_LOG_DEBUG, "got %s: %s", key, val);
+ pam_setenv(pamh, key, val, 1);
+ }
+}
+
+/*
+ * Starts an ssh agent and stores the environment variables derived from
+ * its output.
+ */
+static int
+pam_ssh_start_agent(pam_handle_t *pamh)
+{
+ int agent_pipe[2];
+ pid_t pid;
+ FILE *f;
+
+ /* get a pipe which we will use to read the agent's output */
+ if (pipe(agent_pipe) == -1)
+ return (PAM_SYSTEM_ERR);
+
+ /* start the agent */
+ openpam_log(PAM_LOG_DEBUG, "starting an ssh agent");
+ pid = fork();
+ if (pid == (pid_t)-1) {
+ /* failed */
+ close(agent_pipe[0]);
+ close(agent_pipe[1]);
+ return (PAM_SYSTEM_ERR);
+ }
+ if (pid == 0) {
+ int fd;
+
+ /* child: drop privs, close fds and start agent */
+ setgid(getegid());
+ setuid(geteuid());
+ close(STDIN_FILENO);
+ open(_PATH_DEVNULL, O_RDONLY);
+ dup2(agent_pipe[1], STDOUT_FILENO);
+ dup2(agent_pipe[1], STDERR_FILENO);
+ for (fd = 3; fd < getdtablesize(); ++fd)
+ close(fd);
+ execve(pam_ssh_agent, pam_ssh_agent_argv, pam_ssh_agent_envp);
+ _exit(127);
+ }
+
+ /* parent */
+ close(agent_pipe[1]);
+ if ((f = fdopen(agent_pipe[0], "r")) == NULL)
+ return (PAM_SYSTEM_ERR);
+ pam_ssh_process_agent_output(pamh, f);
+ fclose(f);
+
+ return (PAM_SUCCESS);
+}
+
+/*
+ * Adds previously stored keys to a running agent.
+ */
+static int
+pam_ssh_add_keys_to_agent(pam_handle_t *pamh)
+{
+ const struct pam_ssh_key *psk;
+ const char **kfn;
+ const void *item;
+ char **envlist, **env;
+ int fd, pam_err;
+
+ /* switch to PAM environment */
+ envlist = environ;
+ if ((environ = pam_getenvlist(pamh)) == NULL) {
+ environ = envlist;
+ return (PAM_SYSTEM_ERR);
+ }
+
+ /* get a connection to the agent */
+ if (ssh_get_authentication_socket(&fd) != 0) {
+ openpam_log(PAM_LOG_DEBUG, "failed to connect to the agent");
+ pam_err = PAM_SYSTEM_ERR;
+ goto end;
+ }
+
+ /* look for keys to add to it */
+ for (kfn = pam_ssh_keyfiles; *kfn != NULL; ++kfn) {
+ pam_err = pam_get_data(pamh, *kfn, &item);
+ if (pam_err == PAM_SUCCESS && item != NULL) {
+ psk = item;
+ if (ssh_add_identity(fd, psk->key, psk->comment) == 0)
+ openpam_log(PAM_LOG_DEBUG,
+ "added %s to ssh agent", psk->comment);
+ else
+ openpam_log(PAM_LOG_DEBUG, "failed "
+ "to add %s to ssh agent", psk->comment);
+ /* we won't need the key again, so wipe it */
+ pam_set_data(pamh, *kfn, NULL, NULL);
+ }
+ }
+ pam_err = PAM_SUCCESS;
+
+ /* disconnect from agent */
+ ssh_close_authentication_socket(fd);
+
+ end:
+ /* switch back to original environment */
+ for (env = environ; *env != NULL; ++env)
+ free(*env);
+ free(environ);
+ environ = envlist;
+
+ return (pam_err);
+}
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct passwd *pwd;
+ const char *user;
+ const void *data;
+ int pam_err;
+
+ /* no keys, no work */
+ if (pam_get_data(pamh, pam_ssh_have_keys, &data) != PAM_SUCCESS &&
+ openpam_get_option(pamh, "want_agent") == NULL)
+ return (PAM_SUCCESS);
+
+ /* switch to user credentials */
+ pam_err = pam_get_user(pamh, &user, NULL);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+ pwd = getpwnam(user);
+ if (pwd == NULL)
+ return (PAM_USER_UNKNOWN);
+ pam_err = openpam_borrow_cred(pamh, pwd);
+ if (pam_err != PAM_SUCCESS)
+ return (pam_err);
+
+ /* start the agent */
+ pam_err = pam_ssh_start_agent(pamh);
+ if (pam_err != PAM_SUCCESS) {
+ openpam_restore_cred(pamh);
+ return (pam_err);
+ }
+
+ /* we have an agent, see if we can add any keys to it */
+ pam_err = pam_ssh_add_keys_to_agent(pamh);
+ if (pam_err != PAM_SUCCESS) {
+ /* XXX ignore failures */
+ }
+
+ openpam_restore_cred(pamh);
+ return (PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ const char *ssh_agent_pid;
+ char *end;
+ int status;
+ pid_t pid;
+
+ if ((ssh_agent_pid = pam_getenv(pamh, "SSH_AGENT_PID")) == NULL) {
+ openpam_log(PAM_LOG_DEBUG, "no ssh agent");
+ return (PAM_SUCCESS);
+ }
+ pid = (pid_t)strtol(ssh_agent_pid, &end, 10);
+ if (*ssh_agent_pid == '\0' || *end != '\0') {
+ openpam_log(PAM_LOG_DEBUG, "invalid ssh agent pid");
+ return (PAM_SESSION_ERR);
+ }
+ openpam_log(PAM_LOG_DEBUG, "killing ssh agent %d", (int)pid);
+ if (kill(pid, SIGTERM) == -1 ||
+ (waitpid(pid, &status, 0) == -1 && errno != ECHILD))
+ return (PAM_SYSTEM_ERR);
+ return (PAM_SUCCESS);
+}
+
+PAM_MODULE_ENTRY("pam_ssh");
diff --git a/lib/libpam/modules/pam_tacplus/Makefile b/lib/libpam/modules/pam_tacplus/Makefile
new file mode 100644
index 000000000000..2b558d9f72b3
--- /dev/null
+++ b/lib/libpam/modules/pam_tacplus/Makefile
@@ -0,0 +1,32 @@
+# Copyright 1998 Juniper Networks, Inc.
+# 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, this list of conditions and the following disclaimer.
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+#
+
+LIB= pam_tacplus
+SRCS= pam_tacplus.c
+MAN= pam_tacplus.8
+
+LIBADD+= tacplus
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_tacplus/Makefile.depend b/lib/libpam/modules/pam_tacplus/Makefile.depend
new file mode 100644
index 000000000000..d17468f1a7ac
--- /dev/null
+++ b/lib/libpam/modules/pam_tacplus/Makefile.depend
@@ -0,0 +1,17 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+ lib/libtacplus \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_tacplus/pam_tacplus.8 b/lib/libpam/modules/pam_tacplus/pam_tacplus.8
new file mode 100644
index 000000000000..ad37b3bba95a
--- /dev/null
+++ b/lib/libpam/modules/pam_tacplus/pam_tacplus.8
@@ -0,0 +1,125 @@
+.\" Copyright (c) 1999
+.\" Andrzej Bialecki <abial@FreeBSD.org>. All rights reserved.
+.\"
+.\" Copyright (c) 1992, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software donated to Berkeley by
+.\" Jan-Simon Pendry.
+.\"
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.Dd May 17, 2023
+.Dt PAM_TACPLUS 8
+.Os
+.Sh NAME
+.Nm pam_tacplus
+.Nd TACACS+ authentication PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_tacplus
+.Op Ar options
+.Sh DESCRIPTION
+The
+.Nm
+module provides authentication services based
+upon the TACACS+ protocol
+for the PAM (Pluggable Authentication Module) framework.
+.Pp
+The
+.Nm
+module accepts these optional parameters:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm use_first_pass
+causes
+.Nm
+to use a previously entered password instead of prompting for a new one.
+If no password has been entered then authentication fails.
+.It Cm try_first_pass
+causes
+.Nm
+to use a previously entered password, if one is available.
+If no
+password has been entered,
+.Nm
+prompts for one as usual.
+.It Cm echo_pass
+causes echoing to be left on if
+.Nm
+prompts for a password.
+.It Cm conf Ns = Ns Ar pathname
+specifies a non-standard location for the TACACS+ client configuration file
+(normally located in
+.Pa /etc/tacplus.conf ) .
+.It Cm template_user Ns = Ns Ar username
+specifies a user whose
+.Xr passwd 5
+entry will be used as a template to create the session environment
+if the supplied username does not exist in local password database.
+The user
+will be authenticated with the supplied username and password, but his
+credentials to the system will be presented as the ones for
+.Ar username ,
+i.e., his login class, home directory, resource limits, etc.\& will be set to ones
+defined for
+.Ar username .
+.Pp
+If this option is omitted, and there is no username
+in the system databases equal to the supplied one (as determined by call to
+.Xr getpwnam 3 ) ,
+the authentication will fail.
+.El
+.Sh FILES
+.Bl -tag -width /etc/tacplus.conf -compact
+.It Pa /etc/tacplus.conf
+The standard TACACS+ client configuration file for
+.Nm
+.El
+.Sh SEE ALSO
+.Xr pam 3 ,
+.Xr passwd 5 ,
+.Xr tacplus.conf 5 ,
+.Xr nss_tacplus 8
+.Sh HISTORY
+The
+.Nm
+module first appeared in
+.Fx 3.1 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+manual page was written by
+.An Andrzej Bialecki Aq Mt abial@FreeBSD.org
+and adapted to TACACS+ from RADIUS by
+.An Mark R V Murray Aq Mt markm@FreeBSD.org .
+.Pp
+The
+.Nm
+module was written by
+.An John D. Polstra Aq Mt jdp@FreeBSD.org .
diff --git a/lib/libpam/modules/pam_tacplus/pam_tacplus.c b/lib/libpam/modules/pam_tacplus/pam_tacplus.c
new file mode 100644
index 000000000000..dd19d7da0557
--- /dev/null
+++ b/lib/libpam/modules/pam_tacplus/pam_tacplus.c
@@ -0,0 +1,280 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright 1998 Juniper Networks, Inc.
+ * All rights reserved.
+ * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/param.h>
+
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <taclib.h>
+#include <unistd.h>
+
+#define PAM_SM_AUTH
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#define PAM_OPT_CONF "conf"
+#define PAM_OPT_TEMPLATE_USER "template_user"
+
+typedef int (*set_func)(struct tac_handle *, const char *);
+
+static int do_item(pam_handle_t *, struct tac_handle *, int,
+ set_func, const char *);
+static char *get_msg(struct tac_handle *);
+static int set_msg(struct tac_handle *, const char *);
+
+static int
+do_item(pam_handle_t *pamh, struct tac_handle *tach, int item,
+ set_func func, const char *funcname)
+{
+ int retval;
+ const void *value;
+
+ retval = pam_get_item(pamh, item, &value);
+ if (retval != PAM_SUCCESS)
+ return retval;
+ if (value != NULL && (*func)(tach, (const char *)value) == -1) {
+ syslog(LOG_CRIT, "%s: %s", funcname, tac_strerror(tach));
+ tac_close(tach);
+ return PAM_SERVICE_ERR;
+ }
+ return PAM_SUCCESS;
+}
+
+static char *
+get_msg(struct tac_handle *tach)
+{
+ char *msg;
+
+ msg = tac_get_msg(tach);
+ if (msg == NULL) {
+ syslog(LOG_CRIT, "tac_get_msg: %s", tac_strerror(tach));
+ tac_close(tach);
+ return NULL;
+ }
+ return msg;
+}
+
+static int
+set_msg(struct tac_handle *tach, const char *msg)
+{
+ if (tac_set_msg(tach, msg) == -1) {
+ syslog(LOG_CRIT, "tac_set_msg: %s", tac_strerror(tach));
+ tac_close(tach);
+ return -1;
+ }
+ return 0;
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ int retval;
+ struct tac_handle *tach;
+ const char *conf_file, *template_user;
+
+ conf_file = openpam_get_option(pamh, PAM_OPT_CONF);
+ template_user = openpam_get_option(pamh, PAM_OPT_TEMPLATE_USER);
+
+ tach = tac_open();
+ if (tach == NULL) {
+ syslog(LOG_CRIT, "tac_open failed");
+ return (PAM_SERVICE_ERR);
+ }
+ if (tac_config(tach, conf_file) == -1) {
+ syslog(LOG_ALERT, "tac_config: %s", tac_strerror(tach));
+ tac_close(tach);
+ return (PAM_SERVICE_ERR);
+ }
+ if (tac_create_authen(tach, TAC_AUTHEN_LOGIN, TAC_AUTHEN_TYPE_ASCII,
+ TAC_AUTHEN_SVC_LOGIN) == -1) {
+ syslog(LOG_CRIT, "tac_create_authen: %s", tac_strerror(tach));
+ tac_close(tach);
+ return (PAM_SERVICE_ERR);
+ }
+
+ PAM_LOG("Done tac_open() ... tac_close()");
+
+ retval = do_item(pamh, tach, PAM_USER, tac_set_user, "tac_set_user");
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Done user");
+
+ retval = do_item(pamh, tach, PAM_TTY, tac_set_port, "tac_set_port");
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ PAM_LOG("Done tty");
+
+ retval = do_item(pamh, tach, PAM_RHOST, tac_set_rem_addr,
+ "tac_set_rem_addr");
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ for (;;) {
+ char *srvr_msg;
+ size_t msg_len;
+ const char *user_msg;
+ char *data_msg;
+ int sflags;
+ int status;
+
+ sflags = tac_send_authen(tach);
+ if (sflags == -1) {
+ syslog(LOG_CRIT, "tac_send_authen: %s",
+ tac_strerror(tach));
+ tac_close(tach);
+ return (PAM_AUTHINFO_UNAVAIL);
+ }
+ status = TAC_AUTHEN_STATUS(sflags);
+ openpam_set_option(pamh, PAM_OPT_ECHO_PASS,
+ TAC_AUTHEN_NOECHO(sflags) ? NULL : "");
+ switch (status) {
+
+ case TAC_AUTHEN_STATUS_PASS:
+ tac_close(tach);
+ if (template_user != NULL) {
+ const void *item;
+ const char *user;
+
+ PAM_LOG("Trying template user: %s",
+ template_user);
+
+ /*
+ * If the given user name doesn't exist in
+ * the local password database, change it
+ * to the value given in the "template_user"
+ * option.
+ */
+ retval = pam_get_item(pamh, PAM_USER, &item);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+ user = (const char *)item;
+ if (getpwnam(user) == NULL) {
+ pam_set_item(pamh, PAM_USER,
+ template_user);
+ PAM_LOG("Using template user");
+ }
+ }
+ return (PAM_SUCCESS);
+
+ case TAC_AUTHEN_STATUS_FAIL:
+ tac_close(tach);
+ PAM_VERBOSE_ERROR("TACACS+ authentication failed");
+ return (PAM_AUTH_ERR);
+
+ case TAC_AUTHEN_STATUS_GETUSER:
+ case TAC_AUTHEN_STATUS_GETPASS:
+ if ((srvr_msg = get_msg(tach)) == NULL)
+ return (PAM_SERVICE_ERR);
+ if (status == TAC_AUTHEN_STATUS_GETUSER)
+ retval = pam_get_user(pamh, &user_msg,
+ *srvr_msg ? srvr_msg : NULL);
+ else if (status == TAC_AUTHEN_STATUS_GETPASS)
+ retval = pam_get_authtok(pamh,
+ PAM_AUTHTOK, &user_msg,
+ *srvr_msg ? srvr_msg : "Password:");
+ free(srvr_msg);
+ if (retval != PAM_SUCCESS) {
+ /* XXX - send a TACACS+ abort packet */
+ tac_close(tach);
+ return (retval);
+ }
+ if (set_msg(tach, user_msg) == -1)
+ return (PAM_SERVICE_ERR);
+ break;
+
+ case TAC_AUTHEN_STATUS_GETDATA:
+ if ((srvr_msg = get_msg(tach)) == NULL)
+ return (PAM_SERVICE_ERR);
+ retval = pam_prompt(pamh,
+ openpam_get_option(pamh, PAM_OPT_ECHO_PASS) ?
+ PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF,
+ &data_msg, "%s", *srvr_msg ? srvr_msg : "Data:");
+ free(srvr_msg);
+ if (retval != PAM_SUCCESS) {
+ /* XXX - send a TACACS+ abort packet */
+ tac_close(tach);
+ return (retval);
+ }
+ retval = set_msg(tach, data_msg);
+ memset(data_msg, 0, strlen(data_msg));
+ free(data_msg);
+ if (retval == -1)
+ return (PAM_SERVICE_ERR);
+ break;
+
+ case TAC_AUTHEN_STATUS_ERROR:
+ srvr_msg = (char *)tac_get_data(tach, &msg_len);
+ if (srvr_msg != NULL && msg_len != 0) {
+ syslog(LOG_CRIT, "tac_send_authen:"
+ " server detected error: %s", srvr_msg);
+ free(srvr_msg);
+ }
+ else
+ syslog(LOG_CRIT,
+ "tac_send_authen: server detected error");
+ tac_close(tach);
+ return (PAM_AUTHINFO_UNAVAIL);
+ break;
+
+ case TAC_AUTHEN_STATUS_RESTART:
+ case TAC_AUTHEN_STATUS_FOLLOW:
+ default:
+ syslog(LOG_CRIT,
+ "tac_send_authen: unexpected status %#x", status);
+ tac_close(tach);
+ return (PAM_AUTHINFO_UNAVAIL);
+ }
+ }
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_IGNORE);
+}
+
+PAM_MODULE_ENTRY("pam_tacplus");
diff --git a/lib/libpam/modules/pam_unix/Makefile b/lib/libpam/modules/pam_unix/Makefile
new file mode 100644
index 000000000000..2e76f054c502
--- /dev/null
+++ b/lib/libpam/modules/pam_unix/Makefile
@@ -0,0 +1,52 @@
+# Copyright 1998 Juniper Networks, Inc.
+# All rights reserved.
+# Copyright (c) 2002 Networks Associates Technology, Inc.
+# All rights reserved.
+#
+# Portions of this software was developed for the FreeBSD Project by
+# ThinkSec AS and NAI Labs, the Security Research Division of Network
+# Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+# ("CBOSS"), as part of the DARPA CHATS research program.
+#
+# 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, this list of conditions and the following disclaimer.
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <src.opts.mk>
+.include <bsd.init.mk>
+
+PACKAGE= runtime
+
+LIB= pam_unix
+SRCS= pam_unix.c
+MAN= pam_unix.8
+
+LIBADD+= util crypt
+
+.if ${MK_NIS} != "no"
+CFLAGS+= -DYP
+LIBADD+= ypclnt
+.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_unix/Makefile.depend b/lib/libpam/modules/pam_unix/Makefile.depend
new file mode 100644
index 000000000000..e852c4988ea6
--- /dev/null
+++ b/lib/libpam/modules/pam_unix/Makefile.depend
@@ -0,0 +1,19 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/arpa \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libcrypt \
+ lib/libpam/libpam \
+ lib/libutil \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libpam/modules/pam_unix/Makefile.depend.options b/lib/libpam/modules/pam_unix/Makefile.depend.options
new file mode 100644
index 000000000000..a43cdcfaffb4
--- /dev/null
+++ b/lib/libpam/modules/pam_unix/Makefile.depend.options
@@ -0,0 +1,7 @@
+# This file is not autogenerated - take care!
+
+DIRDEPS_OPTIONS= NIS
+
+DIRDEPS.NIS.yes= lib/libypclnt
+
+.include <dirdeps-options.mk>
diff --git a/lib/libpam/modules/pam_unix/pam_unix.8 b/lib/libpam/modules/pam_unix/pam_unix.8
new file mode 100644
index 000000000000..5c2ae5cf52e2
--- /dev/null
+++ b/lib/libpam/modules/pam_unix/pam_unix.8
@@ -0,0 +1,215 @@
+.\" Copyright (c) 2001 Mark R V Murray
+.\" All rights reserved.
+.\" Copyright (c) 2001 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" This software was developed for the FreeBSD Project by ThinkSec AS and
+.\" NAI Labs, the Security Research Division of Network Associates, Inc.
+.\" under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
+.\" DARPA CHATS research program.
+.\"
+.\" 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, this list of conditions and the following disclaimer.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.Dd April 3, 2020
+.Dt PAM_UNIX 8
+.Os
+.Sh NAME
+.Nm pam_unix
+.Nd UNIX PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_unix
+.Op Ar options
+.Sh DESCRIPTION
+The
+.Ux
+authentication service module for PAM,
+.Nm
+provides functionality for three PAM categories:
+authentication, account management, and password management.
+In terms of the
+.Ar module-type
+parameter, they are the
+.Dq Li auth ,
+.Dq Li account ,
+and
+.Dq Li password
+features.
+It also provides a null function for session management.
+.Ss Ux Ss Authentication Module
+The
+.Ux
+authentication component provides functions to verify the identity of
+a user
+.Pq Fn pam_sm_authenticate ,
+which obtains the relevant
+.Xr passwd 5
+entry.
+It prompts the user for a password and verifies that this is correct with
+.Xr crypt 3 .
+.Pp
+The following options may be passed to the authentication module:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm use_first_pass
+If the authentication module is not the first in the stack, and a
+previous module obtained the user's password, that password is used to
+authenticate the user.
+If this fails, the authentication module returns failure without
+prompting the user for a password.
+This option has no effect if the authentication module is the first in
+the stack, or if no previous modules obtained the user's password.
+.It Cm try_first_pass
+This option is similar to the
+.Cm use_first_pass
+option, except that if the previously obtained password fails, the
+user is prompted for another password.
+.It Cm auth_as_self
+This option will require the user to authenticate themselves as
+themselves, not as the account they are attempting to access.
+This is primarily for services like
+.Xr su 1 ,
+where the user's ability to retype their own password might be deemed
+sufficient.
+.It Cm nullok
+If the password database has no password for the entity being
+authenticated, then this option will forgo password prompting, and
+silently allow authentication to succeed.
+.Pp
+.Sy NOTE:
+If
+.Nm
+is invoked by a process that does not have the privileges required to
+access the password database (in most cases, this means root
+privileges), the
+.Cm nullok
+option may cause
+.Nm
+to allow any user to log in with any password.
+.It Cm emptyok
+If the password database contains the password for the entity being
+authenticated, but the password matches an empty string,
+then this option will forgo password prompting, and
+silently allow authentication to succeed.
+.Pp
+The difference between this and
+.Cm nullok
+is that it avoids prompting for password when the password is set
+to an empty string, as opposed to not being set.
+.It Cm local_pass
+Use only the local password database, even if NIS is in use.
+This will cause an authentication failure if the system is configured
+to only use NIS.
+.It Cm nis_pass
+Use only the NIS password database.
+This will cause an authentication failure if the system is not
+configured to use NIS.
+.El
+.Ss Ux Ss Account Management Module
+The
+.Ux
+account management component provides a function to perform account
+management,
+.Fn pam_sm_acct_mgmt .
+The function verifies that the authenticated user is allowed to log
+into the local user account by checking the following criteria:
+.Bl -dash -offset indent
+.It
+locked status of the account compatible with
+.Xr pw 8
+.Cm lock ;
+.It
+the password expiry date from
+.Xr passwd 5 ;
+.It
+.Xr login.conf 5
+restrictions on the remote host, login time, and tty.
+.El
+.Pp
+The following options may be passed to the management module:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.El
+.Ss Ux Ss Password Management Module
+The
+.Ux
+password management component provides a function to perform password
+management,
+.Fn pam_sm_chauthtok .
+The function changes
+the user's password.
+.Pp
+The following options may be passed to the password module:
+.Bl -tag -width ".Cm use_first_pass"
+.It Cm debug
+.Xr syslog 3
+debugging information at
+.Dv LOG_DEBUG
+level.
+.It Cm no_warn
+suppress warning messages to the user.
+These messages include reasons why the user's authentication attempt
+was declined.
+.It Cm local_pass
+forces the password module to change a local password in favour of a
+NIS one.
+.It Cm nis_pass
+forces the password module to change a NIS password in favour of a
+local one.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /etc/master.passwd" -compact
+.It Pa /etc/master.passwd
+default
+.Ux
+password database.
+.El
+.Sh SEE ALSO
+.Xr passwd 1 ,
+.Xr getlogin 2 ,
+.Xr crypt 3 ,
+.Xr getpwent 3 ,
+.Xr pam 3 ,
+.Xr syslog 3 ,
+.Xr nsswitch.conf 5 ,
+.Xr passwd 5 ,
+.Xr pw 8 ,
+.Xr yp 8
+.Sh BUGS
+The
+.Nm
+module ignores the
+.Dv PAM_CHANGE_EXPIRED_AUTHTOK
+flag.
diff --git a/lib/libpam/modules/pam_unix/pam_unix.c b/lib/libpam/modules/pam_unix/pam_unix.c
new file mode 100644
index 000000000000..88313f6ebae8
--- /dev/null
+++ b/lib/libpam/modules/pam_unix/pam_unix.c
@@ -0,0 +1,492 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright 1998 Juniper Networks, Inc.
+ * All rights reserved.
+ * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software was developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <login_cap.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <libutil.h>
+
+#ifdef YP
+#include <ypclnt.h>
+#endif
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+#define PAM_SM_PASSWORD
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#define PASSWORD_HASH "md5"
+#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
+#define SALTSIZE 32
+
+#define LOCKED_PREFIX "*LOCKED*"
+#define LOCKED_PREFIX_LEN (sizeof(LOCKED_PREFIX) - 1)
+
+static void makesalt(char [SALTSIZE + 1]);
+
+static char password_hash[] = PASSWORD_HASH;
+
+#define PAM_OPT_LOCAL_PASS "local_pass"
+#define PAM_OPT_NIS_PASS "nis_pass"
+
+/*
+ * authentication management
+ */
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags,
+ int argc __unused, const char *argv[] __unused)
+{
+ login_cap_t *lc;
+ struct passwd *pwd;
+ int retval;
+ const char *pass, *user, *realpw, *prompt;
+ const char *emptypasswd = "";
+
+ if (openpam_get_option(pamh, PAM_OPT_AUTH_AS_SELF)) {
+ user = getlogin();
+ } else {
+ retval = pam_get_user(pamh, &user, NULL);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+ }
+ pwd = getpwnam(user);
+
+ PAM_LOG("Got user: %s", user);
+
+ if (pwd != NULL) {
+ PAM_LOG("Doing real authentication");
+ realpw = pwd->pw_passwd;
+ if (realpw[0] == '\0') {
+ if (!(flags & PAM_DISALLOW_NULL_AUTHTOK) &&
+ openpam_get_option(pamh, PAM_OPT_NULLOK))
+ return (PAM_SUCCESS);
+ PAM_LOG("Password is empty, using fake password");
+ realpw = "*";
+ }
+ /*
+ * Check whether the saved password hash matches the one
+ * generated from an empty password - as opposed to empty
+ * saved password hash, which is handled above.
+ */
+ if (!(flags & PAM_DISALLOW_NULL_AUTHTOK) &&
+ openpam_get_option(pamh, PAM_OPT_EMPTYOK) &&
+ strcmp(crypt(emptypasswd, realpw), realpw) == 0)
+ return (PAM_SUCCESS);
+ lc = login_getpwclass(pwd);
+ } else {
+ PAM_LOG("Doing dummy authentication");
+ realpw = "*";
+ lc = login_getclass(NULL);
+ }
+ prompt = login_getcapstr(lc, "passwd_prompt", NULL, NULL);
+ retval = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, prompt);
+ login_close(lc);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+ PAM_LOG("Got password");
+ if (strnlen(pass, _PASSWORD_LEN + 1) > _PASSWORD_LEN) {
+ PAM_LOG("Password is too long, using fake password");
+ realpw = "*";
+ }
+ if (strcmp(crypt(pass, realpw), realpw) == 0)
+ return (PAM_SUCCESS);
+
+ PAM_VERBOSE_ERROR("UNIX authentication refused");
+ return (PAM_AUTH_ERR);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+
+ return (PAM_SUCCESS);
+}
+
+/*
+ * account management
+ */
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct addrinfo hints, *res;
+ struct passwd *pwd;
+ struct timeval tp;
+ login_cap_t *lc;
+ time_t warntime;
+ int retval;
+ const char *user;
+ const void *rhost, *tty;
+ char rhostip[MAXHOSTNAMELEN] = "";
+
+ retval = pam_get_user(pamh, &user, NULL);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ if (user == NULL || (pwd = getpwnam(user)) == NULL)
+ return (PAM_SERVICE_ERR);
+
+ PAM_LOG("Got user: %s", user);
+
+ retval = pam_get_item(pamh, PAM_RHOST, &rhost);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ retval = pam_get_item(pamh, PAM_TTY, &tty);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+
+ if (*pwd->pw_passwd == '\0' &&
+ (flags & PAM_DISALLOW_NULL_AUTHTOK) != 0)
+ return (PAM_NEW_AUTHTOK_REQD);
+
+ if (strncmp(pwd->pw_passwd, LOCKED_PREFIX, LOCKED_PREFIX_LEN) == 0)
+ return (PAM_AUTH_ERR);
+
+ lc = login_getpwclass(pwd);
+ if (lc == NULL) {
+ PAM_LOG("Unable to get login class for user %s", user);
+ return (PAM_SERVICE_ERR);
+ }
+
+ PAM_LOG("Got login_cap");
+
+ if (pwd->pw_change || pwd->pw_expire)
+ gettimeofday(&tp, NULL);
+
+ /*
+ * Check pw_expire before pw_change - no point in letting the
+ * user change the password on an expired account.
+ */
+
+ if (pwd->pw_expire) {
+ warntime = login_getcaptime(lc, "warnexpire",
+ DEFAULT_WARN, DEFAULT_WARN);
+ if (tp.tv_sec >= pwd->pw_expire) {
+ login_close(lc);
+ return (PAM_ACCT_EXPIRED);
+ } else if (pwd->pw_expire - tp.tv_sec < warntime &&
+ (flags & PAM_SILENT) == 0) {
+ pam_error(pamh, "Warning: your account expires on %s",
+ ctime(&pwd->pw_expire));
+ }
+ }
+
+ retval = PAM_SUCCESS;
+ if (pwd->pw_change) {
+ warntime = login_getcaptime(lc, "warnpassword",
+ DEFAULT_WARN, DEFAULT_WARN);
+ if (tp.tv_sec >= pwd->pw_change) {
+ retval = PAM_NEW_AUTHTOK_REQD;
+ } else if (pwd->pw_change - tp.tv_sec < warntime &&
+ (flags & PAM_SILENT) == 0) {
+ pam_error(pamh, "Warning: your password expires on %s",
+ ctime(&pwd->pw_change));
+ }
+ }
+
+ /*
+ * From here on, we must leave retval untouched (unless we
+ * know we're going to fail), because we need to remember
+ * whether we're supposed to return PAM_SUCCESS or
+ * PAM_NEW_AUTHTOK_REQD.
+ */
+
+ if (rhost && *(const char *)rhost != '\0') {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ if (getaddrinfo(rhost, NULL, &hints, &res) == 0) {
+ getnameinfo(res->ai_addr, res->ai_addrlen,
+ rhostip, sizeof(rhostip), NULL, 0,
+ NI_NUMERICHOST);
+ }
+ if (res != NULL)
+ freeaddrinfo(res);
+ }
+
+ /*
+ * Check host / tty / time-of-day restrictions
+ */
+
+ if (!auth_hostok(lc, rhost, rhostip) ||
+ !auth_ttyok(lc, tty) ||
+ !auth_timeok(lc, time(NULL)))
+ retval = PAM_AUTH_ERR;
+
+ login_close(lc);
+
+ return (retval);
+}
+
+/*
+ * password management
+ *
+ * standard Unix and NIS password changing
+ */
+PAM_EXTERN int
+pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc __unused, const char *argv[] __unused)
+{
+#ifdef YP
+ struct ypclnt *ypclnt;
+ const void *yp_domain, *yp_server;
+#endif
+ char salt[SALTSIZE + 1];
+ login_cap_t *lc;
+ struct passwd *pwd, *old_pwd;
+ const char *user, *old_pass, *new_pass;
+ char *encrypted;
+ time_t passwordtime;
+ int pfd, tfd, retval;
+
+ if (openpam_get_option(pamh, PAM_OPT_AUTH_AS_SELF))
+ user = getlogin();
+ else {
+ retval = pam_get_user(pamh, &user, NULL);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+ }
+ pwd = getpwnam(user);
+
+ if (pwd == NULL)
+ return (PAM_AUTHTOK_RECOVERY_ERR);
+
+ PAM_LOG("Got user: %s", user);
+
+ if (flags & PAM_PRELIM_CHECK) {
+
+ PAM_LOG("PRELIM round");
+
+ if (getuid() == 0 &&
+ (pwd->pw_fields & _PWF_SOURCE) == _PWF_FILES)
+ /* root doesn't need the old password */
+ return (pam_set_item(pamh, PAM_OLDAUTHTOK, ""));
+#ifdef YP
+ if (getuid() == 0 &&
+ (pwd->pw_fields & _PWF_SOURCE) == _PWF_NIS) {
+
+ yp_domain = yp_server = NULL;
+ (void)pam_get_data(pamh, "yp_domain", &yp_domain);
+ (void)pam_get_data(pamh, "yp_server", &yp_server);
+
+ ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_server);
+ if (ypclnt == NULL)
+ return (PAM_BUF_ERR);
+
+ if (ypclnt_connect(ypclnt) == -1) {
+ ypclnt_free(ypclnt);
+ return (PAM_SERVICE_ERR);
+ }
+
+ retval = ypclnt_havepasswdd(ypclnt);
+ ypclnt_free(ypclnt);
+ if (retval == 1)
+ return (pam_set_item(pamh, PAM_OLDAUTHTOK, ""));
+ else if (retval == -1)
+ return (PAM_SERVICE_ERR);
+ }
+#endif
+ if (pwd->pw_passwd[0] == '\0'
+ && openpam_get_option(pamh, PAM_OPT_NULLOK)) {
+ /*
+ * No password case. XXX Are we giving too much away
+ * by not prompting for a password?
+ * XXX check PAM_DISALLOW_NULL_AUTHTOK
+ */
+ old_pass = "";
+ retval = PAM_SUCCESS;
+ } else {
+ retval = pam_get_authtok(pamh,
+ PAM_OLDAUTHTOK, &old_pass, NULL);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+ }
+ PAM_LOG("Got old password");
+ /* always encrypt first */
+ encrypted = crypt(old_pass, pwd->pw_passwd);
+ if (old_pass[0] == '\0' &&
+ !openpam_get_option(pamh, PAM_OPT_NULLOK))
+ return (PAM_PERM_DENIED);
+ if (strcmp(encrypted, pwd->pw_passwd) != 0)
+ return (PAM_PERM_DENIED);
+ }
+ else if (flags & PAM_UPDATE_AUTHTOK) {
+ PAM_LOG("UPDATE round");
+
+ retval = pam_get_authtok(pamh,
+ PAM_OLDAUTHTOK, &old_pass, NULL);
+ if (retval != PAM_SUCCESS)
+ return (retval);
+ PAM_LOG("Got old password");
+
+ /* get new password */
+ for (;;) {
+ retval = pam_get_authtok(pamh,
+ PAM_AUTHTOK, &new_pass, NULL);
+ if (retval != PAM_TRY_AGAIN)
+ break;
+ pam_error(pamh, "Mismatch; try again, EOF to quit.");
+ }
+ PAM_LOG("Got new password");
+ if (retval != PAM_SUCCESS) {
+ PAM_VERBOSE_ERROR("Unable to get new password");
+ return (retval);
+ }
+
+ if (getuid() != 0 && new_pass[0] == '\0' &&
+ !openpam_get_option(pamh, PAM_OPT_NULLOK))
+ return (PAM_PERM_DENIED);
+
+ if ((old_pwd = pw_dup(pwd)) == NULL)
+ return (PAM_BUF_ERR);
+
+ lc = login_getclass(pwd->pw_class);
+ if (login_setcryptfmt(lc, password_hash, NULL) == NULL)
+ openpam_log(PAM_LOG_ERROR,
+ "can't set password cipher, relying on default");
+
+ /* set password expiry date */
+ pwd->pw_change = 0;
+ passwordtime = login_getcaptime(lc, "passwordtime", 0, 0);
+ if (passwordtime > 0)
+ pwd->pw_change = time(NULL) + passwordtime;
+
+ login_close(lc);
+ makesalt(salt);
+ pwd->pw_passwd = crypt(new_pass, salt);
+#ifdef YP
+ switch (old_pwd->pw_fields & _PWF_SOURCE) {
+ case _PWF_FILES:
+#endif
+ retval = PAM_SERVICE_ERR;
+ if (pw_init(NULL, NULL))
+ openpam_log(PAM_LOG_ERROR, "pw_init() failed");
+ else if ((pfd = pw_lock()) == -1)
+ openpam_log(PAM_LOG_ERROR, "pw_lock() failed");
+ else if ((tfd = pw_tmp(-1)) == -1)
+ openpam_log(PAM_LOG_ERROR, "pw_tmp() failed");
+ else if (pw_copy(pfd, tfd, pwd, old_pwd) == -1)
+ openpam_log(PAM_LOG_ERROR, "pw_copy() failed");
+ else if (pw_mkdb(pwd->pw_name) == -1)
+ openpam_log(PAM_LOG_ERROR, "pw_mkdb() failed");
+ else
+ retval = PAM_SUCCESS;
+ pw_fini();
+#ifdef YP
+ break;
+ case _PWF_NIS:
+ yp_domain = yp_server = NULL;
+ (void)pam_get_data(pamh, "yp_domain", &yp_domain);
+ (void)pam_get_data(pamh, "yp_server", &yp_server);
+ ypclnt = ypclnt_new(yp_domain,
+ "passwd.byname", yp_server);
+ if (ypclnt == NULL) {
+ retval = PAM_BUF_ERR;
+ } else if (ypclnt_connect(ypclnt) == -1 ||
+ ypclnt_passwd(ypclnt, pwd, old_pass) == -1) {
+ openpam_log(PAM_LOG_ERROR, "%s", ypclnt->error);
+ retval = PAM_SERVICE_ERR;
+ } else {
+ retval = PAM_SUCCESS;
+ }
+ ypclnt_free(ypclnt);
+ break;
+ default:
+ openpam_log(PAM_LOG_ERROR, "unsupported source 0x%x",
+ pwd->pw_fields & _PWF_SOURCE);
+ retval = PAM_SERVICE_ERR;
+ }
+#endif
+ free(old_pwd);
+ }
+ else {
+ /* Very bad juju */
+ retval = PAM_ABORT;
+ PAM_LOG("Illegal 'flags'");
+ }
+
+ return (retval);
+}
+
+/* Mostly stolen from passwd(1)'s local_passwd.c - markm */
+
+static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static void
+to64(char *s, long v, int n)
+{
+ while (--n >= 0) {
+ *s++ = itoa64[v&0x3f];
+ v >>= 6;
+ }
+}
+
+/* Salt suitable for traditional DES and MD5 */
+static void
+makesalt(char salt[SALTSIZE + 1])
+{
+ int i;
+
+ /* These are not really random numbers, they are just
+ * numbers that change to thwart construction of a
+ * dictionary.
+ */
+ for (i = 0; i < SALTSIZE; i += 4)
+ to64(&salt[i], arc4random(), 4);
+ salt[SALTSIZE] = '\0';
+}
+
+PAM_MODULE_ENTRY("pam_unix");
diff --git a/lib/libpam/modules/pam_xdg/Makefile b/lib/libpam/modules/pam_xdg/Makefile
new file mode 100644
index 000000000000..df3948987da6
--- /dev/null
+++ b/lib/libpam/modules/pam_xdg/Makefile
@@ -0,0 +1,5 @@
+LIB= pam_xdg
+SRCS= pam_xdg.c
+MAN= pam_xdg.8
+
+.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_xdg/pam_xdg.8 b/lib/libpam/modules/pam_xdg/pam_xdg.8
new file mode 100644
index 000000000000..031010953e98
--- /dev/null
+++ b/lib/libpam/modules/pam_xdg/pam_xdg.8
@@ -0,0 +1,64 @@
+.\" * SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2024 Beckhoff Automation GmbH & Co. KG
+.\"
+.\" * 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, this list of conditions and the following disclaimer.
+.\" * 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.
+.\" *
+.\" * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.Dd May 20, 2025
+.Dt PAM_XDG 8
+.Os
+.Sh NAME
+.Nm pam_xdg
+.Nd XDG PAM module
+.Sh SYNOPSIS
+.Op Ar service-name
+.Ar module-type
+.Ar control-flag
+.Pa pam_xdg
+.Op Ar arguments
+.Sh DESCRIPTION
+The xdg service module for PAM creates the runtime files base directory
+according to the Cross Desktop Group Base Directory Specification.
+.Pp
+By default the directory is created under
+.Pa /var/run/xdg/ Ns $ Ns Ev USER .
+.Pp
+The following option may be passed to the authentication module:
+.Bl -tag -width "runtime_dir_prefix=directory"
+.It Cm runtime_dir_prefix Ns = Ns Ar directory
+Use an alternate base directory
+.El
+.Sh ENVIRONMENT
+.Bl -tag -width indent
+.It Ev XDG_RUNTIME_DIR
+The location of the runtime files base directory created by this module.
+.El
+.Sh STANDARDS
+The directory created by this module conforms to the
+.Lk https://specifications.freedesktop.org/basedir-spec XDG Base Directory Specification .
+.Sh SEE ALSO
+.Xr pam 3 ,
+.Xr pam.conf 5
+.Sh AUTHORS
+The
+.Nm
+module and this manual page were written by
+.An Emmanuel Vadot Aq Mt manu@FreeBSD.org .
diff --git a/lib/libpam/modules/pam_xdg/pam_xdg.c b/lib/libpam/modules/pam_xdg/pam_xdg.c
new file mode 100644
index 000000000000..10c6467776a3
--- /dev/null
+++ b/lib/libpam/modules/pam_xdg/pam_xdg.c
@@ -0,0 +1,329 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+
+#define PAM_SM_SESSION
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_mod_misc.h>
+
+#define BASE_RUNTIME_DIR_PREFIX "/var/run/xdg"
+#define RUNTIME_DIR_PREFIX runtime_dir_prefix != NULL ? runtime_dir_prefix : BASE_RUNTIME_DIR_PREFIX
+
+#define RUNTIME_DIR_PREFIX_MODE 0711
+#define RUNTIME_DIR_MODE 0700 /* XDG spec */
+
+#define XDG_MAX_SESSION 100 /* Arbitrary limit because we need one */
+
+static int
+_pam_xdg_open(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct passwd *passwd;
+ const char *user;
+ const char *runtime_dir_prefix;
+ struct stat sb;
+ char *runtime_dir = NULL;
+ char *xdg_session_file;
+ int rv, rt_dir_prefix, rt_dir, session_file, i;
+
+ session_file = -1;
+ rt_dir_prefix = -1;
+ runtime_dir_prefix = openpam_get_option(pamh, "runtime_dir_prefix");
+
+ /* Get user info */
+ rv = pam_get_item(pamh, PAM_USER, (const void **)&user);
+ if (rv != PAM_SUCCESS || user == NULL) {
+ PAM_VERBOSE_ERROR("Can't get user information");
+ goto out;
+ }
+ if ((passwd = getpwnam(user)) == NULL) {
+ PAM_VERBOSE_ERROR("Can't get user information");
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+
+ /* Open or create the base xdg directory */
+ rt_dir_prefix = open(RUNTIME_DIR_PREFIX, O_DIRECTORY | O_NOFOLLOW);
+ if (rt_dir_prefix < 0) {
+ rt_dir_prefix = mkdir(RUNTIME_DIR_PREFIX, RUNTIME_DIR_PREFIX_MODE);
+ if (rt_dir_prefix != 0) {
+ PAM_VERBOSE_ERROR("Can't mkdir %s", RUNTIME_DIR_PREFIX);
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+ rt_dir_prefix = open(RUNTIME_DIR_PREFIX, O_DIRECTORY | O_NOFOLLOW);
+ }
+
+ /* Open or create the user xdg directory */
+ rt_dir = openat(rt_dir_prefix, user, O_DIRECTORY | O_NOFOLLOW);
+ if (rt_dir < 0) {
+ rt_dir = mkdirat(rt_dir_prefix, user, RUNTIME_DIR_MODE);
+ if (rt_dir != 0) {
+ PAM_VERBOSE_ERROR("mkdir: %s/%s (%d)", RUNTIME_DIR_PREFIX, user, rt_dir);
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+ rv = fchownat(rt_dir_prefix, user, passwd->pw_uid, passwd->pw_gid, 0);
+ if (rv != 0) {
+ PAM_VERBOSE_ERROR("fchownat: %s/%s (%d)", RUNTIME_DIR_PREFIX, user, rv);
+ rv = unlinkat(rt_dir_prefix, user, AT_REMOVEDIR);
+ if (rv == -1)
+ PAM_VERBOSE_ERROR("unlinkat: %s/%s (%d)", RUNTIME_DIR_PREFIX, user, errno);
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+ } else {
+ close(rt_dir);
+ /* Check that the already create dir is correctly owned */
+ rv = fstatat(rt_dir_prefix, user, &sb, 0);
+ if (rv == -1) {
+ PAM_VERBOSE_ERROR("fstatat %s/%s failed (%d)", RUNTIME_DIR_PREFIX, user, errno);
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+ if (sb.st_uid != passwd->pw_uid ||
+ sb.st_gid != passwd->pw_gid) {
+ PAM_VERBOSE_ERROR("%s/%s isn't owned by %d:%d\n", RUNTIME_DIR_PREFIX, user, passwd->pw_uid, passwd->pw_gid);
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+ /* Test directory mode */
+ if ((sb.st_mode & 0x1FF) != RUNTIME_DIR_MODE) {
+ PAM_VERBOSE_ERROR("%s/%s have wrong mode\n", RUNTIME_DIR_PREFIX, user);
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+ }
+
+ /* Setup the environment variable */
+ rv = asprintf(&runtime_dir, "XDG_RUNTIME_DIR=%s/%s", RUNTIME_DIR_PREFIX, user);
+ if (rv < 0) {
+ PAM_VERBOSE_ERROR("asprintf failed %d\n", rv);
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+ rv = pam_putenv(pamh, runtime_dir);
+ if (rv != PAM_SUCCESS) {
+ PAM_VERBOSE_ERROR("pam_putenv: failed (%d)", rv);
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+
+ /* Setup the session count file */
+ for (i = 0; i < XDG_MAX_SESSION; i++) {
+ rv = asprintf(&xdg_session_file, "%s/xdg_session.%d", user, i);
+ if (rv < 0) {
+ PAM_VERBOSE_ERROR("asprintf failed %d\n", rv);
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+ rv = 0;
+ session_file = openat(rt_dir_prefix, xdg_session_file, O_CREAT | O_EXCL, RUNTIME_DIR_MODE);
+ free(xdg_session_file);
+ if (session_file >= 0)
+ break;
+ }
+ if (session_file < 0) {
+ PAM_VERBOSE_ERROR("Too many sessions");
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+
+out:
+ if (session_file >= 0)
+ close(session_file);
+ if (rt_dir_prefix >= 0)
+ close(rt_dir_prefix);
+
+ if (runtime_dir)
+ free(runtime_dir);
+ return (rv);
+}
+
+static int
+remove_dir(int fd)
+{
+ DIR *dirp;
+ struct dirent *dp;
+
+ dirp = fdopendir(fd);
+ if (dirp == NULL)
+ return (-1);
+
+ while ((dp = readdir(dirp)) != NULL) {
+ if (dp->d_type == DT_DIR) {
+ int dirfd;
+
+ if (strcmp(dp->d_name, ".") == 0 ||
+ strcmp(dp->d_name, "..") == 0)
+ continue;
+ dirfd = openat(fd, dp->d_name, 0);
+ remove_dir(dirfd);
+ close(dirfd);
+ unlinkat(fd, dp->d_name, AT_REMOVEDIR);
+ continue;
+ }
+ unlinkat(fd, dp->d_name, 0);
+ }
+ closedir(dirp);
+
+ return (0);
+}
+
+static int
+_pam_xdg_close(pam_handle_t *pamh __unused, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ struct passwd *passwd;
+ const char *user;
+ const char *runtime_dir_prefix;
+ struct stat sb;
+ char *xdg_session_file;
+ int rv, rt_dir_prefix, rt_dir, session_file, i;
+
+ rt_dir = -1;
+ rt_dir_prefix = -1;
+ runtime_dir_prefix = openpam_get_option(pamh, "runtime_dir_prefix");
+
+ /* Get user info */
+ rv = pam_get_item(pamh, PAM_USER, (const void **)&user);
+ if (rv != PAM_SUCCESS || user == NULL) {
+ PAM_VERBOSE_ERROR("Can't get user information");
+ goto out;
+ }
+ if ((passwd = getpwnam(user)) == NULL) {
+ PAM_VERBOSE_ERROR("Can't get user information");
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+
+ /* Open the xdg base directory */
+ rt_dir_prefix = open(RUNTIME_DIR_PREFIX, O_DIRECTORY | O_NOFOLLOW);
+ if (rt_dir_prefix < 0) {
+ PAM_VERBOSE_ERROR("open: %s failed (%d)\n", runtime_dir_prefix, rt_dir_prefix);
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+ /* Check that the already created dir is correctly owned */
+ rv = fstatat(rt_dir_prefix, user, &sb, 0);
+ if (rv == -1) {
+ PAM_VERBOSE_ERROR("fstatat %s/%s failed (%d)", RUNTIME_DIR_PREFIX, user, errno);
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+ if (sb.st_uid != passwd->pw_uid ||
+ sb.st_gid != passwd->pw_gid) {
+ PAM_VERBOSE_ERROR("%s/%s isn't owned by %d:%d\n", RUNTIME_DIR_PREFIX, user, passwd->pw_uid, passwd->pw_gid);
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+ /* Test directory mode */
+ if ((sb.st_mode & 0x1FF) != RUNTIME_DIR_MODE) {
+ PAM_VERBOSE_ERROR("%s/%s have wrong mode\n", RUNTIME_DIR_PREFIX, user);
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+
+ /* Open the user xdg directory */
+ rt_dir = openat(rt_dir_prefix, user, O_DIRECTORY | O_NOFOLLOW);
+ if (rt_dir < 0) {
+ PAM_VERBOSE_ERROR("openat: %s/%s failed (%d)\n", RUNTIME_DIR_PREFIX, user, rt_dir_prefix);
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+
+ /* Get the last session file created */
+ for (i = XDG_MAX_SESSION; i >= 0; i--) {
+ rv = asprintf(&xdg_session_file, "%s/xdg_session.%d", user, i);
+ if (rv < 0) {
+ PAM_VERBOSE_ERROR("asprintf failed %d\n", rv);
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+ rv = 0;
+ session_file = openat(rt_dir_prefix, xdg_session_file, 0);
+ if (session_file >= 0) {
+ unlinkat(rt_dir_prefix, xdg_session_file, 0);
+ free(xdg_session_file);
+ break;
+ }
+ free(xdg_session_file);
+ }
+ if (session_file < 0) {
+ PAM_VERBOSE_ERROR("Can't find session number\n");
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+ close(session_file);
+
+ /* Final cleanup if last user session */
+ if (i == 0) {
+ remove_dir(rt_dir);
+ if (unlinkat(rt_dir_prefix, user, AT_REMOVEDIR) != 0) {
+ PAM_VERBOSE_ERROR("Can't cleanup %s/%s\n", runtime_dir_prefix, user);
+ rv = PAM_SESSION_ERR;
+ goto out;
+ }
+ }
+
+ rv = PAM_SUCCESS;
+out:
+ if (rt_dir >= 0)
+ close(rt_dir);
+ if (rt_dir_prefix >= 0)
+ close(rt_dir_prefix);
+ return (rv);
+}
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ return (_pam_xdg_open(pamh, flags, argc, argv));
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ return (_pam_xdg_close(pamh, flags, argc, argv));
+}
+
+PAM_MODULE_ENTRY("pam_xdg");