diff options
Diffstat (limited to 'lib/libpam/modules')
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"); |