19a10bb17SJohn Polstra /*- 29a10bb17SJohn Polstra * Copyright 1998 Juniper Networks, Inc. 39a10bb17SJohn Polstra * All rights reserved. 49a10bb17SJohn Polstra * 59a10bb17SJohn Polstra * Redistribution and use in source and binary forms, with or without 69a10bb17SJohn Polstra * modification, are permitted provided that the following conditions 79a10bb17SJohn Polstra * are met: 89a10bb17SJohn Polstra * 1. Redistributions of source code must retain the above copyright 99a10bb17SJohn Polstra * notice, this list of conditions and the following disclaimer. 109a10bb17SJohn Polstra * 2. Redistributions in binary form must reproduce the above copyright 119a10bb17SJohn Polstra * notice, this list of conditions and the following disclaimer in the 129a10bb17SJohn Polstra * documentation and/or other materials provided with the distribution. 139a10bb17SJohn Polstra * 149a10bb17SJohn Polstra * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 159a10bb17SJohn Polstra * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 169a10bb17SJohn Polstra * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 179a10bb17SJohn Polstra * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 189a10bb17SJohn Polstra * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 199a10bb17SJohn Polstra * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 209a10bb17SJohn Polstra * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 219a10bb17SJohn Polstra * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 229a10bb17SJohn Polstra * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 239a10bb17SJohn Polstra * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 249a10bb17SJohn Polstra * SUCH DAMAGE. 259a10bb17SJohn Polstra * 269a10bb17SJohn Polstra * $FreeBSD$ 279a10bb17SJohn Polstra */ 289a10bb17SJohn Polstra 299a10bb17SJohn Polstra #include <sys/types.h> 30d65b34dbSJohn Polstra #include <sys/time.h> 313d55a6c0SMark Murray #ifdef YP 323d55a6c0SMark Murray #include <rpc/rpc.h> 333d55a6c0SMark Murray #include <rpcsvc/yp_prot.h> 343d55a6c0SMark Murray #include <rpcsvc/ypclnt.h> 353d55a6c0SMark Murray #include <rpcsvc/yppasswd.h> 363d55a6c0SMark Murray #endif 37d65b34dbSJohn Polstra #include <login_cap.h> 389a10bb17SJohn Polstra #include <pwd.h> 399a10bb17SJohn Polstra #include <stdlib.h> 409a10bb17SJohn Polstra #include <string.h> 41d65b34dbSJohn Polstra #include <stdio.h> 429a10bb17SJohn Polstra #include <unistd.h> 439a10bb17SJohn Polstra 443d55a6c0SMark Murray #include <pw_copy.h> 453d55a6c0SMark Murray #include <pw_util.h> 463d55a6c0SMark Murray 473d55a6c0SMark Murray #ifdef YP 483d55a6c0SMark Murray #include <pw_yp.h> 493d55a6c0SMark Murray #include "yppasswd_private.h" 503d55a6c0SMark Murray #endif 513d55a6c0SMark Murray 529a10bb17SJohn Polstra #define PAM_SM_AUTH 53d65b34dbSJohn Polstra #define PAM_SM_ACCOUNT 543d55a6c0SMark Murray #define PAM_SM_SESSION 553d55a6c0SMark Murray #define PAM_SM_PASSWORD 563d55a6c0SMark Murray 579a10bb17SJohn Polstra #include <security/pam_modules.h> 589a10bb17SJohn Polstra 599a10bb17SJohn Polstra #include "pam_mod_misc.h" 609a10bb17SJohn Polstra 613d55a6c0SMark Murray #define USER_PROMPT "Username: " 629a10bb17SJohn Polstra #define PASSWORD_PROMPT "Password: " 633d55a6c0SMark Murray #define PASSWORD_PROMPT_EXPIRED "\nPassword expired\nOld Password: " 643d55a6c0SMark Murray #define NEW_PASSWORD_PROMPT_1 "New Password: " 653d55a6c0SMark Murray #define NEW_PASSWORD_PROMPT_2 "New Password (again): " 663d55a6c0SMark Murray #define PASSWORD_HASH "md5" 671642eb1aSMark Murray #define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */ 683d55a6c0SMark Murray #define MAX_TRIES 3 691642eb1aSMark Murray 703d55a6c0SMark Murray enum { PAM_OPT_AUTH_AS_SELF=PAM_OPT_STD_MAX, PAM_OPT_NULLOK, PAM_OPT_LOCAL_PASS, PAM_OPT_NIS_PASS }; 711642eb1aSMark Murray 721642eb1aSMark Murray static struct opttab other_options[] = { 731642eb1aSMark Murray { "auth_as_self", PAM_OPT_AUTH_AS_SELF }, 741642eb1aSMark Murray { "nullok", PAM_OPT_NULLOK }, 753d55a6c0SMark Murray { "local_pass", PAM_OPT_LOCAL_PASS }, 763d55a6c0SMark Murray { "nis_pass", PAM_OPT_NIS_PASS }, 771642eb1aSMark Murray { NULL, 0 } 781642eb1aSMark Murray }; 799a10bb17SJohn Polstra 803d55a6c0SMark Murray #ifdef YP 813d55a6c0SMark Murray int pam_use_yp = 0; 823d55a6c0SMark Murray int yp_errno = YP_TRUE; 833d55a6c0SMark Murray #endif 843d55a6c0SMark Murray 853d55a6c0SMark Murray char *tempname = NULL; 863d55a6c0SMark Murray static int local_passwd(const char *user, const char *pass); 873d55a6c0SMark Murray #ifdef YP 883d55a6c0SMark Murray static int yp_passwd(const char *user, const char *pass); 893d55a6c0SMark Murray #endif 903d55a6c0SMark Murray 91d65b34dbSJohn Polstra /* 92d65b34dbSJohn Polstra * authentication management 93d65b34dbSJohn Polstra */ 949a10bb17SJohn Polstra PAM_EXTERN int 951642eb1aSMark Murray pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) 969a10bb17SJohn Polstra { 973d55a6c0SMark Murray login_cap_t *lc; 981642eb1aSMark Murray struct options options; 999a10bb17SJohn Polstra struct passwd *pwd; 1001642eb1aSMark Murray int retval; 1013d55a6c0SMark Murray const char *pass, *user; 1023d55a6c0SMark Murray char *encrypted, *password_prompt; 1039a10bb17SJohn Polstra 1041642eb1aSMark Murray pam_std_option(&options, other_options, argc, argv); 1051642eb1aSMark Murray 1061642eb1aSMark Murray PAM_LOG("Options processed"); 1071642eb1aSMark Murray 1081642eb1aSMark Murray if (pam_test_option(&options, PAM_OPT_AUTH_AS_SELF, NULL)) 1093d55a6c0SMark Murray pwd = getpwnam(getlogin()); 1104448b21cSMark Murray else { 1111642eb1aSMark Murray retval = pam_get_user(pamh, &user, NULL); 1121642eb1aSMark Murray if (retval != PAM_SUCCESS) 1131642eb1aSMark Murray PAM_RETURN(retval); 1144448b21cSMark Murray pwd = getpwnam(user); 1154448b21cSMark Murray } 1161642eb1aSMark Murray 1171642eb1aSMark Murray PAM_LOG("Got user: %s", user); 1181642eb1aSMark Murray 1193d55a6c0SMark Murray lc = login_getclass(NULL); 1203d55a6c0SMark Murray password_prompt = login_getcapstr(lc, "passwd_prompt", 1213d55a6c0SMark Murray PASSWORD_PROMPT, PASSWORD_PROMPT); 1223d55a6c0SMark Murray login_close(lc); 1233d55a6c0SMark Murray lc = NULL; 1243d55a6c0SMark Murray 1254448b21cSMark Murray if (pwd != NULL) { 1261642eb1aSMark Murray 1271642eb1aSMark Murray PAM_LOG("Doing real authentication"); 1281642eb1aSMark Murray 1291642eb1aSMark Murray if (pwd->pw_passwd[0] == '\0' 1301642eb1aSMark Murray && pam_test_option(&options, PAM_OPT_NULLOK, NULL)) { 13146efbac2SMark Murray /* 13246efbac2SMark Murray * No password case. XXX Are we giving too much away 13346efbac2SMark Murray * by not prompting for a password? 13446efbac2SMark Murray */ 1351642eb1aSMark Murray PAM_LOG("No password, and null password OK"); 1361642eb1aSMark Murray PAM_RETURN(PAM_SUCCESS); 1371642eb1aSMark Murray } 13846efbac2SMark Murray else { 1393d55a6c0SMark Murray retval = pam_get_pass(pamh, &pass, password_prompt, 1401642eb1aSMark Murray &options); 1411642eb1aSMark Murray if (retval != PAM_SUCCESS) 1421642eb1aSMark Murray PAM_RETURN(retval); 1431642eb1aSMark Murray PAM_LOG("Got password"); 14446efbac2SMark Murray } 1453d55a6c0SMark Murray encrypted = crypt(pass, pwd->pw_passwd); 1463d55a6c0SMark Murray if (pass[0] == '\0' && pwd->pw_passwd[0] != '\0') 1479a10bb17SJohn Polstra encrypted = ":"; 1489a10bb17SJohn Polstra 1493d55a6c0SMark Murray PAM_LOG("Encrypted password 1 is: %s", encrypted); 1503d55a6c0SMark Murray PAM_LOG("Encrypted password 2 is: %s", pwd->pw_passwd); 1511642eb1aSMark Murray 1529a10bb17SJohn Polstra retval = strcmp(encrypted, pwd->pw_passwd) == 0 ? 1539a10bb17SJohn Polstra PAM_SUCCESS : PAM_AUTH_ERR; 1541642eb1aSMark Murray } 1551642eb1aSMark Murray else { 1561642eb1aSMark Murray 1571642eb1aSMark Murray PAM_LOG("Doing dummy authentication"); 1581642eb1aSMark Murray 1599a10bb17SJohn Polstra /* 1601642eb1aSMark Murray * User unknown. 1611642eb1aSMark Murray * Encrypt a dummy password so as to not give away too much. 1629a10bb17SJohn Polstra */ 1633d55a6c0SMark Murray retval = pam_get_pass(pamh, &pass, password_prompt, 1641642eb1aSMark Murray &options); 1651642eb1aSMark Murray if (retval != PAM_SUCCESS) 1661642eb1aSMark Murray PAM_RETURN(retval); 1671642eb1aSMark Murray PAM_LOG("Got password"); 1683d55a6c0SMark Murray crypt(pass, "xx"); 1699a10bb17SJohn Polstra retval = PAM_AUTH_ERR; 1709a10bb17SJohn Polstra } 1711642eb1aSMark Murray 1729a10bb17SJohn Polstra /* 1739a10bb17SJohn Polstra * The PAM infrastructure will obliterate the cleartext 1749a10bb17SJohn Polstra * password before returning to the application. 1759a10bb17SJohn Polstra */ 1763d55a6c0SMark Murray if (retval != PAM_SUCCESS) 1773d55a6c0SMark Murray PAM_VERBOSE_ERROR("UNIX authentication refused"); 1783d55a6c0SMark Murray 1791642eb1aSMark Murray PAM_RETURN(retval); 1809a10bb17SJohn Polstra } 1819a10bb17SJohn Polstra 1829a10bb17SJohn Polstra PAM_EXTERN int 1839a10bb17SJohn Polstra pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) 1849a10bb17SJohn Polstra { 1853d55a6c0SMark Murray struct options options; 1863d55a6c0SMark Murray 1873d55a6c0SMark Murray pam_std_option(&options, other_options, argc, argv); 1883d55a6c0SMark Murray 1893d55a6c0SMark Murray PAM_LOG("Options processed"); 1903d55a6c0SMark Murray 1913d55a6c0SMark Murray PAM_RETURN(PAM_SUCCESS); 1929a10bb17SJohn Polstra } 1939294327dSJohn Polstra 194d65b34dbSJohn Polstra /* 195d65b34dbSJohn Polstra * account management 196d65b34dbSJohn Polstra */ 1973d55a6c0SMark Murray PAM_EXTERN int 1983d55a6c0SMark Murray pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) 199d65b34dbSJohn Polstra { 2001642eb1aSMark Murray struct options options; 201d65b34dbSJohn Polstra struct passwd *pw; 202d65b34dbSJohn Polstra struct timeval tp; 2031642eb1aSMark Murray login_cap_t *lc; 204d65b34dbSJohn Polstra time_t warntime; 205d65b34dbSJohn Polstra int retval; 2061642eb1aSMark Murray const char *user; 2071642eb1aSMark Murray char buf[128]; 2081642eb1aSMark Murray 2091642eb1aSMark Murray pam_std_option(&options, other_options, argc, argv); 2101642eb1aSMark Murray 2111642eb1aSMark Murray PAM_LOG("Options processed"); 212d65b34dbSJohn Polstra 213d65b34dbSJohn Polstra retval = pam_get_item(pamh, PAM_USER, (const void **)&user); 214d65b34dbSJohn Polstra if (retval != PAM_SUCCESS || user == NULL) 215d65b34dbSJohn Polstra /* some implementations return PAM_SUCCESS here */ 2161642eb1aSMark Murray PAM_RETURN(PAM_USER_UNKNOWN); 217d65b34dbSJohn Polstra 2181642eb1aSMark Murray pw = getpwnam(user); 2191642eb1aSMark Murray if (pw == NULL) 2201642eb1aSMark Murray PAM_RETURN(PAM_USER_UNKNOWN); 2211642eb1aSMark Murray 2221642eb1aSMark Murray PAM_LOG("Got user: %s", user); 223d65b34dbSJohn Polstra 224d65b34dbSJohn Polstra retval = PAM_SUCCESS; 225d65b34dbSJohn Polstra lc = login_getpwclass(pw); 226d65b34dbSJohn Polstra 227d65b34dbSJohn Polstra if (pw->pw_change || pw->pw_expire) 228d65b34dbSJohn Polstra gettimeofday(&tp, NULL); 229d65b34dbSJohn Polstra 230d65b34dbSJohn Polstra warntime = login_getcaptime(lc, "warnpassword", DEFAULT_WARN, 231d65b34dbSJohn Polstra DEFAULT_WARN); 232d65b34dbSJohn Polstra 2331642eb1aSMark Murray PAM_LOG("Got login_cap"); 2341642eb1aSMark Murray 235d65b34dbSJohn Polstra if (pw->pw_change) { 236d65b34dbSJohn Polstra if (tp.tv_sec >= pw->pw_change) 237d65b34dbSJohn Polstra /* some implementations return PAM_AUTHTOK_EXPIRED */ 238d65b34dbSJohn Polstra retval = PAM_NEW_AUTHTOK_REQD; 239d65b34dbSJohn Polstra else if (pw->pw_change - tp.tv_sec < warntime) { 240d65b34dbSJohn Polstra snprintf(buf, sizeof(buf), 241d65b34dbSJohn Polstra "Warning: your password expires on %s", 242d65b34dbSJohn Polstra ctime(&pw->pw_change)); 243d65b34dbSJohn Polstra pam_prompt(pamh, PAM_ERROR_MSG, buf, NULL); 244d65b34dbSJohn Polstra } 245d65b34dbSJohn Polstra } 246d65b34dbSJohn Polstra 247d65b34dbSJohn Polstra warntime = login_getcaptime(lc, "warnexpire", DEFAULT_WARN, 248d65b34dbSJohn Polstra DEFAULT_WARN); 249d65b34dbSJohn Polstra 250d65b34dbSJohn Polstra if (pw->pw_expire) { 251d65b34dbSJohn Polstra if (tp.tv_sec >= pw->pw_expire) 252d65b34dbSJohn Polstra retval = PAM_ACCT_EXPIRED; 253d65b34dbSJohn Polstra else if (pw->pw_expire - tp.tv_sec < warntime) { 254d65b34dbSJohn Polstra snprintf(buf, sizeof(buf), 255d65b34dbSJohn Polstra "Warning: your account expires on %s", 256d65b34dbSJohn Polstra ctime(&pw->pw_expire)); 257d65b34dbSJohn Polstra pam_prompt(pamh, PAM_ERROR_MSG, buf, NULL); 258d65b34dbSJohn Polstra } 259d65b34dbSJohn Polstra } 260d65b34dbSJohn Polstra 261d65b34dbSJohn Polstra login_close(lc); 2621642eb1aSMark Murray 2631642eb1aSMark Murray PAM_RETURN(retval); 264d65b34dbSJohn Polstra } 265d65b34dbSJohn Polstra 2663d55a6c0SMark Murray /* 2673d55a6c0SMark Murray * session management 2683d55a6c0SMark Murray * 2693d55a6c0SMark Murray * logging only 2703d55a6c0SMark Murray */ 2713d55a6c0SMark Murray PAM_EXTERN int 2723d55a6c0SMark Murray pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) 2733d55a6c0SMark Murray { 2743d55a6c0SMark Murray struct options options; 2753d55a6c0SMark Murray 2763d55a6c0SMark Murray pam_std_option(&options, other_options, argc, argv); 2773d55a6c0SMark Murray 2783d55a6c0SMark Murray PAM_LOG("Options processed"); 2793d55a6c0SMark Murray 2803d55a6c0SMark Murray PAM_RETURN(PAM_SUCCESS); 2813d55a6c0SMark Murray } 2823d55a6c0SMark Murray 2833d55a6c0SMark Murray PAM_EXTERN int 2843d55a6c0SMark Murray pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv) 2853d55a6c0SMark Murray { 2863d55a6c0SMark Murray struct options options; 2873d55a6c0SMark Murray 2883d55a6c0SMark Murray pam_std_option(&options, other_options, argc, argv); 2893d55a6c0SMark Murray 2903d55a6c0SMark Murray PAM_LOG("Options processed"); 2913d55a6c0SMark Murray 2923d55a6c0SMark Murray PAM_RETURN(PAM_SUCCESS); 2933d55a6c0SMark Murray } 2943d55a6c0SMark Murray 2953d55a6c0SMark Murray /* 2963d55a6c0SMark Murray * password management 2973d55a6c0SMark Murray * 2983d55a6c0SMark Murray * standard Unix and NIS password changing 2993d55a6c0SMark Murray */ 3003d55a6c0SMark Murray PAM_EXTERN int 3013d55a6c0SMark Murray pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) 3023d55a6c0SMark Murray { 3033d55a6c0SMark Murray struct options options; 3043d55a6c0SMark Murray struct passwd *pwd; 3053d55a6c0SMark Murray int retval, retry, res, got; 3063d55a6c0SMark Murray const char *user, *pass; 3073d55a6c0SMark Murray char *new_pass, *new_pass_, *encrypted; 3083d55a6c0SMark Murray 3093d55a6c0SMark Murray pam_std_option(&options, other_options, argc, argv); 3103d55a6c0SMark Murray 3113d55a6c0SMark Murray PAM_LOG("Options processed"); 3123d55a6c0SMark Murray 3133d55a6c0SMark Murray if (pam_test_option(&options, PAM_OPT_AUTH_AS_SELF, NULL)) 3143d55a6c0SMark Murray pwd = getpwnam(getlogin()); 3153d55a6c0SMark Murray else { 3163d55a6c0SMark Murray retval = pam_get_user(pamh, &user, NULL); 3173d55a6c0SMark Murray if (retval != PAM_SUCCESS) 3183d55a6c0SMark Murray PAM_RETURN(retval); 3193d55a6c0SMark Murray pwd = getpwnam(user); 3203d55a6c0SMark Murray } 3213d55a6c0SMark Murray 3223d55a6c0SMark Murray PAM_LOG("Got user: %s", user); 3233d55a6c0SMark Murray 3243d55a6c0SMark Murray if (flags & PAM_PRELIM_CHECK) { 3253d55a6c0SMark Murray 3263d55a6c0SMark Murray PAM_LOG("PRELIM round; checking user password"); 3273d55a6c0SMark Murray 3283d55a6c0SMark Murray if (pwd->pw_passwd[0] == '\0' 3293d55a6c0SMark Murray && pam_test_option(&options, PAM_OPT_NULLOK, NULL)) { 3303d55a6c0SMark Murray /* 3313d55a6c0SMark Murray * No password case. XXX Are we giving too much away 3323d55a6c0SMark Murray * by not prompting for a password? 3333d55a6c0SMark Murray */ 3343d55a6c0SMark Murray PAM_LOG("No password, and null password OK"); 3353d55a6c0SMark Murray PAM_RETURN(PAM_SUCCESS); 3363d55a6c0SMark Murray } 3373d55a6c0SMark Murray else { 3383d55a6c0SMark Murray retval = pam_get_pass(pamh, &pass, 3393d55a6c0SMark Murray PASSWORD_PROMPT_EXPIRED, &options); 3403d55a6c0SMark Murray if (retval != PAM_SUCCESS) 3413d55a6c0SMark Murray PAM_RETURN(retval); 3423d55a6c0SMark Murray PAM_LOG("Got password: %s", pass); 3433d55a6c0SMark Murray } 3443d55a6c0SMark Murray encrypted = crypt(pass, pwd->pw_passwd); 3453d55a6c0SMark Murray if (pass[0] == '\0' && pwd->pw_passwd[0] != '\0') 3463d55a6c0SMark Murray encrypted = ":"; 3473d55a6c0SMark Murray 3483d55a6c0SMark Murray PAM_LOG("Encrypted password 1 is: %s", encrypted); 3493d55a6c0SMark Murray PAM_LOG("Encrypted password 2 is: %s", pwd->pw_passwd); 3503d55a6c0SMark Murray 3513d55a6c0SMark Murray if (strcmp(encrypted, pwd->pw_passwd) != 0) 3523d55a6c0SMark Murray PAM_RETURN(PAM_AUTH_ERR); 3533d55a6c0SMark Murray 3543d55a6c0SMark Murray retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *)pass); 3553d55a6c0SMark Murray pass = NULL; 3563d55a6c0SMark Murray if (retval != PAM_SUCCESS) 3573d55a6c0SMark Murray PAM_RETURN(retval); 3583d55a6c0SMark Murray 3593d55a6c0SMark Murray PAM_LOG("Stashed old password"); 3603d55a6c0SMark Murray 3613d55a6c0SMark Murray retval = pam_set_item(pamh, PAM_AUTHTOK, (const void *)pass); 3623d55a6c0SMark Murray if (retval != PAM_SUCCESS) 3633d55a6c0SMark Murray PAM_RETURN(retval); 3643d55a6c0SMark Murray 3653d55a6c0SMark Murray PAM_LOG("Voided old password"); 3663d55a6c0SMark Murray 3673d55a6c0SMark Murray PAM_RETURN(PAM_SUCCESS); 3683d55a6c0SMark Murray } 3693d55a6c0SMark Murray else if (flags & PAM_UPDATE_AUTHTOK) { 3703d55a6c0SMark Murray PAM_LOG("UPDATE round; checking user password"); 3713d55a6c0SMark Murray 3723d55a6c0SMark Murray retval = pam_get_item(pamh, PAM_OLDAUTHTOK, 3733d55a6c0SMark Murray (const void **)&pass); 3743d55a6c0SMark Murray if (retval != PAM_SUCCESS) 3753d55a6c0SMark Murray PAM_RETURN(retval); 3763d55a6c0SMark Murray 3773d55a6c0SMark Murray PAM_LOG("Got old password: %s", pass); 3783d55a6c0SMark Murray 3793d55a6c0SMark Murray got = 0; 3803d55a6c0SMark Murray retry = 0; 3813d55a6c0SMark Murray while (retry++ < MAX_TRIES) { 3823d55a6c0SMark Murray new_pass = NULL; 3833d55a6c0SMark Murray retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, 3843d55a6c0SMark Murray NEW_PASSWORD_PROMPT_1, &new_pass); 3853d55a6c0SMark Murray 3863d55a6c0SMark Murray if (new_pass == NULL) 3873d55a6c0SMark Murray new_pass = ""; 3883d55a6c0SMark Murray 3893d55a6c0SMark Murray if (retval == PAM_SUCCESS) { 3903d55a6c0SMark Murray new_pass_ = NULL; 3913d55a6c0SMark Murray retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, 3923d55a6c0SMark Murray NEW_PASSWORD_PROMPT_2, &new_pass_); 3933d55a6c0SMark Murray 3943d55a6c0SMark Murray if (new_pass_ == NULL) 3953d55a6c0SMark Murray new_pass_ = ""; 3963d55a6c0SMark Murray 3973d55a6c0SMark Murray if (retval == PAM_SUCCESS) { 3983d55a6c0SMark Murray if (strcmp(new_pass, new_pass_) == 0) { 3993d55a6c0SMark Murray got = 1; 4003d55a6c0SMark Murray break; 4013d55a6c0SMark Murray } 4023d55a6c0SMark Murray else 4033d55a6c0SMark Murray PAM_VERBOSE_ERROR("Password mismatch"); 4043d55a6c0SMark Murray } 4053d55a6c0SMark Murray } 4063d55a6c0SMark Murray } 4073d55a6c0SMark Murray 4083d55a6c0SMark Murray if (!got) { 4093d55a6c0SMark Murray PAM_VERBOSE_ERROR("Unable to get valid password"); 4103d55a6c0SMark Murray PAM_RETURN(PAM_PERM_DENIED); 4113d55a6c0SMark Murray } 4123d55a6c0SMark Murray 4133d55a6c0SMark Murray PAM_LOG("Got new password: %s", new_pass); 4143d55a6c0SMark Murray 4153d55a6c0SMark Murray #ifdef YP 4163d55a6c0SMark Murray /* If NIS is set in the passwd database, use it */ 4173d55a6c0SMark Murray res = use_yp((char *)user, 0, 0); 4183d55a6c0SMark Murray if (res == USER_YP_ONLY) { 4193d55a6c0SMark Murray if (!pam_test_option(&options, PAM_OPT_LOCAL_PASS, 4203d55a6c0SMark Murray NULL)) 4213d55a6c0SMark Murray retval = yp_passwd(user, new_pass); 4223d55a6c0SMark Murray else { 4233d55a6c0SMark Murray /* Reject 'local' flag if NIS is on and the user 4243d55a6c0SMark Murray * is not local 4253d55a6c0SMark Murray */ 4263d55a6c0SMark Murray retval = PAM_PERM_DENIED; 4273d55a6c0SMark Murray PAM_LOG("Unknown local user: %s", user); 4283d55a6c0SMark Murray } 4293d55a6c0SMark Murray } 4303d55a6c0SMark Murray else if (res == USER_LOCAL_ONLY) { 4313d55a6c0SMark Murray if (!pam_test_option(&options, PAM_OPT_NIS_PASS, NULL)) 4323d55a6c0SMark Murray retval = local_passwd(user, new_pass); 4333d55a6c0SMark Murray else { 4343d55a6c0SMark Murray /* Reject 'nis' flag if user is only local */ 4353d55a6c0SMark Murray retval = PAM_PERM_DENIED; 4363d55a6c0SMark Murray PAM_LOG("Unknown NIS user: %s", user); 4373d55a6c0SMark Murray } 4383d55a6c0SMark Murray } 4393d55a6c0SMark Murray else if (res == USER_YP_AND_LOCAL) { 4403d55a6c0SMark Murray if (pam_test_option(&options, PAM_OPT_NIS_PASS, NULL)) 4413d55a6c0SMark Murray retval = yp_passwd(user, new_pass); 4423d55a6c0SMark Murray else 4433d55a6c0SMark Murray retval = local_passwd(user, new_pass); 4443d55a6c0SMark Murray } 4453d55a6c0SMark Murray else 4463d55a6c0SMark Murray retval = PAM_ABORT; /* Bad juju */ 4473d55a6c0SMark Murray #else 4483d55a6c0SMark Murray retval = local_passwd(user, new_pass); 4493d55a6c0SMark Murray #endif 4503d55a6c0SMark Murray 4513d55a6c0SMark Murray /* XXX wipe the mem as well */ 4523d55a6c0SMark Murray pass = NULL; 4533d55a6c0SMark Murray new_pass = NULL; 4543d55a6c0SMark Murray } 4553d55a6c0SMark Murray else { 4563d55a6c0SMark Murray /* Very bad juju */ 4573d55a6c0SMark Murray retval = PAM_ABORT; 4583d55a6c0SMark Murray PAM_LOG("Illegal 'flags'"); 4593d55a6c0SMark Murray } 4603d55a6c0SMark Murray 4613d55a6c0SMark Murray PAM_RETURN(retval); 4623d55a6c0SMark Murray } 4633d55a6c0SMark Murray 4643d55a6c0SMark Murray /* Mostly stolen from passwd(1)'s local_passwd.c - markm */ 4653d55a6c0SMark Murray 4663d55a6c0SMark Murray static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ 4673d55a6c0SMark Murray "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 4683d55a6c0SMark Murray 4693d55a6c0SMark Murray static void 4703d55a6c0SMark Murray to64(char *s, long v, int n) 4713d55a6c0SMark Murray { 4723d55a6c0SMark Murray while (--n >= 0) { 4733d55a6c0SMark Murray *s++ = itoa64[v&0x3f]; 4743d55a6c0SMark Murray v >>= 6; 4753d55a6c0SMark Murray } 4763d55a6c0SMark Murray } 4773d55a6c0SMark Murray 4783d55a6c0SMark Murray static int 4793d55a6c0SMark Murray local_passwd(const char *user, const char *pass) 4803d55a6c0SMark Murray { 4813d55a6c0SMark Murray login_cap_t * lc; 4823d55a6c0SMark Murray struct passwd *pwd; 4833d55a6c0SMark Murray struct timeval tv; 4843d55a6c0SMark Murray int pfd, tfd; 4853d55a6c0SMark Murray char *crypt_type, salt[32]; 4863d55a6c0SMark Murray 4873d55a6c0SMark Murray pwd = getpwnam(user); 4883d55a6c0SMark Murray if (pwd == NULL) 4893d55a6c0SMark Murray return(PAM_ABORT); /* Really bad things */ 4903d55a6c0SMark Murray 4913d55a6c0SMark Murray #ifdef YP 4923d55a6c0SMark Murray pwd = (struct passwd *)&local_password; 4933d55a6c0SMark Murray #endif 4943d55a6c0SMark Murray pw_init(); 4953d55a6c0SMark Murray 4963d55a6c0SMark Murray pwd->pw_change = 0; 4973d55a6c0SMark Murray lc = login_getclass(NULL); 4983d55a6c0SMark Murray crypt_type = login_getcapstr(lc, "passwd_format", 4993d55a6c0SMark Murray PASSWORD_HASH, PASSWORD_HASH); 5003d55a6c0SMark Murray if (login_setcryptfmt(lc, crypt_type, NULL) == NULL) 5013d55a6c0SMark Murray syslog(LOG_ERR, "cannot set password cipher"); 5023d55a6c0SMark Murray login_close(lc); 5033d55a6c0SMark Murray /* Salt suitable for anything */ 5043d55a6c0SMark Murray srandomdev(); 5053d55a6c0SMark Murray gettimeofday(&tv, 0); 5063d55a6c0SMark Murray to64(&salt[0], random(), 3); 5073d55a6c0SMark Murray to64(&salt[3], tv.tv_usec, 3); 5083d55a6c0SMark Murray to64(&salt[6], tv.tv_sec, 2); 5093d55a6c0SMark Murray to64(&salt[8], random(), 5); 5103d55a6c0SMark Murray to64(&salt[13], random(), 5); 5113d55a6c0SMark Murray to64(&salt[17], random(), 5); 5123d55a6c0SMark Murray to64(&salt[22], random(), 5); 5133d55a6c0SMark Murray salt[27] = '\0'; 5143d55a6c0SMark Murray 5153d55a6c0SMark Murray pwd->pw_passwd = crypt(pass, salt); 5163d55a6c0SMark Murray 5173d55a6c0SMark Murray pfd = pw_lock(); 5183d55a6c0SMark Murray tfd = pw_tmp(); 5193d55a6c0SMark Murray pw_copy(pfd, tfd, pwd); 5203d55a6c0SMark Murray 5213d55a6c0SMark Murray if (!pw_mkdb((char *)user)) 5223d55a6c0SMark Murray pw_error((char *)NULL, 0, 1); 5233d55a6c0SMark Murray 5243d55a6c0SMark Murray return PAM_SUCCESS; 5253d55a6c0SMark Murray } 5263d55a6c0SMark Murray 5273d55a6c0SMark Murray #ifdef YP 5283d55a6c0SMark Murray /* Stolen from src/usr.bin/passwd/yp_passwd.c, carrying copyrights of: 5293d55a6c0SMark Murray * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca> 5303d55a6c0SMark Murray * Copyright (c) 1994 Olaf Kirch <okir@monad.swb.de> 5313d55a6c0SMark Murray * Copyright (c) 1995 Bill Paul <wpaul@ctr.columbia.edu> 5323d55a6c0SMark Murray */ 5333d55a6c0SMark Murray int 5343d55a6c0SMark Murray yp_passwd(const char *user, const char *pass) 5353d55a6c0SMark Murray { 5363d55a6c0SMark Murray struct master_yppasswd master_yppasswd; 5373d55a6c0SMark Murray struct passwd *pwd; 5383d55a6c0SMark Murray struct rpc_err err; 5393d55a6c0SMark Murray struct timeval tv; 5403d55a6c0SMark Murray struct yppasswd yppasswd; 5413d55a6c0SMark Murray CLIENT *clnt; 5423d55a6c0SMark Murray login_cap_t *lc; 5433d55a6c0SMark Murray int *status; 5443d55a6c0SMark Murray uid_t uid; 5453d55a6c0SMark Murray char *master, *sockname = YP_SOCKNAME, salt[32]; 5463d55a6c0SMark Murray 5473d55a6c0SMark Murray _use_yp = 1; 5483d55a6c0SMark Murray 5493d55a6c0SMark Murray uid = getuid(); 5503d55a6c0SMark Murray 5513d55a6c0SMark Murray master = get_yp_master(1); 5523d55a6c0SMark Murray if (master == NULL) 5533d55a6c0SMark Murray return PAM_ABORT; /* Major disaster */ 5543d55a6c0SMark Murray 5553d55a6c0SMark Murray /* 5563d55a6c0SMark Murray * It is presumed that by the time we get here, use_yp() 5573d55a6c0SMark Murray * has been called and that we have verified that the user 5583d55a6c0SMark Murray * actually exists. This being the case, the yp_password 5593d55a6c0SMark Murray * stucture has already been filled in for us. 5603d55a6c0SMark Murray */ 5613d55a6c0SMark Murray 5623d55a6c0SMark Murray /* Use the correct password */ 5633d55a6c0SMark Murray pwd = (struct passwd *)&yp_password; 5643d55a6c0SMark Murray 5653d55a6c0SMark Murray pwd->pw_change = 0; 5663d55a6c0SMark Murray 5673d55a6c0SMark Murray /* Initialize password information */ 5683d55a6c0SMark Murray if (suser_override) { 5693d55a6c0SMark Murray master_yppasswd.newpw.pw_passwd = strdup(pwd->pw_passwd); 5703d55a6c0SMark Murray master_yppasswd.newpw.pw_name = strdup(pwd->pw_name); 5713d55a6c0SMark Murray master_yppasswd.newpw.pw_uid = pwd->pw_uid; 5723d55a6c0SMark Murray master_yppasswd.newpw.pw_gid = pwd->pw_gid; 5733d55a6c0SMark Murray master_yppasswd.newpw.pw_expire = pwd->pw_expire; 5743d55a6c0SMark Murray master_yppasswd.newpw.pw_change = pwd->pw_change; 5753d55a6c0SMark Murray master_yppasswd.newpw.pw_fields = pwd->pw_fields; 5763d55a6c0SMark Murray master_yppasswd.newpw.pw_gecos = strdup(pwd->pw_gecos); 5773d55a6c0SMark Murray master_yppasswd.newpw.pw_dir = strdup(pwd->pw_dir); 5783d55a6c0SMark Murray master_yppasswd.newpw.pw_shell = strdup(pwd->pw_shell); 5793d55a6c0SMark Murray master_yppasswd.newpw.pw_class = pwd->pw_class != NULL ? 5803d55a6c0SMark Murray strdup(pwd->pw_class) : ""; 5813d55a6c0SMark Murray master_yppasswd.oldpass = ""; 5823d55a6c0SMark Murray master_yppasswd.domain = yp_domain; 5833d55a6c0SMark Murray } else { 5843d55a6c0SMark Murray yppasswd.newpw.pw_passwd = strdup(pwd->pw_passwd); 5853d55a6c0SMark Murray yppasswd.newpw.pw_name = strdup(pwd->pw_name); 5863d55a6c0SMark Murray yppasswd.newpw.pw_uid = pwd->pw_uid; 5873d55a6c0SMark Murray yppasswd.newpw.pw_gid = pwd->pw_gid; 5883d55a6c0SMark Murray yppasswd.newpw.pw_gecos = strdup(pwd->pw_gecos); 5893d55a6c0SMark Murray yppasswd.newpw.pw_dir = strdup(pwd->pw_dir); 5903d55a6c0SMark Murray yppasswd.newpw.pw_shell = strdup(pwd->pw_shell); 5913d55a6c0SMark Murray yppasswd.oldpass = ""; 5923d55a6c0SMark Murray } 5933d55a6c0SMark Murray 5943d55a6c0SMark Murray if (login_setcryptfmt(lc, "md5", NULL) == NULL) 5953d55a6c0SMark Murray syslog(LOG_ERR, "cannot set password cipher"); 5963d55a6c0SMark Murray login_close(lc); 5973d55a6c0SMark Murray /* Salt suitable for anything */ 5983d55a6c0SMark Murray srandomdev(); 5993d55a6c0SMark Murray gettimeofday(&tv, 0); 6003d55a6c0SMark Murray to64(&salt[0], random(), 3); 6013d55a6c0SMark Murray to64(&salt[3], tv.tv_usec, 3); 6023d55a6c0SMark Murray to64(&salt[6], tv.tv_sec, 2); 6033d55a6c0SMark Murray to64(&salt[8], random(), 5); 6043d55a6c0SMark Murray to64(&salt[13], random(), 5); 6053d55a6c0SMark Murray to64(&salt[17], random(), 5); 6063d55a6c0SMark Murray to64(&salt[22], random(), 5); 6073d55a6c0SMark Murray salt[27] = '\0'; 6083d55a6c0SMark Murray 6093d55a6c0SMark Murray if (suser_override) 6103d55a6c0SMark Murray master_yppasswd.newpw.pw_passwd = crypt(pass, salt); 6113d55a6c0SMark Murray else 6123d55a6c0SMark Murray yppasswd.newpw.pw_passwd = crypt(pass, salt); 6133d55a6c0SMark Murray 6143d55a6c0SMark Murray if (suser_override) { 6153d55a6c0SMark Murray if ((clnt = clnt_create(sockname, MASTER_YPPASSWDPROG, 6163d55a6c0SMark Murray MASTER_YPPASSWDVERS, "unix")) == NULL) { 6173d55a6c0SMark Murray syslog(LOG_ERR, 6183d55a6c0SMark Murray "Cannot contact rpc.yppasswdd on host %s: %s", 6193d55a6c0SMark Murray master, clnt_spcreateerror("")); 6203d55a6c0SMark Murray return PAM_ABORT; 6213d55a6c0SMark Murray } 6223d55a6c0SMark Murray } 6233d55a6c0SMark Murray else { 6243d55a6c0SMark Murray if ((clnt = clnt_create(master, YPPASSWDPROG, 6253d55a6c0SMark Murray YPPASSWDVERS, "udp")) == NULL) { 6263d55a6c0SMark Murray syslog(LOG_ERR, 6273d55a6c0SMark Murray "Cannot contact rpc.yppasswdd on host %s: %s", 6283d55a6c0SMark Murray master, clnt_spcreateerror("")); 6293d55a6c0SMark Murray return PAM_ABORT; 6303d55a6c0SMark Murray } 6313d55a6c0SMark Murray } 6323d55a6c0SMark Murray /* 6333d55a6c0SMark Murray * The yppasswd.x file said `unix authentication required', 6343d55a6c0SMark Murray * so I added it. This is the only reason it is in here. 6353d55a6c0SMark Murray * My yppasswdd doesn't use it, but maybe some others out there 6363d55a6c0SMark Murray * do. --okir 6373d55a6c0SMark Murray */ 6383d55a6c0SMark Murray clnt->cl_auth = authunix_create_default(); 6393d55a6c0SMark Murray 6403d55a6c0SMark Murray if (suser_override) 6413d55a6c0SMark Murray status = yppasswdproc_update_master_1(&master_yppasswd, clnt); 6423d55a6c0SMark Murray else 6433d55a6c0SMark Murray status = yppasswdproc_update_1(&yppasswd, clnt); 6443d55a6c0SMark Murray 6453d55a6c0SMark Murray clnt_geterr(clnt, &err); 6463d55a6c0SMark Murray 6473d55a6c0SMark Murray auth_destroy(clnt->cl_auth); 6483d55a6c0SMark Murray clnt_destroy(clnt); 6493d55a6c0SMark Murray 6503d55a6c0SMark Murray if (err.re_status != RPC_SUCCESS || status == NULL || *status) 6513d55a6c0SMark Murray return PAM_ABORT; 6523d55a6c0SMark Murray 6533d55a6c0SMark Murray return (err.re_status || status == NULL || *status) 6543d55a6c0SMark Murray ? PAM_ABORT : PAM_SUCCESS; 6553d55a6c0SMark Murray } 6563d55a6c0SMark Murray #endif /* YP */ 6573d55a6c0SMark Murray 6589294327dSJohn Polstra PAM_MODULE_ENTRY("pam_unix"); 659