Index: head/lib/libpam/modules/pam_ssh/pam_ssh.8 =================================================================== --- head/lib/libpam/modules/pam_ssh/pam_ssh.8 (revision 82351) +++ head/lib/libpam/modules/pam_ssh/pam_ssh.8 (revision 82352) @@ -1,148 +1,178 @@ .\" 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. .\" .\" $FreeBSD$ .\" .Dd July 7, 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. .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 syslog 3 , .Xr pam.conf 5 , .Xr passwd 5 , .Xr pam 8 Index: head/lib/libpam/modules/pam_unix/Makefile =================================================================== --- head/lib/libpam/modules/pam_unix/Makefile (revision 82351) +++ head/lib/libpam/modules/pam_unix/Makefile (revision 82352) @@ -1,34 +1,78 @@ # 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= pam_unix.so -SRCS= pam_unix.c -DPADD= ${LIBUTIL} ${LIBCRYPT} -LDADD= -lutil -lcrypt +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 +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 + +.PATH: ${.CURDIR}/../../../../usr.bin/chpass +.PATH: ${.CURDIR}/../../../../usr.sbin/vipw +.PATH: ${.CURDIR}/../../../../libexec/ypxfr Index: head/lib/libpam/modules/pam_unix/pam_unix.8 =================================================================== --- head/lib/libpam/modules/pam_unix/pam_unix.8 (revision 82351) +++ head/lib/libpam/modules/pam_unix/pam_unix.8 (revision 82352) @@ -1,148 +1,178 @@ .\" 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. .\" .\" $FreeBSD$ .\" .Dd July 7, 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. .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 syslog 3 , .Xr pam.conf 5 , .Xr passwd 5 , .Xr pam 8 Index: head/lib/libpam/modules/pam_unix/pam_unix.c =================================================================== --- head/lib/libpam/modules/pam_unix/pam_unix.c (revision 82351) +++ head/lib/libpam/modules/pam_unix/pam_unix.c (revision 82352) @@ -1,217 +1,658 @@ /*- * 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$ */ #include #include +#ifdef YP +#include +#include +#include +#include +#endif #include #include #include #include #include #include +#include +#include + +#ifdef YP +#include +#include "yppasswd_private.h" +#endif + #define PAM_SM_AUTH #define PAM_SM_ACCOUNT +#define PAM_SM_SESSION +#define PAM_SM_PASSWORD + #include #include "pam_mod_misc.h" -#define PASSWORD_PROMPT "Password:" -#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */ +#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 -enum { PAM_OPT_AUTH_AS_SELF=PAM_OPT_STD_MAX, PAM_OPT_NULLOK }; +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, int argc, const char **argv) { + login_cap_t *lc; struct options options; struct passwd *pwd; int retval; - const char *password, *user; - char *encrypted; + 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 = getpwuid(getuid()); + 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, PASSWORD_PROMPT); + 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_pass(pamh, &password, PASSWORD_PROMPT, + retval = pam_get_pass(pamh, &pass, password_prompt, &options); if (retval != PAM_SUCCESS) PAM_RETURN(retval); PAM_LOG("Got password"); } - encrypted = crypt(password, pwd->pw_passwd); - if (password[0] == '\0' && pwd->pw_passwd[0] != '\0') + encrypted = crypt(pass, pwd->pw_passwd); + if (pass[0] == '\0' && pwd->pw_passwd[0] != '\0') encrypted = ":"; - PAM_LOG("Encrypted passwords are: %s & %s", encrypted, - pwd->pw_passwd); + 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_pass(pamh, &password, PASSWORD_PROMPT, + retval = pam_get_pass(pamh, &pass, password_prompt, &options); if (retval != PAM_SUCCESS) PAM_RETURN(retval); PAM_LOG("Got password"); - crypt(password, "xx"); + 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, int flags, int argc, const char **argv) { - return PAM_SUCCESS; + struct options options; + + pam_std_option(&options, other_options, argc, argv); + + PAM_LOG("Options processed"); + + PAM_RETURN(PAM_SUCCESS); } /* * account management - * - * check pw_change and pw_expire fields */ -PAM_EXTERN -int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) +PAM_EXTERN int +pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { struct options options; struct passwd *pw; struct timeval tp; login_cap_t *lc; time_t warntime; int retval; const char *user; char buf[128]; 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 || user == NULL) /* some implementations return PAM_SUCCESS here */ PAM_RETURN(PAM_USER_UNKNOWN); pw = getpwnam(user); if (pw == NULL) PAM_RETURN(PAM_USER_UNKNOWN); PAM_LOG("Got user: %s", user); retval = PAM_SUCCESS; lc = login_getpwclass(pw); if (pw->pw_change || pw->pw_expire) gettimeofday(&tp, NULL); warntime = login_getcaptime(lc, "warnpassword", DEFAULT_WARN, DEFAULT_WARN); PAM_LOG("Got login_cap"); if (pw->pw_change) { if (tp.tv_sec >= pw->pw_change) /* some implementations return PAM_AUTHTOK_EXPIRED */ retval = PAM_NEW_AUTHTOK_REQD; else if (pw->pw_change - tp.tv_sec < warntime) { snprintf(buf, sizeof(buf), "Warning: your password expires on %s", ctime(&pw->pw_change)); pam_prompt(pamh, PAM_ERROR_MSG, buf, NULL); } } warntime = login_getcaptime(lc, "warnexpire", DEFAULT_WARN, DEFAULT_WARN); if (pw->pw_expire) { if (tp.tv_sec >= pw->pw_expire) retval = PAM_ACCT_EXPIRED; else if (pw->pw_expire - tp.tv_sec < warntime) { snprintf(buf, sizeof(buf), "Warning: your account expires on %s", ctime(&pw->pw_expire)); pam_prompt(pamh, PAM_ERROR_MSG, buf, NULL); } } login_close(lc); PAM_RETURN(retval); } + +/* + * session management + * + * logging only + */ +PAM_EXTERN int +pam_sm_open_session(pam_handle_t *pamh, int flags, 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, int flags, 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; + + 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_pass(pamh, &pass, + PASSWORD_PROMPT_EXPIRED, &options); + 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 = ":"; + + 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_PASSWORD_PROMPT_1, &new_pass); + + if (new_pass == NULL) + new_pass = ""; + + if (retval == PAM_SUCCESS) { + new_pass_ = NULL; + retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, + NEW_PASSWORD_PROMPT_2, &new_pass_); + + if (new_pass_ == NULL) + new_pass_ = ""; + + 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 */ + res = use_yp((char *)user, 0, 0); + 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_ABORT; /* 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[32]; + + pwd = getpwnam(user); + if (pwd == NULL) + return(PAM_ABORT); /* 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); + /* Salt suitable for anything */ + srandomdev(); + gettimeofday(&tv, 0); + to64(&salt[0], random(), 3); + to64(&salt[3], tv.tv_usec, 3); + to64(&salt[6], tv.tv_sec, 2); + to64(&salt[8], random(), 5); + to64(&salt[13], random(), 5); + to64(&salt[17], random(), 5); + to64(&salt[22], random(), 5); + salt[27] = '\0'; + + pwd->pw_passwd = crypt(pass, salt); + + pfd = pw_lock(); + tfd = pw_tmp(); + pw_copy(pfd, tfd, pwd); + + if (!pw_mkdb((char *)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 + * Copyright (c) 1994 Olaf Kirch + * Copyright (c) 1995 Bill Paul + */ +int +yp_passwd(const char *user, const char *pass) +{ + struct master_yppasswd master_yppasswd; + struct passwd *pwd; + struct rpc_err err; + struct timeval tv; + struct yppasswd yppasswd; + CLIENT *clnt; + login_cap_t *lc; + int *status; + uid_t uid; + char *master, *sockname = YP_SOCKNAME, salt[32]; + + _use_yp = 1; + + uid = getuid(); + + master = get_yp_master(1); + if (master == NULL) + return PAM_ABORT; /* 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_yppasswd.newpw.pw_passwd = strdup(pwd->pw_passwd); + master_yppasswd.newpw.pw_name = strdup(pwd->pw_name); + master_yppasswd.newpw.pw_uid = pwd->pw_uid; + master_yppasswd.newpw.pw_gid = pwd->pw_gid; + master_yppasswd.newpw.pw_expire = pwd->pw_expire; + master_yppasswd.newpw.pw_change = pwd->pw_change; + master_yppasswd.newpw.pw_fields = pwd->pw_fields; + master_yppasswd.newpw.pw_gecos = strdup(pwd->pw_gecos); + master_yppasswd.newpw.pw_dir = strdup(pwd->pw_dir); + master_yppasswd.newpw.pw_shell = strdup(pwd->pw_shell); + master_yppasswd.newpw.pw_class = pwd->pw_class != NULL ? + strdup(pwd->pw_class) : ""; + master_yppasswd.oldpass = ""; + master_yppasswd.domain = yp_domain; + } else { + yppasswd.newpw.pw_passwd = strdup(pwd->pw_passwd); + yppasswd.newpw.pw_name = strdup(pwd->pw_name); + yppasswd.newpw.pw_uid = pwd->pw_uid; + yppasswd.newpw.pw_gid = pwd->pw_gid; + yppasswd.newpw.pw_gecos = strdup(pwd->pw_gecos); + yppasswd.newpw.pw_dir = strdup(pwd->pw_dir); + yppasswd.newpw.pw_shell = strdup(pwd->pw_shell); + yppasswd.oldpass = ""; + } + + if (login_setcryptfmt(lc, "md5", NULL) == NULL) + syslog(LOG_ERR, "cannot set password cipher"); + login_close(lc); + /* Salt suitable for anything */ + srandomdev(); + gettimeofday(&tv, 0); + to64(&salt[0], random(), 3); + to64(&salt[3], tv.tv_usec, 3); + to64(&salt[6], tv.tv_sec, 2); + to64(&salt[8], random(), 5); + to64(&salt[13], random(), 5); + to64(&salt[17], random(), 5); + to64(&salt[22], random(), 5); + salt[27] = '\0'; + + if (suser_override) + master_yppasswd.newpw.pw_passwd = crypt(pass, salt); + else + yppasswd.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_ABORT; + } + } + 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_ABORT; + } + } + /* + * 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_yppasswd, clnt); + else + status = yppasswdproc_update_1(&yppasswd, clnt); + + clnt_geterr(clnt, &err); + + auth_destroy(clnt->cl_auth); + clnt_destroy(clnt); + + if (err.re_status != RPC_SUCCESS || status == NULL || *status) + return PAM_ABORT; + + return (err.re_status || status == NULL || *status) + ? PAM_ABORT : PAM_SUCCESS; +} +#endif /* YP */ PAM_MODULE_ENTRY("pam_unix");