1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <stdlib.h> 30*0Sstevel@tonic-gate #include <syslog.h> 31*0Sstevel@tonic-gate #include <errno.h> 32*0Sstevel@tonic-gate #include <string.h> 33*0Sstevel@tonic-gate #include <rpc/rpc.h> 34*0Sstevel@tonic-gate #include <unistd.h> 35*0Sstevel@tonic-gate #include <assert.h> 36*0Sstevel@tonic-gate #include <stdarg.h> 37*0Sstevel@tonic-gate #include <sys/types.h> 38*0Sstevel@tonic-gate #include <sys/wait.h> 39*0Sstevel@tonic-gate #include <limits.h> 40*0Sstevel@tonic-gate 41*0Sstevel@tonic-gate #include <rpcsvc/nis.h> 42*0Sstevel@tonic-gate #include <rpcsvc/nispasswd.h> 43*0Sstevel@tonic-gate #include <rpcsvc/yppasswd.h> 44*0Sstevel@tonic-gate #include <rpcsvc/ypclnt.h> 45*0Sstevel@tonic-gate #include <rpc/key_prot.h> 46*0Sstevel@tonic-gate #include <rpc/rpc.h> 47*0Sstevel@tonic-gate #include <nfs/nfs.h> 48*0Sstevel@tonic-gate #include <nfs/nfssys.h> 49*0Sstevel@tonic-gate #include <nss_dbdefs.h> 50*0Sstevel@tonic-gate #include <nsswitch.h> 51*0Sstevel@tonic-gate #include <rpcsvc/nis_dhext.h> 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate #include <security/pam_appl.h> 54*0Sstevel@tonic-gate #include <security/pam_modules.h> 55*0Sstevel@tonic-gate #include <security/pam_impl.h> 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate #include <libintl.h> 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate #include <sys/mman.h> 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate #include <passwdutil.h> 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate #include "key_call_uid.h" 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate /* to keep track of codepath */ 66*0Sstevel@tonic-gate #define CODEPATH_PAM_SM_AUTHENTICATE 0 67*0Sstevel@tonic-gate #define CODEPATH_PAM_SM_SETCRED 1 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate #define SUNW_OLDRPCPASS "SUNW-OLD-RPC-PASSWORD" 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate extern int _nfssys(int, void *); 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate /* 74*0Sstevel@tonic-gate * int msg(pamh, ...) 75*0Sstevel@tonic-gate * 76*0Sstevel@tonic-gate * display message to the user 77*0Sstevel@tonic-gate */ 78*0Sstevel@tonic-gate /*PRINTFLIKE2*/ 79*0Sstevel@tonic-gate int 80*0Sstevel@tonic-gate msg(pam_handle_t *pamh, char *fmt, ...) 81*0Sstevel@tonic-gate { 82*0Sstevel@tonic-gate va_list ap; 83*0Sstevel@tonic-gate char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate va_start(ap, fmt); 86*0Sstevel@tonic-gate (void) vsnprintf(messages[0], sizeof (messages[0]), fmt, ap); 87*0Sstevel@tonic-gate va_end(ap); 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate return (__pam_display_msg(pamh, PAM_ERROR_MSG, 1, messages, NULL)); 90*0Sstevel@tonic-gate } 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate /* 94*0Sstevel@tonic-gate * Get the secret key for the given netname, key length, and algorithm 95*0Sstevel@tonic-gate * type and send it to keyserv if the given pw decrypts it. Update the 96*0Sstevel@tonic-gate * following counter args as necessary: get_seckey_cnt, good_pw_cnt, and 97*0Sstevel@tonic-gate * set_seckey_cnt. 98*0Sstevel@tonic-gate * 99*0Sstevel@tonic-gate * Returns 0 on malloc failure, else 1. 100*0Sstevel@tonic-gate */ 101*0Sstevel@tonic-gate static int 102*0Sstevel@tonic-gate get_and_set_seckey( 103*0Sstevel@tonic-gate pam_handle_t *pamh, /* in */ 104*0Sstevel@tonic-gate const char *netname, /* in */ 105*0Sstevel@tonic-gate keylen_t keylen, /* in */ 106*0Sstevel@tonic-gate algtype_t algtype, /* in */ 107*0Sstevel@tonic-gate const char *pw, /* in */ 108*0Sstevel@tonic-gate uid_t uid, /* in */ 109*0Sstevel@tonic-gate gid_t gid, /* in */ 110*0Sstevel@tonic-gate int *get_seckey_cnt, /* out */ 111*0Sstevel@tonic-gate int *good_pw_cnt, /* out */ 112*0Sstevel@tonic-gate int *set_seckey_cnt, /* out */ 113*0Sstevel@tonic-gate int flags, /* in */ 114*0Sstevel@tonic-gate int debug) /* in */ 115*0Sstevel@tonic-gate { 116*0Sstevel@tonic-gate char *skey; 117*0Sstevel@tonic-gate int skeylen; 118*0Sstevel@tonic-gate char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate skeylen = BITS2NIBBLES(keylen) + 1; 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate if ((skey = malloc(skeylen)) == NULL) { 123*0Sstevel@tonic-gate return (0); 124*0Sstevel@tonic-gate } 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate if (getsecretkey_g(netname, keylen, algtype, skey, skeylen, pw)) { 127*0Sstevel@tonic-gate (*get_seckey_cnt)++; 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate if (skey[0]) { 130*0Sstevel@tonic-gate /* password does decrypt secret key */ 131*0Sstevel@tonic-gate (*good_pw_cnt)++; 132*0Sstevel@tonic-gate if (key_setnet_g_uid(netname, skey, keylen, NULL, 0, 133*0Sstevel@tonic-gate algtype, uid, gid) >= 0) { 134*0Sstevel@tonic-gate (*set_seckey_cnt)++; 135*0Sstevel@tonic-gate } else { 136*0Sstevel@tonic-gate if (debug) 137*0Sstevel@tonic-gate syslog(LOG_DEBUG, "pam_dhkeys: " 138*0Sstevel@tonic-gate "get_and_set_seckey: could not " 139*0Sstevel@tonic-gate "set secret key for keytype " 140*0Sstevel@tonic-gate "%d-%d", keylen, algtype); 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate } else { 143*0Sstevel@tonic-gate if (pamh && !(flags & PAM_SILENT)) { 144*0Sstevel@tonic-gate (void) snprintf(messages[0], 145*0Sstevel@tonic-gate sizeof (messages[0]), 146*0Sstevel@tonic-gate dgettext(TEXT_DOMAIN, 147*0Sstevel@tonic-gate "Password does not " 148*0Sstevel@tonic-gate "decrypt secret key (type = %d-%d) " 149*0Sstevel@tonic-gate "for '%s'."), keylen, algtype, netname); 150*0Sstevel@tonic-gate (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, 151*0Sstevel@tonic-gate messages, NULL); 152*0Sstevel@tonic-gate } 153*0Sstevel@tonic-gate } 154*0Sstevel@tonic-gate } else { 155*0Sstevel@tonic-gate if (debug) 156*0Sstevel@tonic-gate syslog(LOG_DEBUG, "pam_dhkeys: get_and_set_seckey: " 157*0Sstevel@tonic-gate "could not get secret key for keytype %d-%d", 158*0Sstevel@tonic-gate keylen, algtype); 159*0Sstevel@tonic-gate } 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate free(skey); 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate return (1); 164*0Sstevel@tonic-gate } 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate /* 167*0Sstevel@tonic-gate * int establish_key(pamh, flags, debug, netname) 168*0Sstevel@tonic-gate * 169*0Sstevel@tonic-gate * This routine established the Secure RPC Credentials for the 170*0Sstevel@tonic-gate * user specified in PAM_USER, using the password in PAM_AUTHTOK. 171*0Sstevel@tonic-gate * 172*0Sstevel@tonic-gate * Because this routine is used for both pam_authenticate *and* 173*0Sstevel@tonic-gate * pam_setcred, we have to be somewhat careful: 174*0Sstevel@tonic-gate * 175*0Sstevel@tonic-gate * - if called from pam_sm_authenticate: 176*0Sstevel@tonic-gate * 1. if we don't need creds (no NIS+ or not tight), we don't 177*0Sstevel@tonic-gate * set them (they will be set by pam_sm_setcred()) and return 178*0Sstevel@tonic-gate * PAM_IGNORE. 179*0Sstevel@tonic-gate * 2. if we do need to set them (passwd == "*NP*"), we try to 180*0Sstevel@tonic-gate * do so. Not having credentials in this case results in 181*0Sstevel@tonic-gate * PAM_AUTH_ERR. 182*0Sstevel@tonic-gate * 183*0Sstevel@tonic-gate * - if called from pam_sm_setcred: 184*0Sstevel@tonic-gate * If we are root (uid == 0), we do nothing and return PAM_IGNORE. 185*0Sstevel@tonic-gate * Otherwise, we try to establish the credentials. 186*0Sstevel@tonic-gate * Not having credentials in this case results in PAM_IGNORE. 187*0Sstevel@tonic-gate * 188*0Sstevel@tonic-gate * For both modi, we return PAM_IGNORE if the creds are established. 189*0Sstevel@tonic-gate * If we fail, we return 190*0Sstevel@tonic-gate * - PAM_AUTH_ERR if the password didn't decrypt the cred 191*0Sstevel@tonic-gate * - PAM_SYSTEM_ERR if the cred's could not be stored. 192*0Sstevel@tonic-gate * 193*0Sstevel@tonic-gate * This routine returns the user's netname in "netname". 194*0Sstevel@tonic-gate * 195*0Sstevel@tonic-gate * All tools--but the PAM stack--currently use getpass() to obtain 196*0Sstevel@tonic-gate * the user's secure RPC password. We must make sure we don't use more than 197*0Sstevel@tonic-gate * the first des_block (eight) characters of whatever is handed down to us. 198*0Sstevel@tonic-gate * Therefore, we use a local variable "short_pass" to hold those 8 char's. 199*0Sstevel@tonic-gate */ 200*0Sstevel@tonic-gate int 201*0Sstevel@tonic-gate establish_key(pam_handle_t *pamh, int flags, int codepath, int debug, 202*0Sstevel@tonic-gate char *netname) 203*0Sstevel@tonic-gate { 204*0Sstevel@tonic-gate char *user; 205*0Sstevel@tonic-gate char *passwd; 206*0Sstevel@tonic-gate char short_pass[sizeof (des_block)+1], *short_passp; 207*0Sstevel@tonic-gate int result; 208*0Sstevel@tonic-gate uid_t uid; 209*0Sstevel@tonic-gate gid_t gid; 210*0Sstevel@tonic-gate int err; 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate struct passwd pw; /* Needed to obtain uid */ 213*0Sstevel@tonic-gate char *scratch; 214*0Sstevel@tonic-gate int scratchlen; 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate int need_cred; /* is not having credentials set a failure? */ 217*0Sstevel@tonic-gate char *repository_name = NULL; /* which repository are we using */ 218*0Sstevel@tonic-gate char *repository_pass = NULL; /* user's password from that rep */ 219*0Sstevel@tonic-gate pwu_repository_t *pwu_rep; 220*0Sstevel@tonic-gate struct pam_repository *auth_rep; 221*0Sstevel@tonic-gate attrlist attr_pw[2]; 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate mechanism_t **mechs; 224*0Sstevel@tonic-gate mechanism_t **mpp; 225*0Sstevel@tonic-gate int get_seckey_cnt = 0; 226*0Sstevel@tonic-gate int set_seckey_cnt = 0; 227*0Sstevel@tonic-gate int good_pw_cnt = 0; 228*0Sstevel@tonic-gate int valid_mech_cnt = 0; 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate (void) pam_get_item(pamh, PAM_USER, (void **)&user); 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate if (user == NULL || *user == '\0') { 233*0Sstevel@tonic-gate if (debug) 234*0Sstevel@tonic-gate syslog(LOG_DEBUG, "pam_dhkeys: user NULL or empty"); 235*0Sstevel@tonic-gate return (PAM_USER_UNKNOWN); 236*0Sstevel@tonic-gate } 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate (void) pam_get_item(pamh, PAM_AUTHTOK, (void **)&passwd); 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate scratchlen = sysconf(_SC_GETPW_R_SIZE_MAX); 241*0Sstevel@tonic-gate if ((scratch = malloc(scratchlen)) == NULL) 242*0Sstevel@tonic-gate return (PAM_BUF_ERR); 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate if (getpwnam_r(user, &pw, scratch, scratchlen) == NULL) { 245*0Sstevel@tonic-gate result = PAM_USER_UNKNOWN; 246*0Sstevel@tonic-gate goto out; 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate uid = pw.pw_uid; 250*0Sstevel@tonic-gate gid = pw.pw_gid; 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate /* 253*0Sstevel@tonic-gate * We don't set credentials when root logs in. 254*0Sstevel@tonic-gate * We do, however, need to set the credentials if the NIS+ permissions 255*0Sstevel@tonic-gate * require so. Thus, we only bail out if we're root and we're 256*0Sstevel@tonic-gate * called from pam_setcred. 257*0Sstevel@tonic-gate */ 258*0Sstevel@tonic-gate if (uid == 0 && codepath == CODEPATH_PAM_SM_SETCRED) { 259*0Sstevel@tonic-gate result = PAM_IGNORE; 260*0Sstevel@tonic-gate goto out; 261*0Sstevel@tonic-gate } 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate /* 264*0Sstevel@tonic-gate * Check to see if we REALLY need to set the credentials, i.e. 265*0Sstevel@tonic-gate * whether not being able to do so is an error or whether we 266*0Sstevel@tonic-gate * can ignore it. 267*0Sstevel@tonic-gate * We need to get the password from the repository that we're 268*0Sstevel@tonic-gate * currently authenticating against. IFF this password equals 269*0Sstevel@tonic-gate * "*NP" *AND* we are authenticating against NIS+, we actually 270*0Sstevel@tonic-gate * do need to set the credentials. In all other cases, we 271*0Sstevel@tonic-gate * can forget about them. 272*0Sstevel@tonic-gate */ 273*0Sstevel@tonic-gate (void) pam_get_item(pamh, PAM_REPOSITORY, (void **)&auth_rep); 274*0Sstevel@tonic-gate if (auth_rep != NULL) { 275*0Sstevel@tonic-gate if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL) 276*0Sstevel@tonic-gate return (PAM_BUF_ERR); 277*0Sstevel@tonic-gate pwu_rep->type = auth_rep->type; 278*0Sstevel@tonic-gate pwu_rep->scope = auth_rep->scope; 279*0Sstevel@tonic-gate pwu_rep->scope_len = auth_rep->scope_len; 280*0Sstevel@tonic-gate } else 281*0Sstevel@tonic-gate pwu_rep = PWU_DEFAULT_REP; 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate attr_pw[0].type = ATTR_PASSWD; attr_pw[0].next = &attr_pw[1]; 284*0Sstevel@tonic-gate attr_pw[1].type = ATTR_REP_NAME; attr_pw[1].next = NULL; 285*0Sstevel@tonic-gate result = __get_authtoken_attr(user, pwu_rep, attr_pw); 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate if (pwu_rep != PWU_DEFAULT_REP) 288*0Sstevel@tonic-gate free(pwu_rep); 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate if (result == PWU_NOT_FOUND) { 291*0Sstevel@tonic-gate if (debug) 292*0Sstevel@tonic-gate syslog(LOG_DEBUG, "pam_dhkeys: user %s not found", 293*0Sstevel@tonic-gate user); 294*0Sstevel@tonic-gate result = PAM_USER_UNKNOWN; 295*0Sstevel@tonic-gate goto out; 296*0Sstevel@tonic-gate } else if (result != PWU_SUCCESS) { 297*0Sstevel@tonic-gate result = PAM_PERM_DENIED; 298*0Sstevel@tonic-gate goto out; 299*0Sstevel@tonic-gate } 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate repository_name = attr_pw[1].data.val_s; 302*0Sstevel@tonic-gate repository_pass = attr_pw[0].data.val_s; 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate need_cred = (strcmp(repository_name, "nisplus") == 0 && 305*0Sstevel@tonic-gate strcmp(repository_pass, "*NP*") == 0); 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate if (codepath == CODEPATH_PAM_SM_AUTHENTICATE && need_cred == 0) { 308*0Sstevel@tonic-gate /* 309*0Sstevel@tonic-gate * No need to set credentials right now. 310*0Sstevel@tonic-gate * Will do so later through pam_sm_setcred() 311*0Sstevel@tonic-gate */ 312*0Sstevel@tonic-gate result = PAM_IGNORE; 313*0Sstevel@tonic-gate goto out; 314*0Sstevel@tonic-gate } 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate if (uid == 0) /* "root", need to create a host-netname */ 317*0Sstevel@tonic-gate err = host2netname(netname, NULL, NULL); 318*0Sstevel@tonic-gate else 319*0Sstevel@tonic-gate err = user2netname(netname, uid, NULL); 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate if (err != 1) { 322*0Sstevel@tonic-gate if (debug) 323*0Sstevel@tonic-gate syslog(LOG_DEBUG, "pam_dhkeys: user2netname failed"); 324*0Sstevel@tonic-gate if (need_cred) { 325*0Sstevel@tonic-gate syslog(LOG_ALERT, "pam_dhkeys: user %s needs " 326*0Sstevel@tonic-gate "Secure RPC Credentials to login.", user); 327*0Sstevel@tonic-gate result = PAM_SERVICE_ERR; 328*0Sstevel@tonic-gate } else 329*0Sstevel@tonic-gate result = PAM_SYSTEM_ERR; 330*0Sstevel@tonic-gate goto out; 331*0Sstevel@tonic-gate } 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate /* passwd can be NULL (no passwd or su as root) */ 334*0Sstevel@tonic-gate if (passwd) { 335*0Sstevel@tonic-gate (void) strlcpy(short_pass, passwd, sizeof (short_pass)); 336*0Sstevel@tonic-gate short_passp = short_pass; 337*0Sstevel@tonic-gate } else 338*0Sstevel@tonic-gate short_passp = NULL; 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate if (mechs = __nis_get_mechanisms(FALSE)) { 341*0Sstevel@tonic-gate 342*0Sstevel@tonic-gate for (mpp = mechs; *mpp; mpp++) { 343*0Sstevel@tonic-gate mechanism_t *mp = *mpp; 344*0Sstevel@tonic-gate 345*0Sstevel@tonic-gate if (AUTH_DES_COMPAT_CHK(mp)) 346*0Sstevel@tonic-gate break; /* fall through to AUTH_DES below */ 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate if (!VALID_MECH_ENTRY(mp)) 349*0Sstevel@tonic-gate continue; 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate if (debug) 352*0Sstevel@tonic-gate syslog(LOG_DEBUG, "pam_dhkeys: trying " 353*0Sstevel@tonic-gate "key type = %d-%d", mp->keylen, 354*0Sstevel@tonic-gate mp->algtype); 355*0Sstevel@tonic-gate valid_mech_cnt++; 356*0Sstevel@tonic-gate if (!get_and_set_seckey(pamh, netname, mp->keylen, 357*0Sstevel@tonic-gate mp->algtype, short_passp, 358*0Sstevel@tonic-gate uid, gid, 359*0Sstevel@tonic-gate &get_seckey_cnt, &good_pw_cnt, 360*0Sstevel@tonic-gate &set_seckey_cnt, flags, 361*0Sstevel@tonic-gate debug)) { 362*0Sstevel@tonic-gate result = PAM_BUF_ERR; 363*0Sstevel@tonic-gate goto out; 364*0Sstevel@tonic-gate } 365*0Sstevel@tonic-gate } 366*0Sstevel@tonic-gate __nis_release_mechanisms(mechs); 367*0Sstevel@tonic-gate /* fall through to AUTH_DES below */ 368*0Sstevel@tonic-gate } else { 369*0Sstevel@tonic-gate /* 370*0Sstevel@tonic-gate * No usable mechs found in NIS+ security cf thus 371*0Sstevel@tonic-gate * fallback to AUTH_DES compat. 372*0Sstevel@tonic-gate */ 373*0Sstevel@tonic-gate if (debug) 374*0Sstevel@tonic-gate syslog(LOG_DEBUG, "pam_dhkeys: no valid mechs " 375*0Sstevel@tonic-gate "found. Trying AUTH_DES."); 376*0Sstevel@tonic-gate } 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate /* 379*0Sstevel@tonic-gate * We always perform AUTH_DES for the benefit of non-NIS+ 380*0Sstevel@tonic-gate * services (e.g. NFS) that may depend on the classic des 381*0Sstevel@tonic-gate * 192bit key being set. 382*0Sstevel@tonic-gate */ 383*0Sstevel@tonic-gate if (!get_and_set_seckey(pamh, netname, AUTH_DES_KEYLEN, 384*0Sstevel@tonic-gate AUTH_DES_ALGTYPE, short_passp, uid, gid, &get_seckey_cnt, 385*0Sstevel@tonic-gate &good_pw_cnt, &set_seckey_cnt, flags, debug)) { 386*0Sstevel@tonic-gate result = PAM_BUF_ERR; 387*0Sstevel@tonic-gate goto out; 388*0Sstevel@tonic-gate } 389*0Sstevel@tonic-gate 390*0Sstevel@tonic-gate if (debug) { 391*0Sstevel@tonic-gate syslog(LOG_DEBUG, "pam_dhkeys: mech key totals:\n"); 392*0Sstevel@tonic-gate syslog(LOG_DEBUG, "pam_dhkeys: %d valid mechanism(s)", 393*0Sstevel@tonic-gate valid_mech_cnt); 394*0Sstevel@tonic-gate syslog(LOG_DEBUG, "pam_dhkeys: %d secret key(s) retrieved", 395*0Sstevel@tonic-gate get_seckey_cnt); 396*0Sstevel@tonic-gate syslog(LOG_DEBUG, "pam_dhkeys: %d passwd decrypt successes", 397*0Sstevel@tonic-gate good_pw_cnt); 398*0Sstevel@tonic-gate syslog(LOG_DEBUG, "pam_dhkeys: %d secret key(s) set", 399*0Sstevel@tonic-gate set_seckey_cnt); 400*0Sstevel@tonic-gate } 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate if (get_seckey_cnt == 0) { /* No credentials */ 403*0Sstevel@tonic-gate result = need_cred ? PAM_AUTH_ERR : PAM_IGNORE; 404*0Sstevel@tonic-gate goto out; 405*0Sstevel@tonic-gate } 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate if (good_pw_cnt == 0) { /* wrong password */ 408*0Sstevel@tonic-gate result = PAM_AUTH_ERR; 409*0Sstevel@tonic-gate goto out; 410*0Sstevel@tonic-gate } 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate if (set_seckey_cnt == 0) { 413*0Sstevel@tonic-gate result = PAM_SYSTEM_ERR; 414*0Sstevel@tonic-gate goto out; 415*0Sstevel@tonic-gate } 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate result = PAM_IGNORE; 418*0Sstevel@tonic-gate out: 419*0Sstevel@tonic-gate if (repository_name) 420*0Sstevel@tonic-gate free(repository_name); 421*0Sstevel@tonic-gate if (repository_pass) 422*0Sstevel@tonic-gate free(repository_pass); 423*0Sstevel@tonic-gate 424*0Sstevel@tonic-gate free(scratch); 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate (void) memset(short_pass, '\0', sizeof (short_pass)); 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate return (result); 429*0Sstevel@tonic-gate } 430*0Sstevel@tonic-gate 431*0Sstevel@tonic-gate int 432*0Sstevel@tonic-gate pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) 433*0Sstevel@tonic-gate { 434*0Sstevel@tonic-gate int i; 435*0Sstevel@tonic-gate int debug = 0; 436*0Sstevel@tonic-gate int result; 437*0Sstevel@tonic-gate char netname[MAXNETNAMELEN + 1]; 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate for (i = 0; i < argc; i++) { 440*0Sstevel@tonic-gate if (strcmp(argv[i], "debug") == 0) 441*0Sstevel@tonic-gate debug = 1; 442*0Sstevel@tonic-gate else if (strcmp(argv[i], "nowarn") == 0) 443*0Sstevel@tonic-gate flags |= PAM_SILENT; 444*0Sstevel@tonic-gate } 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gate result = establish_key(pamh, flags, CODEPATH_PAM_SM_AUTHENTICATE, debug, 447*0Sstevel@tonic-gate netname); 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate return (result); 450*0Sstevel@tonic-gate } 451*0Sstevel@tonic-gate 452*0Sstevel@tonic-gate int 453*0Sstevel@tonic-gate remove_key(pam_handle_t *pamh, int flags, int debug) 454*0Sstevel@tonic-gate { 455*0Sstevel@tonic-gate int result; 456*0Sstevel@tonic-gate char *uname; 457*0Sstevel@tonic-gate attrlist attr_pw[2]; 458*0Sstevel@tonic-gate struct pam_repository *auth_rep = NULL; 459*0Sstevel@tonic-gate pwu_repository_t *pwu_rep; 460*0Sstevel@tonic-gate uid_t uid; 461*0Sstevel@tonic-gate gid_t gid; 462*0Sstevel@tonic-gate struct nfs_revauth_args nra; 463*0Sstevel@tonic-gate 464*0Sstevel@tonic-gate (void) pam_get_item(pamh, PAM_USER, (void **)&uname); 465*0Sstevel@tonic-gate if (uname == NULL || *uname == NULL) { 466*0Sstevel@tonic-gate if (debug) 467*0Sstevel@tonic-gate syslog(LOG_DEBUG, 468*0Sstevel@tonic-gate "pam_dhkeys: user NULL or empty in remove_key()"); 469*0Sstevel@tonic-gate return (PAM_USER_UNKNOWN); 470*0Sstevel@tonic-gate } 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate if (strcmp(uname, "root") == 0) { 473*0Sstevel@tonic-gate if ((flags & PAM_SILENT) == 0) { 474*0Sstevel@tonic-gate char msg[3][PAM_MAX_MSG_SIZE]; 475*0Sstevel@tonic-gate (void) snprintf(msg[0], sizeof (msg[0]), 476*0Sstevel@tonic-gate dgettext(TEXT_DOMAIN, 477*0Sstevel@tonic-gate "removing root credentials would" 478*0Sstevel@tonic-gate " break the rpc services that")); 479*0Sstevel@tonic-gate (void) snprintf(msg[1], sizeof (msg[1]), 480*0Sstevel@tonic-gate dgettext(TEXT_DOMAIN, 481*0Sstevel@tonic-gate "use secure rpc on this host!")); 482*0Sstevel@tonic-gate (void) snprintf(msg[2], sizeof (msg[2]), 483*0Sstevel@tonic-gate dgettext(TEXT_DOMAIN, 484*0Sstevel@tonic-gate "root may use keylogout -f to do" 485*0Sstevel@tonic-gate " this (at your own risk)!")); 486*0Sstevel@tonic-gate (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 3, 487*0Sstevel@tonic-gate msg, NULL); 488*0Sstevel@tonic-gate } 489*0Sstevel@tonic-gate return (PAM_PERM_DENIED); 490*0Sstevel@tonic-gate } 491*0Sstevel@tonic-gate 492*0Sstevel@tonic-gate (void) pam_get_item(pamh, PAM_REPOSITORY, (void **)&auth_rep); 493*0Sstevel@tonic-gate if (auth_rep != NULL) { 494*0Sstevel@tonic-gate if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL) 495*0Sstevel@tonic-gate return (PAM_BUF_ERR); 496*0Sstevel@tonic-gate pwu_rep->type = auth_rep->type; 497*0Sstevel@tonic-gate pwu_rep->scope = auth_rep->scope; 498*0Sstevel@tonic-gate pwu_rep->scope_len = auth_rep->scope_len; 499*0Sstevel@tonic-gate } else 500*0Sstevel@tonic-gate pwu_rep = PWU_DEFAULT_REP; 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate /* Retrieve user's uid/gid from the password repository */ 503*0Sstevel@tonic-gate attr_pw[0].type = ATTR_UID; attr_pw[0].next = &attr_pw[1]; 504*0Sstevel@tonic-gate attr_pw[1].type = ATTR_GID; attr_pw[1].next = NULL; 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate result = __get_authtoken_attr(uname, pwu_rep, attr_pw); 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate if (pwu_rep != PWU_DEFAULT_REP) 509*0Sstevel@tonic-gate free(pwu_rep); 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate if (result == PWU_NOT_FOUND) 512*0Sstevel@tonic-gate return (PAM_USER_UNKNOWN); 513*0Sstevel@tonic-gate if (result == PWU_DENIED) 514*0Sstevel@tonic-gate return (PAM_PERM_DENIED); 515*0Sstevel@tonic-gate if (result != PWU_SUCCESS) 516*0Sstevel@tonic-gate return (PAM_SYSTEM_ERR); 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate uid = (uid_t)attr_pw[0].data.val_i; 519*0Sstevel@tonic-gate gid = (gid_t)attr_pw[1].data.val_i; 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate (void) key_removesecret_g_uid(uid, gid); 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate /* Revoke NFS DES credentials */ 524*0Sstevel@tonic-gate nra.authtype = AUTH_DES; 525*0Sstevel@tonic-gate nra.uid = uid; 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate if (_nfssys(NFS_REVAUTH, &nra) < 0) { 528*0Sstevel@tonic-gate if ((flags & PAM_SILENT) == 0) { 529*0Sstevel@tonic-gate (void) msg(pamh, dgettext(TEXT_DOMAIN, 530*0Sstevel@tonic-gate "Warning: NFS credentials not destroyed")); 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate return (PAM_AUTH_ERR); 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate return (PAM_IGNORE); 536*0Sstevel@tonic-gate } 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate int 539*0Sstevel@tonic-gate pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) 540*0Sstevel@tonic-gate { 541*0Sstevel@tonic-gate int i; 542*0Sstevel@tonic-gate int debug = 0; 543*0Sstevel@tonic-gate int result; 544*0Sstevel@tonic-gate char netname[MAXNETNAMELEN + 1]; 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate for (i = 0; i < argc; i++) { 547*0Sstevel@tonic-gate if (strcmp(argv[i], "debug") == 0) 548*0Sstevel@tonic-gate debug = 1; 549*0Sstevel@tonic-gate else if (strcmp(argv[i], "nowarn") == 0) 550*0Sstevel@tonic-gate flags |= PAM_SILENT; 551*0Sstevel@tonic-gate } 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate /* Check for invalid flags */ 554*0Sstevel@tonic-gate if (flags && (flags & PAM_ESTABLISH_CRED) == 0 && 555*0Sstevel@tonic-gate (flags & PAM_REINITIALIZE_CRED) == 0 && 556*0Sstevel@tonic-gate (flags & PAM_REFRESH_CRED) == 0 && 557*0Sstevel@tonic-gate (flags & PAM_DELETE_CRED) == 0 && 558*0Sstevel@tonic-gate (flags & PAM_SILENT) == 0) { 559*0Sstevel@tonic-gate syslog(LOG_ERR, "pam_dhkeys: pam_setcred: illegal flags %d", 560*0Sstevel@tonic-gate flags); 561*0Sstevel@tonic-gate return (PAM_SYSTEM_ERR); 562*0Sstevel@tonic-gate } 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate if ((flags & PAM_REINITIALIZE_CRED) || (flags & PAM_REFRESH_CRED)) { 566*0Sstevel@tonic-gate /* doesn't apply to UNIX */ 567*0Sstevel@tonic-gate if (debug) 568*0Sstevel@tonic-gate syslog(LOG_DEBUG, "pam_dhkeys: cred reinit/refresh " 569*0Sstevel@tonic-gate "ignored\n"); 570*0Sstevel@tonic-gate return (PAM_IGNORE); 571*0Sstevel@tonic-gate } 572*0Sstevel@tonic-gate 573*0Sstevel@tonic-gate if (flags & PAM_DELETE_CRED) { 574*0Sstevel@tonic-gate if (debug) 575*0Sstevel@tonic-gate syslog(LOG_DEBUG, "pam_dhkeys: removing creds\n"); 576*0Sstevel@tonic-gate result = remove_key(pamh, flags, debug); 577*0Sstevel@tonic-gate } else { 578*0Sstevel@tonic-gate result = establish_key(pamh, flags, CODEPATH_PAM_SM_SETCRED, 579*0Sstevel@tonic-gate debug, netname); 580*0Sstevel@tonic-gate /* Some diagnostics */ 581*0Sstevel@tonic-gate if ((flags & PAM_SILENT) == 0) { 582*0Sstevel@tonic-gate if (result == PAM_AUTH_ERR) 583*0Sstevel@tonic-gate (void) msg(pamh, dgettext(TEXT_DOMAIN, 584*0Sstevel@tonic-gate "Password does not decrypt any secret " 585*0Sstevel@tonic-gate "keys for %s."), netname); 586*0Sstevel@tonic-gate else if (result == PAM_SYSTEM_ERR && netname[0]) 587*0Sstevel@tonic-gate (void) msg(pamh, dgettext(TEXT_DOMAIN, 588*0Sstevel@tonic-gate "Could not set secret key(s) for %s. " 589*0Sstevel@tonic-gate "The key server may be down."), netname); 590*0Sstevel@tonic-gate } 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate /* Not having credentials set is not an error... */ 593*0Sstevel@tonic-gate result = PAM_IGNORE; 594*0Sstevel@tonic-gate } 595*0Sstevel@tonic-gate 596*0Sstevel@tonic-gate return (result); 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate /*ARGSUSED*/ 600*0Sstevel@tonic-gate void 601*0Sstevel@tonic-gate rpc_cleanup(pam_handle_t *pamh, void *data, int pam_status) 602*0Sstevel@tonic-gate { 603*0Sstevel@tonic-gate if (data) { 604*0Sstevel@tonic-gate (void) memset(data, 0, strlen(data)); 605*0Sstevel@tonic-gate free(data); 606*0Sstevel@tonic-gate } 607*0Sstevel@tonic-gate } 608*0Sstevel@tonic-gate 609*0Sstevel@tonic-gate int 610*0Sstevel@tonic-gate pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) 611*0Sstevel@tonic-gate { 612*0Sstevel@tonic-gate int i; 613*0Sstevel@tonic-gate int debug = 0; 614*0Sstevel@tonic-gate int res; 615*0Sstevel@tonic-gate pam_repository_t *pam_rep; 616*0Sstevel@tonic-gate pwu_repository_t *pwu_rep; 617*0Sstevel@tonic-gate char *oldpw; 618*0Sstevel@tonic-gate char *user; 619*0Sstevel@tonic-gate int tries; 620*0Sstevel@tonic-gate int oldpw_ok; 621*0Sstevel@tonic-gate char *oldrpcpw; 622*0Sstevel@tonic-gate char *oldrpcpass; 623*0Sstevel@tonic-gate char *data; 624*0Sstevel@tonic-gate /* password truncated at 8 chars, see comment at establish_key() */ 625*0Sstevel@tonic-gate char short_pass[sizeof (des_block)+1], *short_passp; 626*0Sstevel@tonic-gate 627*0Sstevel@tonic-gate for (i = 0; i < argc; i++) 628*0Sstevel@tonic-gate if (strcmp(argv[i], "debug") == 0) 629*0Sstevel@tonic-gate debug = 1; 630*0Sstevel@tonic-gate 631*0Sstevel@tonic-gate if (debug) 632*0Sstevel@tonic-gate syslog(LOG_DEBUG, "pam_dhkeys: entered pam_sm_chauthtok()"); 633*0Sstevel@tonic-gate 634*0Sstevel@tonic-gate if ((flags & PAM_PRELIM_CHECK) == 0) 635*0Sstevel@tonic-gate return (PAM_IGNORE); 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate /* 638*0Sstevel@tonic-gate * See if the old secure-rpc password has already been set 639*0Sstevel@tonic-gate */ 640*0Sstevel@tonic-gate res = pam_get_data(pamh, SUNW_OLDRPCPASS, (const void **)&oldrpcpass); 641*0Sstevel@tonic-gate if (res == PAM_SUCCESS) { 642*0Sstevel@tonic-gate if (debug) 643*0Sstevel@tonic-gate syslog(LOG_DEBUG, 644*0Sstevel@tonic-gate "pam_dhkeys: OLDRPCPASS already set"); 645*0Sstevel@tonic-gate return (PAM_IGNORE); 646*0Sstevel@tonic-gate } 647*0Sstevel@tonic-gate 648*0Sstevel@tonic-gate (void) pam_get_item(pamh, PAM_REPOSITORY, (void **)&pam_rep); 649*0Sstevel@tonic-gate 650*0Sstevel@tonic-gate (void) pam_get_item(pamh, PAM_USER, (void **)&user); 651*0Sstevel@tonic-gate 652*0Sstevel@tonic-gate (void) pam_get_item(pamh, PAM_AUTHTOK, (void **)&oldpw); 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate if (user == NULL || *user == '\0') { 655*0Sstevel@tonic-gate if (debug) 656*0Sstevel@tonic-gate syslog(LOG_DEBUG, "pam_dhkeys: user NULL or empty"); 657*0Sstevel@tonic-gate return (PAM_USER_UNKNOWN); 658*0Sstevel@tonic-gate } 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate /* oldpw can be NULL (eg. root changing someone's passwd) */ 661*0Sstevel@tonic-gate if (oldpw) { 662*0Sstevel@tonic-gate (void) strlcpy(short_pass, oldpw, sizeof (short_pass)); 663*0Sstevel@tonic-gate short_passp = short_pass; 664*0Sstevel@tonic-gate } else 665*0Sstevel@tonic-gate short_passp = NULL; 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate /* 668*0Sstevel@tonic-gate * For NIS+ we need to check whether the old password equals 669*0Sstevel@tonic-gate * the RPC password. If it doesn't, we won't be able to update 670*0Sstevel@tonic-gate * the secure RPC credentials later on in the process. 671*0Sstevel@tonic-gate */ 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gate if (pam_rep == NULL) 674*0Sstevel@tonic-gate pwu_rep = PWU_DEFAULT_REP; 675*0Sstevel@tonic-gate else { 676*0Sstevel@tonic-gate if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL) 677*0Sstevel@tonic-gate return (PAM_BUF_ERR); 678*0Sstevel@tonic-gate pwu_rep->type = pam_rep->type; 679*0Sstevel@tonic-gate pwu_rep->scope = pam_rep->scope; 680*0Sstevel@tonic-gate pwu_rep->scope_len = pam_rep->scope_len; 681*0Sstevel@tonic-gate } 682*0Sstevel@tonic-gate 683*0Sstevel@tonic-gate switch (__verify_rpc_passwd(user, short_passp, pwu_rep)) { 684*0Sstevel@tonic-gate case PWU_SUCCESS: 685*0Sstevel@tonic-gate /* oldpw matches RPC password, or no RPC password needed */ 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate if (pwu_rep != PWU_DEFAULT_REP) 688*0Sstevel@tonic-gate free(pwu_rep); 689*0Sstevel@tonic-gate 690*0Sstevel@tonic-gate if (short_passp) { 691*0Sstevel@tonic-gate if ((data = strdup(short_pass)) == NULL) { 692*0Sstevel@tonic-gate (void) memset(short_pass, '\0', 693*0Sstevel@tonic-gate sizeof (short_pass)); 694*0Sstevel@tonic-gate return (PAM_BUF_ERR); 695*0Sstevel@tonic-gate } 696*0Sstevel@tonic-gate } else 697*0Sstevel@tonic-gate data = NULL; 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate (void) pam_set_data(pamh, SUNW_OLDRPCPASS, data, rpc_cleanup); 700*0Sstevel@tonic-gate return (PAM_IGNORE); 701*0Sstevel@tonic-gate 702*0Sstevel@tonic-gate case PWU_NOT_FOUND: 703*0Sstevel@tonic-gate if (pwu_rep != PWU_DEFAULT_REP) 704*0Sstevel@tonic-gate free(pwu_rep); 705*0Sstevel@tonic-gate (void) memset(short_pass, '\0', sizeof (short_pass)); 706*0Sstevel@tonic-gate return (PAM_USER_UNKNOWN); 707*0Sstevel@tonic-gate case PWU_CRED_ERROR: 708*0Sstevel@tonic-gate /* The old password does not decrypt any credentials */ 709*0Sstevel@tonic-gate break; 710*0Sstevel@tonic-gate default: 711*0Sstevel@tonic-gate if (pwu_rep != PWU_DEFAULT_REP) 712*0Sstevel@tonic-gate free(pwu_rep); 713*0Sstevel@tonic-gate (void) memset(short_pass, '\0', sizeof (short_pass)); 714*0Sstevel@tonic-gate return (PAM_SYSTEM_ERR); 715*0Sstevel@tonic-gate } 716*0Sstevel@tonic-gate 717*0Sstevel@tonic-gate /* 718*0Sstevel@tonic-gate * We got here because the OLDAUTHTOK doesn't match the Secure RPC 719*0Sstevel@tonic-gate * password. In compliance with the old behavior, we give the 720*0Sstevel@tonic-gate * user two chances to get the password right. If that succeeds 721*0Sstevel@tonic-gate * all is well; if it doesn't, we'll return an error. 722*0Sstevel@tonic-gate */ 723*0Sstevel@tonic-gate 724*0Sstevel@tonic-gate (void) msg(pamh, dgettext(TEXT_DOMAIN, 725*0Sstevel@tonic-gate "This password differs from your secure RPC password.")); 726*0Sstevel@tonic-gate 727*0Sstevel@tonic-gate tries = 0; 728*0Sstevel@tonic-gate oldpw_ok = 0; 729*0Sstevel@tonic-gate 730*0Sstevel@tonic-gate while (oldpw_ok == 0 && ++tries < 3) { 731*0Sstevel@tonic-gate if (tries > 1) 732*0Sstevel@tonic-gate (void) msg(pamh, dgettext(TEXT_DOMAIN, 733*0Sstevel@tonic-gate "This password does not decrypt your " 734*0Sstevel@tonic-gate "secure RPC password.")); 735*0Sstevel@tonic-gate res = __pam_get_authtok(pamh, PAM_PROMPT, 0, 736*0Sstevel@tonic-gate dgettext(TEXT_DOMAIN, 737*0Sstevel@tonic-gate "Please enter your old Secure RPC password: "), &oldpw); 738*0Sstevel@tonic-gate if (res != PAM_SUCCESS) { 739*0Sstevel@tonic-gate if (pwu_rep != PWU_DEFAULT_REP) 740*0Sstevel@tonic-gate free(pwu_rep); 741*0Sstevel@tonic-gate return (res); 742*0Sstevel@tonic-gate } 743*0Sstevel@tonic-gate (void) strlcpy(short_pass, oldpw, sizeof (short_pass)); 744*0Sstevel@tonic-gate (void) memset(oldpw, 0, strlen(oldpw)); 745*0Sstevel@tonic-gate free(oldpw); 746*0Sstevel@tonic-gate oldpw = NULL; 747*0Sstevel@tonic-gate if (__verify_rpc_passwd(user, short_pass, pwu_rep) == 748*0Sstevel@tonic-gate PWU_SUCCESS) 749*0Sstevel@tonic-gate oldpw_ok = 1; 750*0Sstevel@tonic-gate } 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gate if (pwu_rep != PWU_DEFAULT_REP) 753*0Sstevel@tonic-gate free(pwu_rep); 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate if (oldpw_ok == 0) { 756*0Sstevel@tonic-gate (void) memset(short_pass, '\0', sizeof (short_pass)); 757*0Sstevel@tonic-gate return (PAM_AUTHTOK_ERR); 758*0Sstevel@tonic-gate } 759*0Sstevel@tonic-gate 760*0Sstevel@tonic-gate /* 761*0Sstevel@tonic-gate * Since the PAM framework only provides space for two different 762*0Sstevel@tonic-gate * password (one old and one current), there is officially no 763*0Sstevel@tonic-gate * place to put additional passwords (like our old rpc password). 764*0Sstevel@tonic-gate * We have no choice but to stuff it in a data item, and hope it 765*0Sstevel@tonic-gate * will be picked up by the password-update routines. 766*0Sstevel@tonic-gate */ 767*0Sstevel@tonic-gate 768*0Sstevel@tonic-gate oldrpcpw = strdup(short_pass); 769*0Sstevel@tonic-gate (void) memset(short_pass, '\0', sizeof (short_pass)); 770*0Sstevel@tonic-gate 771*0Sstevel@tonic-gate if (oldrpcpw == NULL) 772*0Sstevel@tonic-gate return (PAM_BUF_ERR); 773*0Sstevel@tonic-gate 774*0Sstevel@tonic-gate res = pam_set_data(pamh, SUNW_OLDRPCPASS, oldrpcpw, rpc_cleanup); 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate return (res); 777*0Sstevel@tonic-gate } 778