summaryrefslogtreecommitdiffstats
path: root/lib/libpam/modules/pam_unix
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpam/modules/pam_unix')
-rw-r--r--lib/libpam/modules/pam_unix/Makefile79
-rw-r--r--lib/libpam/modules/pam_unix/pam_unix.8202
-rw-r--r--lib/libpam/modules/pam_unix/pam_unix.c731
3 files changed, 1012 insertions, 0 deletions
diff --git a/lib/libpam/modules/pam_unix/Makefile b/lib/libpam/modules/pam_unix/Makefile
new file mode 100644
index 0000000..d4a14c9
--- /dev/null
+++ b/lib/libpam/modules/pam_unix/Makefile
@@ -0,0 +1,79 @@
+# 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.
+#
+# $FreeBSD$
+
+LIB= pam_unix
+SHLIB_NAME= ${LIB}.so.${SHLIB_MAJOR}
+SRCS= pam_unix.c pw_copy.c pw_yp.c pw_util.c ypxfr_misc.c ${GENSRCS}
+CFLAGS+= -DYP -Dyp_error=warnx \
+ -I${.OBJDIR} \
+ -I${.CURDIR}/../../../../libexec/ypxfr \
+ -I${.CURDIR}/../../../../usr.sbin/vipw \
+ -I${.CURDIR}/../../../../usr.bin/chpass \
+ -I${.CURDIR}/../../../../lib/libc/gen
+DPADD= ${LIBUTIL} ${LIBCRYPT} ${LIBRPCSVC}
+LDADD= -lutil -lcrypt -lrpcsvc
+MAN= pam_unix.8
+
+GENSRCS=yp.h yp_clnt.c yppasswd.h yppasswd_clnt.c \
+ yppasswd_private.h yppasswd_private_clnt.c yppasswd_private_xdr.c
+
+RPCGEN= rpcgen -C
+RPCSRC= ${DESTDIR}/usr/include/rpcsvc/yp.x
+RPCSRC_PW= ${DESTDIR}/usr/include/rpcsvc/yppasswd.x
+RPCSRC_PRIV= ${.CURDIR}/../../../../usr.sbin/rpc.yppasswdd/yppasswd_private.x
+
+yp.h: ${RPCSRC}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC}
+
+yp_clnt.c: ${RPCSRC} yp.h
+ ${RPCGEN} -l -o ${.TARGET} ${RPCSRC}
+
+yppasswd.h: ${RPCSRC_PW}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC_PW}
+
+yppasswd_clnt.c: ${RPCSRC_PW}
+ ${RPCGEN} -l -o ${.TARGET} ${RPCSRC_PW}
+
+yppasswd_private.h: ${RPCSRC_PRIV}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC_PRIV}
+
+yppasswd_private_xdr.c: ${RPCSRC_PRIV}
+ ${RPCGEN} -c -o ${.TARGET} ${RPCSRC_PRIV}
+
+yppasswd_private_clnt.c: ${RPCSRC_PRIV}
+ ${RPCGEN} -l -o ${.TARGET} ${RPCSRC_PRIV}
+
+
+yppasswd_private.h: ${RPCSRC_PRIV}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC_PRIV}
+
+CLEANFILES= ${GENSRCS}
+
+.include <bsd.lib.mk>
+
+.PATH: ${.CURDIR}/../../../../usr.bin/chpass
+.PATH: ${.CURDIR}/../../../../usr.sbin/vipw
+.PATH: ${.CURDIR}/../../../../libexec/ypxfr
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 0000000..f8e5e0e
--- /dev/null
+++ b/lib/libpam/modules/pam_unix/pam_unix.8
@@ -0,0 +1,202 @@
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 26, 2001
+.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 two PAM categories:
+authentication
+and account management.
+In terms of the
+.Ar module-type
+parameter, they are the
+.Dq Li auth
+and
+.Dq Li account
+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 themself as the user
+given by
+.Xr getlogin 2 ,
+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.
+.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 login to the local user account
+by checking the password expiry date.
+.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 account 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 syslog 3 ,
+.Xr nis 4 ,
+.Xr nsswitch.conf 5 ,
+.Xr pam.conf 5 ,
+.Xr passwd 5 ,
+.Xr pam 8
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 0000000..09910a6
--- /dev/null
+++ b/lib/libpam/modules/pam_unix/pam_unix.c
@@ -0,0 +1,731 @@
+/*-
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yppasswd.h>
+#endif
+
+#include <login_cap.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <pw_copy.h>
+#include <pw_util.h>
+
+#ifdef YP
+#include <pw_yp.h>
+#include "yppasswd_private.h"
+#endif
+
+#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>
+#include <security/pam_mod_misc.h>
+
+#define USER_PROMPT "Username: "
+#define PASSWORD_PROMPT "Password:"
+#define PASSWORD_PROMPT_EXPIRED "\nPassword expired\nOld Password:"
+#define NEW_PASSWORD_PROMPT_1 "New Password:"
+#define NEW_PASSWORD_PROMPT_2 "New Password (again):"
+#define PASSWORD_HASH "md5"
+#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
+#define MAX_TRIES 3
+#define SALTSIZE 32
+
+static void makesalt(char []);
+
+static char password_prompt_def[] = PASSWORD_PROMPT;
+static char password_hash[] = PASSWORD_HASH;
+static char blank[] = "";
+static char colon[] = ":";
+
+enum {
+ PAM_OPT_AUTH_AS_SELF = PAM_OPT_STD_MAX,
+ PAM_OPT_NULLOK,
+ PAM_OPT_LOCAL_PASS,
+ PAM_OPT_NIS_PASS
+};
+
+static struct opttab other_options[] = {
+ { "auth_as_self", PAM_OPT_AUTH_AS_SELF },
+ { "nullok", PAM_OPT_NULLOK },
+ { "local_pass", PAM_OPT_LOCAL_PASS },
+ { "nis_pass", PAM_OPT_NIS_PASS },
+ { NULL, 0 }
+};
+
+#ifdef YP
+int pam_use_yp = 0;
+int yp_errno = YP_TRUE;
+#endif
+
+char *tempname = NULL;
+static int local_passwd(const char *user, const char *pass);
+#ifdef YP
+static int yp_passwd(const char *user, const char *pass);
+#endif
+
+/*
+ * authentication management
+ */
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, int argc, const char **argv)
+{
+ login_cap_t *lc;
+ struct options options;
+ struct passwd *pwd;
+ int retval;
+ const char *pass, *user;
+ char *encrypted, *password_prompt;
+
+ pam_std_option(&options, other_options, argc, argv);
+
+ PAM_LOG("Options processed");
+
+ if (pam_test_option(&options, PAM_OPT_AUTH_AS_SELF, NULL))
+ pwd = getpwnam(getlogin());
+ else {
+ retval = pam_get_user(pamh, &user, NULL);
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+ pwd = getpwnam(user);
+ }
+
+ PAM_LOG("Got user: %s", user);
+
+ lc = login_getclass(NULL);
+ password_prompt = login_getcapstr(lc, "passwd_prompt",
+ password_prompt_def, password_prompt_def);
+ login_close(lc);
+ lc = NULL;
+
+ if (pwd != NULL) {
+
+ PAM_LOG("Doing real authentication");
+
+ if (pwd->pw_passwd[0] == '\0'
+ && pam_test_option(&options, PAM_OPT_NULLOK, NULL)) {
+ /*
+ * No password case. XXX Are we giving too much away
+ * by not prompting for a password?
+ */
+ PAM_LOG("No password, and null password OK");
+ PAM_RETURN(PAM_SUCCESS);
+ }
+ else {
+ retval = pam_get_authtok(pamh, &pass, password_prompt);
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+ PAM_LOG("Got password");
+ }
+ encrypted = crypt(pass, pwd->pw_passwd);
+ if (pass[0] == '\0' && pwd->pw_passwd[0] != '\0')
+ encrypted = colon;
+
+ PAM_LOG("Encrypted password 1 is: %s", encrypted);
+ PAM_LOG("Encrypted password 2 is: %s", pwd->pw_passwd);
+
+ retval = strcmp(encrypted, pwd->pw_passwd) == 0 ?
+ PAM_SUCCESS : PAM_AUTH_ERR;
+ }
+ else {
+
+ PAM_LOG("Doing dummy authentication");
+
+ /*
+ * User unknown.
+ * Encrypt a dummy password so as to not give away too much.
+ */
+ retval = pam_get_authtok(pamh, &pass, password_prompt);
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+ PAM_LOG("Got password");
+ crypt(pass, "xx");
+ retval = PAM_AUTH_ERR;
+ }
+
+ /*
+ * The PAM infrastructure will obliterate the cleartext
+ * password before returning to the application.
+ */
+ if (retval != PAM_SUCCESS)
+ PAM_VERBOSE_ERROR("UNIX authentication refused");
+
+ PAM_RETURN(retval);
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv)
+{
+ struct options options;
+
+ pam_std_option(&options, other_options, argc, argv);
+
+ PAM_LOG("Options processed");
+
+ PAM_RETURN(PAM_SUCCESS);
+}
+
+/*
+ * account management
+ */
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags __unused, int argc, const char **argv)
+{
+ struct addrinfo hints, *res;
+ struct options options;
+ struct passwd *pwd;
+ struct timeval tp;
+ login_cap_t *lc;
+ time_t warntime;
+ int retval;
+ const char *rhost, *tty, *user;
+ char rhostip[MAXHOSTNAMELEN];
+
+ pam_std_option(&options, other_options, argc, argv);
+
+ PAM_LOG("Options processed");
+
+ retval = pam_get_item(pamh, PAM_USER, (const void **)&user);
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+
+ if (user == NULL || (pwd = getpwnam(user)) == NULL)
+ PAM_RETURN(PAM_SERVICE_ERR);
+
+ PAM_LOG("Got user: %s", user);
+
+ retval = pam_get_item(pamh, PAM_RHOST, (const void **)&rhost);
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+
+ retval = pam_get_item(pamh, PAM_TTY, (const void **)&tty);
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+
+ if (*pwd->pw_passwd == '\0' &&
+ (flags & PAM_DISALLOW_NULL_AUTHTOK) != 0)
+ return (PAM_NEW_AUTHTOK_REQD);
+
+ 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);
+ PAM_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) {
+ 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|NI_WITHSCOPEID);
+ }
+ 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);
+
+ PAM_RETURN(retval);
+}
+
+/*
+ * session management
+ *
+ * logging only
+ */
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv)
+{
+ struct options options;
+
+ pam_std_option(&options, other_options, argc, argv);
+
+ PAM_LOG("Options processed");
+
+ PAM_RETURN(PAM_SUCCESS);
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv)
+{
+ struct options options;
+
+ pam_std_option(&options, other_options, argc, argv);
+
+ PAM_LOG("Options processed");
+
+ PAM_RETURN(PAM_SUCCESS);
+}
+
+/*
+ * password management
+ *
+ * standard Unix and NIS password changing
+ */
+PAM_EXTERN int
+pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+ struct options options;
+ struct passwd *pwd;
+ int retval, retry, res, got;
+ const char *user, *pass;
+ char *new_pass, *new_pass_, *encrypted, *usrdup;
+
+ pam_std_option(&options, other_options, argc, argv);
+
+ PAM_LOG("Options processed");
+
+ if (pam_test_option(&options, PAM_OPT_AUTH_AS_SELF, NULL))
+ pwd = getpwnam(getlogin());
+ else {
+ retval = pam_get_user(pamh, &user, NULL);
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+ pwd = getpwnam(user);
+ }
+
+ PAM_LOG("Got user: %s", user);
+
+ if (flags & PAM_PRELIM_CHECK) {
+
+ PAM_LOG("PRELIM round; checking user password");
+
+ if (pwd->pw_passwd[0] == '\0'
+ && pam_test_option(&options, PAM_OPT_NULLOK, NULL)) {
+ /*
+ * No password case. XXX Are we giving too much away
+ * by not prompting for a password?
+ */
+ PAM_LOG("No password, and null password OK");
+ PAM_RETURN(PAM_SUCCESS);
+ }
+ else {
+ retval = pam_get_authtok(pamh, &pass,
+ PASSWORD_PROMPT_EXPIRED);
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+ PAM_LOG("Got password: %s", pass);
+ }
+ encrypted = crypt(pass, pwd->pw_passwd);
+ if (pass[0] == '\0' && pwd->pw_passwd[0] != '\0')
+ encrypted = colon;
+
+ PAM_LOG("Encrypted password 1 is: %s", encrypted);
+ PAM_LOG("Encrypted password 2 is: %s", pwd->pw_passwd);
+
+ if (strcmp(encrypted, pwd->pw_passwd) != 0)
+ PAM_RETURN(PAM_AUTH_ERR);
+
+ retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *)pass);
+ pass = NULL;
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+
+ PAM_LOG("Stashed old password");
+
+ retval = pam_set_item(pamh, PAM_AUTHTOK, (const void *)pass);
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+
+ PAM_LOG("Voided old password");
+
+ PAM_RETURN(PAM_SUCCESS);
+ }
+ else if (flags & PAM_UPDATE_AUTHTOK) {
+ PAM_LOG("UPDATE round; checking user password");
+
+ retval = pam_get_item(pamh, PAM_OLDAUTHTOK,
+ (const void **)&pass);
+ if (retval != PAM_SUCCESS)
+ PAM_RETURN(retval);
+
+ PAM_LOG("Got old password: %s", pass);
+
+ got = 0;
+ retry = 0;
+ while (retry++ < MAX_TRIES) {
+ new_pass = NULL;
+ retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF,
+ &new_pass, "%s", NEW_PASSWORD_PROMPT_1);
+
+ if (new_pass == NULL)
+ new_pass = blank;
+
+ if (retval == PAM_SUCCESS) {
+ new_pass_ = NULL;
+ retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF,
+ &new_pass_, "%s", NEW_PASSWORD_PROMPT_2);
+
+ if (new_pass_ == NULL)
+ new_pass_ = blank;
+
+ if (retval == PAM_SUCCESS) {
+ if (strcmp(new_pass, new_pass_) == 0) {
+ got = 1;
+ break;
+ }
+ else
+ PAM_VERBOSE_ERROR("Password mismatch");
+ }
+ }
+ }
+
+ if (!got) {
+ PAM_VERBOSE_ERROR("Unable to get valid password");
+ PAM_RETURN(PAM_PERM_DENIED);
+ }
+
+ PAM_LOG("Got new password: %s", new_pass);
+
+#ifdef YP
+ /* If NIS is set in the passwd database, use it */
+ if ((usrdup = strdup(user)) == NULL)
+ PAM_RETURN(PAM_BUF_ERR);
+ res = use_yp(usrdup, 0, 0);
+ free(usrdup);
+ if (res == USER_YP_ONLY) {
+ if (!pam_test_option(&options, PAM_OPT_LOCAL_PASS,
+ NULL))
+ retval = yp_passwd(user, new_pass);
+ else {
+ /* Reject 'local' flag if NIS is on and the user
+ * is not local
+ */
+ retval = PAM_PERM_DENIED;
+ PAM_LOG("Unknown local user: %s", user);
+ }
+ }
+ else if (res == USER_LOCAL_ONLY) {
+ if (!pam_test_option(&options, PAM_OPT_NIS_PASS, NULL))
+ retval = local_passwd(user, new_pass);
+ else {
+ /* Reject 'nis' flag if user is only local */
+ retval = PAM_PERM_DENIED;
+ PAM_LOG("Unknown NIS user: %s", user);
+ }
+ }
+ else if (res == USER_YP_AND_LOCAL) {
+ if (pam_test_option(&options, PAM_OPT_NIS_PASS, NULL))
+ retval = yp_passwd(user, new_pass);
+ else
+ retval = local_passwd(user, new_pass);
+ }
+ else
+ retval = PAM_SERVICE_ERR; /* Bad juju */
+#else
+ retval = local_passwd(user, new_pass);
+#endif
+
+ /* XXX wipe the mem as well */
+ pass = NULL;
+ new_pass = NULL;
+ }
+ else {
+ /* Very bad juju */
+ retval = PAM_ABORT;
+ PAM_LOG("Illegal 'flags'");
+ }
+
+ PAM_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;
+ }
+}
+
+static int
+local_passwd(const char *user, const char *pass)
+{
+ login_cap_t * lc;
+ struct passwd *pwd;
+ struct timeval tv;
+ int pfd, tfd;
+ char *crypt_type, salt[SALTSIZE + 1];
+
+ pwd = getpwnam(user);
+ if (pwd == NULL)
+ return(PAM_SERVICE_ERR); /* Really bad things */
+
+#ifdef YP
+ pwd = (struct passwd *)&local_password;
+#endif
+ pw_init();
+
+ pwd->pw_change = 0;
+ lc = login_getclass(NULL);
+ crypt_type = login_getcapstr(lc, "passwd_format",
+ password_hash, password_hash);
+ if (login_setcryptfmt(lc, crypt_type, NULL) == NULL)
+ syslog(LOG_ERR, "cannot set password cipher");
+ login_close(lc);
+ makesalt(salt);
+ pwd->pw_passwd = crypt(pass, salt);
+
+ pfd = pw_lock();
+ tfd = pw_tmp();
+ pw_copy(pfd, tfd, pwd, NULL);
+
+ if (!pw_mkdb(user))
+ pw_error((char *)NULL, 0, 1);
+
+ return (PAM_SUCCESS);
+}
+
+#ifdef YP
+/* Stolen from src/usr.bin/passwd/yp_passwd.c, carrying copyrights of:
+ * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca>
+ * Copyright (c) 1994 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (c) 1995 Bill Paul <wpaul@ctr.columbia.edu>
+ */
+int
+yp_passwd(const char *user __unused, const char *pass)
+{
+ struct master_yppasswd master_yppwd;
+ struct passwd *pwd;
+ struct rpc_err err;
+ struct timeval tv;
+ struct yppasswd yppwd;
+ CLIENT *clnt;
+ login_cap_t *lc;
+ int *status;
+ gid_t gid;
+ pid_t pid;
+ uid_t uid;
+ char *master, sockname[] = YP_SOCKNAME, salt[SALTSIZE + 1];
+
+ _use_yp = 1;
+
+ uid = getuid();
+
+ master = get_yp_master(1);
+ if (master == NULL)
+ return (PAM_SERVICE_ERR); /* Major disaster */
+
+ /*
+ * It is presumed that by the time we get here, use_yp()
+ * has been called and that we have verified that the user
+ * actually exists. This being the case, the yp_password
+ * stucture has already been filled in for us.
+ */
+
+ /* Use the correct password */
+ pwd = (struct passwd *)&yp_password;
+
+ pwd->pw_change = 0;
+
+ /* Initialize password information */
+ if (suser_override) {
+ master_yppwd.newpw.pw_passwd = strdup(pwd->pw_passwd);
+ master_yppwd.newpw.pw_name = strdup(pwd->pw_name);
+ master_yppwd.newpw.pw_uid = pwd->pw_uid;
+ master_yppwd.newpw.pw_gid = pwd->pw_gid;
+ master_yppwd.newpw.pw_expire = pwd->pw_expire;
+ master_yppwd.newpw.pw_change = pwd->pw_change;
+ master_yppwd.newpw.pw_fields = pwd->pw_fields;
+ master_yppwd.newpw.pw_gecos = strdup(pwd->pw_gecos);
+ master_yppwd.newpw.pw_dir = strdup(pwd->pw_dir);
+ master_yppwd.newpw.pw_shell = strdup(pwd->pw_shell);
+ master_yppwd.newpw.pw_class = pwd->pw_class != NULL ?
+ strdup(pwd->pw_class) : strdup("");
+ master_yppwd.oldpass = strdup("");
+ master_yppwd.domain = yp_domain;
+ } else {
+ yppwd.newpw.pw_passwd = strdup(pwd->pw_passwd);
+ yppwd.newpw.pw_name = strdup(pwd->pw_name);
+ yppwd.newpw.pw_uid = pwd->pw_uid;
+ yppwd.newpw.pw_gid = pwd->pw_gid;
+ yppwd.newpw.pw_gecos = strdup(pwd->pw_gecos);
+ yppwd.newpw.pw_dir = strdup(pwd->pw_dir);
+ yppwd.newpw.pw_shell = strdup(pwd->pw_shell);
+ yppwd.oldpass = strdup("");
+ }
+
+ if (login_setcryptfmt(lc, "md5", NULL) == NULL)
+ syslog(LOG_ERR, "cannot set password cipher");
+ login_close(lc);
+
+ makesalt(salt);
+ if (suser_override)
+ master_yppwd.newpw.pw_passwd = crypt(pass, salt);
+ else
+ yppwd.newpw.pw_passwd = crypt(pass, salt);
+
+ if (suser_override) {
+ if ((clnt = clnt_create(sockname, MASTER_YPPASSWDPROG,
+ MASTER_YPPASSWDVERS, "unix")) == NULL) {
+ syslog(LOG_ERR,
+ "Cannot contact rpc.yppasswdd on host %s: %s",
+ master, clnt_spcreateerror(""));
+ return (PAM_SERVICE_ERR);
+ }
+ }
+ else {
+ if ((clnt = clnt_create(master, YPPASSWDPROG,
+ YPPASSWDVERS, "udp")) == NULL) {
+ syslog(LOG_ERR,
+ "Cannot contact rpc.yppasswdd on host %s: %s",
+ master, clnt_spcreateerror(""));
+ return (PAM_SERVICE_ERR);
+ }
+ }
+ /*
+ * The yppasswd.x file said `unix authentication required',
+ * so I added it. This is the only reason it is in here.
+ * My yppasswdd doesn't use it, but maybe some others out there
+ * do. --okir
+ */
+ clnt->cl_auth = authunix_create_default();
+
+ if (suser_override)
+ status = yppasswdproc_update_master_1(&master_yppwd, clnt);
+ else
+ status = yppasswdproc_update_1(&yppwd, clnt);
+
+ clnt_geterr(clnt, &err);
+
+ auth_destroy(clnt->cl_auth);
+ clnt_destroy(clnt);
+
+ if (err.re_status != RPC_SUCCESS || status == NULL || *status)
+ return (PAM_SERVICE_ERR);
+
+ if (err.re_status || status == NULL || *status)
+ return (PAM_SERVICE_ERR);
+ return (PAM_SUCCESS);
+}
+#endif /* YP */
+
+/* Salt suitable for traditional DES and MD5 */
+void
+makesalt(char salt[SALTSIZE])
+{
+ int i;
+
+ /* These are not really random numbers, they are just
+ * numbers that change to thwart construction of a
+ * dictionary. This is exposed to the public.
+ */
+ for (i = 0; i < SALTSIZE; i += 4)
+ to64(&salt[i], arc4random(), 4);
+ salt[SALTSIZE] = '\0';
+}
+
+PAM_MODULE_ENTRY("pam_unix");
OpenPOWER on IntegriCloud