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/Makefile53
-rw-r--r--lib/libpam/modules/pam_unix/pam_unix.8215
-rw-r--r--lib/libpam/modules/pam_unix/pam_unix.c471
3 files changed, 739 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..fd48360
--- /dev/null
+++ b/lib/libpam/modules/pam_unix/Makefile
@@ -0,0 +1,53 @@
+# 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.
+#
+# $FreeBSD$
+
+NO_PROFILE=
+.include <bsd.own.mk>
+
+LIB= pam_unix
+SRCS= pam_unix.c
+MAN= pam_unix.8
+
+DPADD= ${LIBUTIL} ${LIBCRYPT}
+LDADD= -lutil -lcrypt
+
+.if ${MK_NIS} != "no"
+CFLAGS+= -DYP
+DPADD+= ${LIBYPCLNT}
+LDADD+= -lypclnt
+.endif
+
+.include <bsd.lib.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 0000000..60667e6
--- /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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 27, 2007
+.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 himself 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 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 syslog 3 ,
+.Xr nsswitch.conf 5 ,
+.Xr passwd 5 ,
+.Xr pam 8 ,
+.Xr pw 8 ,
+.Xr yp 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..46b5f47
--- /dev/null
+++ b/lib/libpam/modules/pam_unix/pam_unix.c
@@ -0,0 +1,471 @@
+/*-
+ * 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#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 <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 []);
+
+static char password_hash[] = PASSWORD_HASH;
+
+#define PAM_OPT_LOCAL_PASS "local_pass"
+#define PAM_OPT_NIS_PASS "nis_pass"
+
+char *tempname = NULL;
+
+/*
+ * authentication management
+ */
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
+ int argc __unused, const char *argv[] __unused)
+{
+ login_cap_t *lc;
+ struct passwd *pwd;
+ int retval;
+ const char *pass, *user, *realpw, *prompt;
+
+ if (openpam_get_option(pamh, PAM_OPT_AUTH_AS_SELF)) {
+ pwd = getpwnam(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);
+ realpw = "*";
+ }
+ 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 (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;
+ 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;
+ int pfd, tfd, retval;
+
+ if (openpam_get_option(pamh, PAM_OPT_AUTH_AS_SELF))
+ pwd = getpwnam(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 = "";
+ } 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);
+
+ pwd->pw_change = 0;
+ 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");
+ 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 */
+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