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