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