1*242be47eSzrj /*- 2*242be47eSzrj * Copyright 1998 Juniper Networks, Inc. 3*242be47eSzrj * All rights reserved. 4*242be47eSzrj * Copyright (c) 2002-2003 Networks Associates Technology, Inc. 5*242be47eSzrj * All rights reserved. 6*242be47eSzrj * 7*242be47eSzrj * Portions of this software was developed for the FreeBSD Project by 8*242be47eSzrj * ThinkSec AS and NAI Labs, the Security Research Division of Network 9*242be47eSzrj * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 10*242be47eSzrj * ("CBOSS"), as part of the DARPA CHATS research program. 11*242be47eSzrj * 12*242be47eSzrj * Redistribution and use in source and binary forms, with or without 13*242be47eSzrj * modification, are permitted provided that the following conditions 14*242be47eSzrj * are met: 15*242be47eSzrj * 1. Redistributions of source code must retain the above copyright 16*242be47eSzrj * notice, this list of conditions and the following disclaimer. 17*242be47eSzrj * 2. Redistributions in binary form must reproduce the above copyright 18*242be47eSzrj * notice, this list of conditions and the following disclaimer in the 19*242be47eSzrj * documentation and/or other materials provided with the distribution. 20*242be47eSzrj * 3. The name of the author may not be used to endorse or promote 21*242be47eSzrj * products derived from this software without specific prior written 22*242be47eSzrj * permission. 23*242be47eSzrj * 24*242be47eSzrj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25*242be47eSzrj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26*242be47eSzrj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27*242be47eSzrj * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28*242be47eSzrj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29*242be47eSzrj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30*242be47eSzrj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31*242be47eSzrj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32*242be47eSzrj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33*242be47eSzrj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34*242be47eSzrj * SUCH DAMAGE. 35*242be47eSzrj * 36*242be47eSzrj * $FreeBSD: src/lib/libpam/modules/pam_unix/pam_unix.c,v 1.56 2011/11/05 10:00:29 ed Exp $ 37*242be47eSzrj */ 38*242be47eSzrj 39*242be47eSzrj #include <sys/param.h> 40*242be47eSzrj #include <sys/socket.h> 41*242be47eSzrj #include <sys/time.h> 42*242be47eSzrj #include <netinet/in.h> 43*242be47eSzrj #include <arpa/inet.h> 44*242be47eSzrj 45*242be47eSzrj #include <login_cap.h> 46*242be47eSzrj #include <netdb.h> 47*242be47eSzrj #include <pwd.h> 48*242be47eSzrj #include <stdlib.h> 49*242be47eSzrj #include <string.h> 50*242be47eSzrj #include <stdio.h> 51*242be47eSzrj #include <syslog.h> 52*242be47eSzrj #include <time.h> 53*242be47eSzrj #include <unistd.h> 54*242be47eSzrj 55*242be47eSzrj #include <libutil.h> 56*242be47eSzrj 57*242be47eSzrj #ifdef YP 58*242be47eSzrj #include <ypclnt.h> 59*242be47eSzrj #endif 60*242be47eSzrj 61*242be47eSzrj #define PAM_SM_AUTH 62*242be47eSzrj #define PAM_SM_ACCOUNT 63*242be47eSzrj #define PAM_SM_PASSWORD 64*242be47eSzrj 65*242be47eSzrj #include <security/pam_appl.h> 66*242be47eSzrj #include <security/pam_modules.h> 67*242be47eSzrj #include <security/pam_mod_misc.h> 68*242be47eSzrj 69*242be47eSzrj #define PASSWORD_HASH "sha512" 70*242be47eSzrj #define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */ 71*242be47eSzrj #define SALTSIZE 32 72*242be47eSzrj 73*242be47eSzrj #define LOCKED_PREFIX "*LOCKED*" 74*242be47eSzrj #define LOCKED_PREFIX_LEN (sizeof(LOCKED_PREFIX) - 1) 75*242be47eSzrj 76*242be47eSzrj static void makesalt(char []); 77*242be47eSzrj 78*242be47eSzrj static char password_hash[] = PASSWORD_HASH; 79*242be47eSzrj 80*242be47eSzrj #define PAM_OPT_LOCAL_PASS "local_pass" 81*242be47eSzrj #define PAM_OPT_NIS_PASS "nis_pass" 82*242be47eSzrj 83*242be47eSzrj /* 84*242be47eSzrj * authentication management 85*242be47eSzrj */ 86*242be47eSzrj PAM_EXTERN int 87*242be47eSzrj pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, 88*242be47eSzrj int argc __unused, const char *argv[] __unused) 89*242be47eSzrj { 90*242be47eSzrj login_cap_t *lc; 91*242be47eSzrj struct passwd *pwd; 92*242be47eSzrj int retval; 93*242be47eSzrj const char *pass, *user, *realpw, *prompt; 94*242be47eSzrj char *cryptpw; 95*242be47eSzrj 96*242be47eSzrj if (openpam_get_option(pamh, PAM_OPT_AUTH_AS_SELF)) { 97*242be47eSzrj pwd = getpwnam(getlogin()); 98*242be47eSzrj } else { 99*242be47eSzrj retval = pam_get_user(pamh, &user, NULL); 100*242be47eSzrj if (retval != PAM_SUCCESS) 101*242be47eSzrj return (retval); 102*242be47eSzrj pwd = getpwnam(user); 103*242be47eSzrj } 104*242be47eSzrj 105*242be47eSzrj PAM_LOG("Got user: %s", user); 106*242be47eSzrj 107*242be47eSzrj if (pwd != NULL) { 108*242be47eSzrj PAM_LOG("Doing real authentication"); 109*242be47eSzrj realpw = pwd->pw_passwd; 110*242be47eSzrj if (realpw[0] == '\0') { 111*242be47eSzrj if (!(flags & PAM_DISALLOW_NULL_AUTHTOK) && 112*242be47eSzrj openpam_get_option(pamh, PAM_OPT_NULLOK)) 113*242be47eSzrj return (PAM_SUCCESS); 114*242be47eSzrj realpw = "*"; 115*242be47eSzrj } 116*242be47eSzrj lc = login_getpwclass(pwd); 117*242be47eSzrj } else { 118*242be47eSzrj PAM_LOG("Doing dummy authentication"); 119*242be47eSzrj realpw = "*"; 120*242be47eSzrj lc = login_getclass(NULL); 121*242be47eSzrj } 122*242be47eSzrj prompt = login_getcapstr(lc, "passwd_prompt", NULL, NULL); 123*242be47eSzrj retval = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, prompt); 124*242be47eSzrj login_close(lc); 125*242be47eSzrj if (retval != PAM_SUCCESS) 126*242be47eSzrj return (retval); 127*242be47eSzrj PAM_LOG("Got password"); 128*242be47eSzrj cryptpw = crypt(pass, realpw); 129*242be47eSzrj if (cryptpw != NULL && strcmp(cryptpw, realpw) == 0) 130*242be47eSzrj return (PAM_SUCCESS); 131*242be47eSzrj 132*242be47eSzrj PAM_VERBOSE_ERROR("UNIX authentication refused"); 133*242be47eSzrj return (PAM_AUTH_ERR); 134*242be47eSzrj } 135*242be47eSzrj 136*242be47eSzrj PAM_EXTERN int 137*242be47eSzrj pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused, 138*242be47eSzrj int argc __unused, const char *argv[] __unused) 139*242be47eSzrj { 140*242be47eSzrj 141*242be47eSzrj return (PAM_SUCCESS); 142*242be47eSzrj } 143*242be47eSzrj 144*242be47eSzrj /* 145*242be47eSzrj * account management 146*242be47eSzrj */ 147*242be47eSzrj PAM_EXTERN int 148*242be47eSzrj pam_sm_acct_mgmt(pam_handle_t *pamh, int flags __unused, 149*242be47eSzrj int argc __unused, const char *argv[] __unused) 150*242be47eSzrj { 151*242be47eSzrj struct addrinfo hints, *res; 152*242be47eSzrj struct passwd *pwd; 153*242be47eSzrj struct timeval tp; 154*242be47eSzrj login_cap_t *lc; 155*242be47eSzrj time_t warntime; 156*242be47eSzrj int retval; 157*242be47eSzrj const char *user; 158*242be47eSzrj const void *rhost, *tty; 159*242be47eSzrj char rhostip[MAXHOSTNAMELEN] = ""; 160*242be47eSzrj 161*242be47eSzrj retval = pam_get_user(pamh, &user, NULL); 162*242be47eSzrj if (retval != PAM_SUCCESS) 163*242be47eSzrj return (retval); 164*242be47eSzrj 165*242be47eSzrj if (user == NULL || (pwd = getpwnam(user)) == NULL) 166*242be47eSzrj return (PAM_SERVICE_ERR); 167*242be47eSzrj 168*242be47eSzrj PAM_LOG("Got user: %s", user); 169*242be47eSzrj 170*242be47eSzrj retval = pam_get_item(pamh, PAM_RHOST, &rhost); 171*242be47eSzrj if (retval != PAM_SUCCESS) 172*242be47eSzrj return (retval); 173*242be47eSzrj 174*242be47eSzrj retval = pam_get_item(pamh, PAM_TTY, &tty); 175*242be47eSzrj if (retval != PAM_SUCCESS) 176*242be47eSzrj return (retval); 177*242be47eSzrj 178*242be47eSzrj if (*pwd->pw_passwd == '\0' && 179*242be47eSzrj (flags & PAM_DISALLOW_NULL_AUTHTOK) != 0) 180*242be47eSzrj return (PAM_NEW_AUTHTOK_REQD); 181*242be47eSzrj 182*242be47eSzrj if (strncmp(pwd->pw_passwd, LOCKED_PREFIX, LOCKED_PREFIX_LEN) == 0) 183*242be47eSzrj return (PAM_AUTH_ERR); 184*242be47eSzrj 185*242be47eSzrj lc = login_getpwclass(pwd); 186*242be47eSzrj if (lc == NULL) { 187*242be47eSzrj PAM_LOG("Unable to get login class for user %s", user); 188*242be47eSzrj return (PAM_SERVICE_ERR); 189*242be47eSzrj } 190*242be47eSzrj 191*242be47eSzrj PAM_LOG("Got login_cap"); 192*242be47eSzrj 193*242be47eSzrj if (pwd->pw_change || pwd->pw_expire) 194*242be47eSzrj gettimeofday(&tp, NULL); 195*242be47eSzrj 196*242be47eSzrj /* 197*242be47eSzrj * Check pw_expire before pw_change - no point in letting the 198*242be47eSzrj * user change the password on an expired account. 199*242be47eSzrj */ 200*242be47eSzrj 201*242be47eSzrj if (pwd->pw_expire) { 202*242be47eSzrj warntime = login_getcaptime(lc, "warnexpire", 203*242be47eSzrj DEFAULT_WARN, DEFAULT_WARN); 204*242be47eSzrj if (tp.tv_sec >= pwd->pw_expire) { 205*242be47eSzrj login_close(lc); 206*242be47eSzrj return (PAM_ACCT_EXPIRED); 207*242be47eSzrj } else if (pwd->pw_expire - tp.tv_sec < warntime && 208*242be47eSzrj (flags & PAM_SILENT) == 0) { 209*242be47eSzrj pam_error(pamh, "Warning: your account expires on %s", 210*242be47eSzrj ctime(&pwd->pw_expire)); 211*242be47eSzrj } 212*242be47eSzrj } 213*242be47eSzrj 214*242be47eSzrj retval = PAM_SUCCESS; 215*242be47eSzrj if (pwd->pw_change) { 216*242be47eSzrj warntime = login_getcaptime(lc, "warnpassword", 217*242be47eSzrj DEFAULT_WARN, DEFAULT_WARN); 218*242be47eSzrj if (tp.tv_sec >= pwd->pw_change) { 219*242be47eSzrj retval = PAM_NEW_AUTHTOK_REQD; 220*242be47eSzrj } else if (pwd->pw_change - tp.tv_sec < warntime && 221*242be47eSzrj (flags & PAM_SILENT) == 0) { 222*242be47eSzrj pam_error(pamh, "Warning: your password expires on %s", 223*242be47eSzrj ctime(&pwd->pw_change)); 224*242be47eSzrj } 225*242be47eSzrj } 226*242be47eSzrj 227*242be47eSzrj /* 228*242be47eSzrj * From here on, we must leave retval untouched (unless we 229*242be47eSzrj * know we're going to fail), because we need to remember 230*242be47eSzrj * whether we're supposed to return PAM_SUCCESS or 231*242be47eSzrj * PAM_NEW_AUTHTOK_REQD. 232*242be47eSzrj */ 233*242be47eSzrj 234*242be47eSzrj if (rhost && *(const char *)rhost != '\0') { 235*242be47eSzrj memset(&hints, 0, sizeof(hints)); 236*242be47eSzrj hints.ai_family = AF_UNSPEC; 237*242be47eSzrj if (getaddrinfo(rhost, NULL, &hints, &res) == 0) { 238*242be47eSzrj getnameinfo(res->ai_addr, res->ai_addrlen, 239*242be47eSzrj rhostip, sizeof(rhostip), NULL, 0, 240*242be47eSzrj NI_NUMERICHOST); 241*242be47eSzrj } 242*242be47eSzrj if (res != NULL) 243*242be47eSzrj freeaddrinfo(res); 244*242be47eSzrj } 245*242be47eSzrj 246*242be47eSzrj /* 247*242be47eSzrj * Check host / tty / time-of-day restrictions 248*242be47eSzrj */ 249*242be47eSzrj 250*242be47eSzrj if (!auth_hostok(lc, rhost, rhostip) || 251*242be47eSzrj !auth_ttyok(lc, tty) || 252*242be47eSzrj !auth_timeok(lc, time(NULL))) 253*242be47eSzrj retval = PAM_AUTH_ERR; 254*242be47eSzrj 255*242be47eSzrj login_close(lc); 256*242be47eSzrj 257*242be47eSzrj return (retval); 258*242be47eSzrj } 259*242be47eSzrj 260*242be47eSzrj /* 261*242be47eSzrj * password management 262*242be47eSzrj * 263*242be47eSzrj * standard Unix and NIS password changing 264*242be47eSzrj */ 265*242be47eSzrj PAM_EXTERN int 266*242be47eSzrj pam_sm_chauthtok(pam_handle_t *pamh, int flags, 267*242be47eSzrj int argc __unused, const char *argv[] __unused) 268*242be47eSzrj { 269*242be47eSzrj #ifdef YP 270*242be47eSzrj struct ypclnt *ypclnt; 271*242be47eSzrj const void *yp_domain, *yp_server; 272*242be47eSzrj #endif 273*242be47eSzrj char salt[SALTSIZE + 1]; 274*242be47eSzrj login_cap_t *lc; 275*242be47eSzrj struct passwd *pwd, *old_pwd; 276*242be47eSzrj const char *user, *old_pass, *new_pass; 277*242be47eSzrj char *encrypted; 278*242be47eSzrj time_t passwordtime; 279*242be47eSzrj int pfd, tfd, retval; 280*242be47eSzrj 281*242be47eSzrj if (openpam_get_option(pamh, PAM_OPT_AUTH_AS_SELF)) 282*242be47eSzrj pwd = getpwnam(getlogin()); 283*242be47eSzrj else { 284*242be47eSzrj retval = pam_get_user(pamh, &user, NULL); 285*242be47eSzrj if (retval != PAM_SUCCESS) 286*242be47eSzrj return (retval); 287*242be47eSzrj pwd = getpwnam(user); 288*242be47eSzrj } 289*242be47eSzrj 290*242be47eSzrj if (pwd == NULL) 291*242be47eSzrj return (PAM_AUTHTOK_RECOVERY_ERR); 292*242be47eSzrj 293*242be47eSzrj PAM_LOG("Got user: %s", user); 294*242be47eSzrj 295*242be47eSzrj if (flags & PAM_PRELIM_CHECK) { 296*242be47eSzrj 297*242be47eSzrj PAM_LOG("PRELIM round"); 298*242be47eSzrj 299*242be47eSzrj if (getuid() == 0 && 300*242be47eSzrj (pwd->pw_fields & _PWF_SOURCE) == _PWF_FILES) 301*242be47eSzrj /* root doesn't need the old password */ 302*242be47eSzrj return (pam_set_item(pamh, PAM_OLDAUTHTOK, "")); 303*242be47eSzrj #ifdef YP 304*242be47eSzrj if (getuid() == 0 && 305*242be47eSzrj (pwd->pw_fields & _PWF_SOURCE) == _PWF_NIS) { 306*242be47eSzrj 307*242be47eSzrj yp_domain = yp_server = NULL; 308*242be47eSzrj pam_get_data(pamh, "yp_domain", &yp_domain); 309*242be47eSzrj pam_get_data(pamh, "yp_server", &yp_server); 310*242be47eSzrj 311*242be47eSzrj ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_server); 312*242be47eSzrj if (ypclnt == NULL) 313*242be47eSzrj return (PAM_BUF_ERR); 314*242be47eSzrj 315*242be47eSzrj if (ypclnt_connect(ypclnt) == -1) { 316*242be47eSzrj ypclnt_free(ypclnt); 317*242be47eSzrj return (PAM_SERVICE_ERR); 318*242be47eSzrj } 319*242be47eSzrj 320*242be47eSzrj retval = ypclnt_havepasswdd(ypclnt); 321*242be47eSzrj ypclnt_free(ypclnt); 322*242be47eSzrj if (retval == 1) 323*242be47eSzrj return (pam_set_item(pamh, PAM_OLDAUTHTOK, "")); 324*242be47eSzrj else if (retval == -1) 325*242be47eSzrj return (PAM_SERVICE_ERR); 326*242be47eSzrj } 327*242be47eSzrj #endif 328*242be47eSzrj if (pwd->pw_passwd[0] == '\0' 329*242be47eSzrj && openpam_get_option(pamh, PAM_OPT_NULLOK)) { 330*242be47eSzrj /* 331*242be47eSzrj * No password case. XXX Are we giving too much away 332*242be47eSzrj * by not prompting for a password? 333*242be47eSzrj * XXX check PAM_DISALLOW_NULL_AUTHTOK 334*242be47eSzrj */ 335*242be47eSzrj old_pass = ""; 336*242be47eSzrj } else { 337*242be47eSzrj retval = pam_get_authtok(pamh, 338*242be47eSzrj PAM_OLDAUTHTOK, &old_pass, NULL); 339*242be47eSzrj if (retval != PAM_SUCCESS) 340*242be47eSzrj return (retval); 341*242be47eSzrj } 342*242be47eSzrj PAM_LOG("Got old password"); 343*242be47eSzrj /* always encrypt first */ 344*242be47eSzrj encrypted = crypt(old_pass, pwd->pw_passwd); 345*242be47eSzrj if (old_pass[0] == '\0' && 346*242be47eSzrj !openpam_get_option(pamh, PAM_OPT_NULLOK)) 347*242be47eSzrj return (PAM_PERM_DENIED); 348*242be47eSzrj if (encrypted == NULL || strcmp(encrypted, pwd->pw_passwd) != 0) 349*242be47eSzrj return (PAM_PERM_DENIED); 350*242be47eSzrj } 351*242be47eSzrj else if (flags & PAM_UPDATE_AUTHTOK) { 352*242be47eSzrj PAM_LOG("UPDATE round"); 353*242be47eSzrj 354*242be47eSzrj retval = pam_get_authtok(pamh, 355*242be47eSzrj PAM_OLDAUTHTOK, &old_pass, NULL); 356*242be47eSzrj if (retval != PAM_SUCCESS) 357*242be47eSzrj return (retval); 358*242be47eSzrj PAM_LOG("Got old password"); 359*242be47eSzrj 360*242be47eSzrj /* get new password */ 361*242be47eSzrj for (;;) { 362*242be47eSzrj retval = pam_get_authtok(pamh, 363*242be47eSzrj PAM_AUTHTOK, &new_pass, NULL); 364*242be47eSzrj if (retval != PAM_TRY_AGAIN) 365*242be47eSzrj break; 366*242be47eSzrj pam_error(pamh, "Mismatch; try again, EOF to quit."); 367*242be47eSzrj } 368*242be47eSzrj PAM_LOG("Got new password"); 369*242be47eSzrj if (retval != PAM_SUCCESS) { 370*242be47eSzrj PAM_VERBOSE_ERROR("Unable to get new password"); 371*242be47eSzrj return (retval); 372*242be47eSzrj } 373*242be47eSzrj 374*242be47eSzrj if (getuid() != 0 && new_pass[0] == '\0' && 375*242be47eSzrj !openpam_get_option(pamh, PAM_OPT_NULLOK)) 376*242be47eSzrj return (PAM_PERM_DENIED); 377*242be47eSzrj 378*242be47eSzrj if ((old_pwd = pw_dup(pwd)) == NULL) 379*242be47eSzrj return (PAM_BUF_ERR); 380*242be47eSzrj 381*242be47eSzrj lc = login_getclass(pwd->pw_class); 382*242be47eSzrj if (login_setcryptfmt(lc, password_hash, NULL) == NULL) 383*242be47eSzrj openpam_log(PAM_LOG_ERROR, 384*242be47eSzrj "can't set password cipher, relying on default"); 385*242be47eSzrj 386*242be47eSzrj /* set password expiry date */ 387*242be47eSzrj pwd->pw_change = 0; 388*242be47eSzrj passwordtime = login_getcaptime(lc, "passwordtime", 0, 0); 389*242be47eSzrj if (passwordtime > 0) 390*242be47eSzrj pwd->pw_change = time(NULL) + passwordtime; 391*242be47eSzrj 392*242be47eSzrj login_close(lc); 393*242be47eSzrj makesalt(salt); 394*242be47eSzrj pwd->pw_passwd = crypt(new_pass, salt); 395*242be47eSzrj #ifdef YP 396*242be47eSzrj switch (old_pwd->pw_fields & _PWF_SOURCE) { 397*242be47eSzrj case _PWF_FILES: 398*242be47eSzrj #endif 399*242be47eSzrj retval = PAM_SERVICE_ERR; 400*242be47eSzrj if (pw_init(NULL, NULL)) 401*242be47eSzrj openpam_log(PAM_LOG_ERROR, "pw_init() failed"); 402*242be47eSzrj else if ((pfd = pw_lock()) == -1) 403*242be47eSzrj openpam_log(PAM_LOG_ERROR, "pw_lock() failed"); 404*242be47eSzrj else if ((tfd = pw_tmp(-1)) == -1) 405*242be47eSzrj openpam_log(PAM_LOG_ERROR, "pw_tmp() failed"); 406*242be47eSzrj else if (pw_copy(pfd, tfd, pwd, old_pwd) == -1) 407*242be47eSzrj openpam_log(PAM_LOG_ERROR, "pw_copy() failed"); 408*242be47eSzrj else if (pw_mkdb(pwd->pw_name) == -1) 409*242be47eSzrj openpam_log(PAM_LOG_ERROR, "pw_mkdb() failed"); 410*242be47eSzrj else 411*242be47eSzrj retval = PAM_SUCCESS; 412*242be47eSzrj pw_fini(); 413*242be47eSzrj #ifdef YP 414*242be47eSzrj break; 415*242be47eSzrj case _PWF_NIS: 416*242be47eSzrj yp_domain = yp_server = NULL; 417*242be47eSzrj pam_get_data(pamh, "yp_domain", &yp_domain); 418*242be47eSzrj pam_get_data(pamh, "yp_server", &yp_server); 419*242be47eSzrj ypclnt = ypclnt_new(yp_domain, 420*242be47eSzrj "passwd.byname", yp_server); 421*242be47eSzrj if (ypclnt == NULL) { 422*242be47eSzrj retval = PAM_BUF_ERR; 423*242be47eSzrj } else if (ypclnt_connect(ypclnt) == -1 || 424*242be47eSzrj ypclnt_passwd(ypclnt, pwd, old_pass) == -1) { 425*242be47eSzrj openpam_log(PAM_LOG_ERROR, "%s", ypclnt->error); 426*242be47eSzrj retval = PAM_SERVICE_ERR; 427*242be47eSzrj } else { 428*242be47eSzrj retval = PAM_SUCCESS; 429*242be47eSzrj } 430*242be47eSzrj ypclnt_free(ypclnt); 431*242be47eSzrj break; 432*242be47eSzrj default: 433*242be47eSzrj openpam_log(PAM_LOG_ERROR, "unsupported source 0x%x", 434*242be47eSzrj pwd->pw_fields & _PWF_SOURCE); 435*242be47eSzrj retval = PAM_SERVICE_ERR; 436*242be47eSzrj } 437*242be47eSzrj #endif 438*242be47eSzrj free(old_pwd); 439*242be47eSzrj } 440*242be47eSzrj else { 441*242be47eSzrj /* Very bad juju */ 442*242be47eSzrj retval = PAM_ABORT; 443*242be47eSzrj PAM_LOG("Illegal 'flags'"); 444*242be47eSzrj } 445*242be47eSzrj 446*242be47eSzrj return (retval); 447*242be47eSzrj } 448*242be47eSzrj 449*242be47eSzrj /* Mostly stolen from passwd(1)'s local_passwd.c - markm */ 450*242be47eSzrj 451*242be47eSzrj static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ 452*242be47eSzrj "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 453*242be47eSzrj 454*242be47eSzrj static void 455*242be47eSzrj to64(char *s, long v, int n) 456*242be47eSzrj { 457*242be47eSzrj while (--n >= 0) { 458*242be47eSzrj *s++ = itoa64[v&0x3f]; 459*242be47eSzrj v >>= 6; 460*242be47eSzrj } 461*242be47eSzrj } 462*242be47eSzrj 463*242be47eSzrj /* Salt suitable for traditional DES and MD5 */ 464*242be47eSzrj static void 465*242be47eSzrj makesalt(char salt[SALTSIZE + 1]) 466*242be47eSzrj { 467*242be47eSzrj int i; 468*242be47eSzrj 469*242be47eSzrj /* These are not really random numbers, they are just 470*242be47eSzrj * numbers that change to thwart construction of a 471*242be47eSzrj * dictionary. 472*242be47eSzrj */ 473*242be47eSzrj for (i = 0; i < SALTSIZE; i += 4) 474*242be47eSzrj to64(&salt[i], arc4random(), 4); 475*242be47eSzrj salt[SALTSIZE] = '\0'; 476*242be47eSzrj } 477*242be47eSzrj 478*242be47eSzrj PAM_MODULE_ENTRY("pam_unix"); 479