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