diff options
Diffstat (limited to 'lib/libpam/modules/pam_unix')
-rw-r--r-- | lib/libpam/modules/pam_unix/Makefile | 53 | ||||
-rw-r--r-- | lib/libpam/modules/pam_unix/pam_unix.8 | 215 | ||||
-rw-r--r-- | lib/libpam/modules/pam_unix/pam_unix.c | 471 |
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"); |