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 2006 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 <kadm5/admin.h> 29 #include <krb5.h> 30 31 #include <security/pam_appl.h> 32 #include <security/pam_modules.h> 33 #include <security/pam_impl.h> 34 #include <syslog.h> 35 #include <string.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <sys/types.h> 39 #include <pwd.h> 40 #include <libintl.h> 41 #include <netdb.h> 42 #include "utils.h" 43 #include "krb5_repository.h" 44 45 #define MISC_EXIT_STATUS 6 46 #define DONT_DISP_POLICY 0 47 #define DISP_POLICY 1 48 49 extern int attempt_krb5_auth(void *, krb5_module_data_t *, char *, char **, 50 boolean_t); 51 extern int krb5_verifypw(pam_handle_t *, char *, char *, boolean_t, int); 52 53 static char *get_passwd(pam_handle_t *, char *); 54 static void display_msg(pam_handle_t *, int, char *); 55 static void display_msgs(pam_handle_t *, int, int, 56 char msgs[][PAM_MAX_MSG_SIZE]); 57 static int krb5_changepw(pam_handle_t *, char *, char *, char *, int); 58 59 /* 60 * set_ccname() 61 * 62 * set KRB5CCNAME shell var 63 */ 64 static void 65 set_ccname( 66 pam_handle_t *pamh, 67 krb5_module_data_t *kmd, 68 int login_result, 69 int debug) 70 { 71 int result; 72 73 if (debug) 74 syslog(LOG_DEBUG, 75 "PAM-KRB5 (password): password: finalize" 76 " ccname env, login_result =%d, env ='%s'", 77 login_result, kmd->env ? kmd->env : "<null>"); 78 79 if (kmd->env) { 80 81 if (login_result == PAM_SUCCESS) { 82 /* 83 * Put ccname into the pamh so that login 84 * apps can pick this up when they run 85 * pam_getenvlist(). 86 */ 87 if ((result = pam_putenv(pamh, kmd->env)) 88 != PAM_SUCCESS) { 89 /* should not happen but... */ 90 syslog(LOG_ERR, 91 dgettext(TEXT_DOMAIN, 92 "PAM-KRB5 (password):" 93 " pam_putenv failed: result: %d"), 94 result); 95 goto cleanupccname; 96 } 97 } else { 98 cleanupccname: 99 /* for lack of a Solaris unputenv() */ 100 krb5_unsetenv(KRB5_ENV_CCNAME); 101 free(kmd->env); 102 kmd->env = NULL; 103 } 104 } 105 } 106 107 /* 108 * get_set_creds() 109 * 110 * do a krb5 login to get and set krb5 creds (needed after a pw change 111 * on pw expire on login) 112 */ 113 static void 114 get_set_creds( 115 pam_handle_t *pamh, 116 krb5_module_data_t *kmd, 117 char *user, 118 char *newpass, 119 int debug) 120 { 121 int login_result; 122 123 if (!kmd || kmd->age_status != PAM_NEW_AUTHTOK_REQD) 124 return; 125 126 /* 127 * if pw has expired, get/set krb5 creds ala auth mod 128 * 129 * pwchange verified user sufficiently, so don't request strict 130 * tgt verification (will cause rcache perm issues possibly anyways) 131 */ 132 login_result = attempt_krb5_auth(pamh, kmd, user, &newpass, 0); 133 if (debug) 134 syslog(LOG_DEBUG, 135 "PAM-KRB5 (password): get_set_creds: login_result= %d", 136 login_result); 137 /* 138 * the krb5 login should not fail, but if so, 139 * warn the user they have to kinit(1) 140 */ 141 if (login_result != PAM_SUCCESS) { 142 display_msg(pamh, PAM_TEXT_INFO, 143 dgettext(TEXT_DOMAIN, 144 "Warning: " 145 "Could not cache Kerberos" 146 " credentials, please run " 147 "kinit(1) or re-login\n")); 148 } 149 set_ccname(pamh, kmd, login_result, debug); 150 } 151 /* 152 * This is the PAM Kerberos Password Change module 153 * 154 */ 155 156 int 157 pam_sm_chauthtok( 158 pam_handle_t *pamh, 159 int flags, 160 int argc, 161 const char **argv) 162 { 163 164 char *user; 165 int err, result = PAM_AUTH_ERR; 166 char *newpass = NULL, *vnewpass = NULL; 167 char *oldpass = NULL; 168 int i; 169 int debug = 0; 170 uid_t pw_uid; 171 krb5_module_data_t *kmd = NULL; 172 char *pam_service; 173 int promptforold = 0; 174 int promptfornew = 0; 175 pam_repository_t *rep_data = NULL; 176 177 for (i = 0; i < argc; i++) { 178 if (strcmp(argv[i], "debug") == 0) 179 debug = 1; 180 else 181 syslog(LOG_ERR, 182 dgettext(TEXT_DOMAIN, 183 "PAM-KRB5 (password): illegal option %s"), 184 argv[i]); 185 } 186 187 if (debug) 188 syslog(LOG_DEBUG, 189 "PAM-KRB5 (password): start: flags = %x", 190 flags); 191 192 err = pam_get_item(pamh, PAM_REPOSITORY, (void **)&rep_data); 193 if (rep_data != NULL) { 194 if (strcmp(rep_data->type, KRB5_REPOSITORY_NAME) != 0) { 195 if (debug) 196 syslog(LOG_DEBUG, "PAM-KRB5 (auth): wrong" 197 "repository found (%s), returning " 198 "PAM_IGNORE", rep_data->type); 199 return (PAM_IGNORE); 200 } 201 } 202 203 if (flags & PAM_PRELIM_CHECK) { 204 /* Nothing to do here */ 205 if (debug) 206 syslog(LOG_DEBUG, 207 "PAM-KRB5 (password): prelim check"); 208 return (PAM_IGNORE); 209 } 210 211 /* make sure PAM framework is telling us to update passwords */ 212 if (!(flags & PAM_UPDATE_AUTHTOK)) { 213 syslog(LOG_ERR, dgettext(TEXT_DOMAIN, 214 "PAM-KRB5 (password): bad flags: %d"), 215 flags); 216 return (PAM_SYSTEM_ERR); 217 } 218 219 220 if ((err = pam_get_data(pamh, KRB5_DATA, (const void **)&kmd)) 221 != PAM_SUCCESS) { 222 if (debug) 223 syslog(LOG_DEBUG, 224 "PAM-KRB5 (password): get mod data failed %d", 225 err); 226 kmd = NULL; 227 } 228 229 if (flags & PAM_CHANGE_EXPIRED_AUTHTOK) { 230 /* let's make sure we know the krb5 pw has expired */ 231 232 if (debug) 233 syslog(LOG_DEBUG, 234 "PAM-KRB5 (password): kmd age status %d", 235 kmd ? kmd->age_status : -99); 236 237 if (!kmd || kmd->age_status != PAM_NEW_AUTHTOK_REQD) 238 return (PAM_IGNORE); 239 } 240 241 err = pam_get_item(pamh, PAM_SERVICE, (void **)&pam_service); 242 if (err != PAM_SUCCESS) { 243 syslog(LOG_ERR, 244 "PAM-KRB5 (password): error getting SERVICE"); 245 return (PAM_SYSTEM_ERR); 246 } 247 248 err = pam_get_item(pamh, PAM_USER, (void **)&user); 249 if (err != PAM_SUCCESS) { 250 syslog(LOG_ERR, 251 "PAM-KRB5 (password): error getting USER"); 252 return (PAM_SYSTEM_ERR); 253 } 254 255 if (user == NULL || user == '\0') { 256 syslog(LOG_ERR, 257 "PAM-KRB5 (password): username is empty"); 258 return (PAM_SYSTEM_ERR); 259 } 260 261 if (!get_pw_uid(user, &pw_uid)) { 262 syslog(LOG_ERR, 263 "PAM-KRB5 (password): can't get uid for %s", 264 user); 265 return (PAM_AUTHTOK_ERR); 266 } 267 268 /* 269 * if root key exists in the keytab, it's a random key so no 270 * need to prompt for pw and we just return IGNORE 271 */ 272 if ((strcmp(user, ROOT_UNAME) == 0) && 273 key_in_keytab(user, debug)) { 274 if (debug) 275 syslog(LOG_DEBUG, 276 "PAM-KRB5 (password): " 277 "key for '%s' in keytab, returning IGNORE", user); 278 result = PAM_IGNORE; 279 goto out; 280 } 281 282 if ((err = pam_get_item(pamh, PAM_AUTHTOK, 283 (void **) &newpass)) < 0) 284 return (err); 285 286 if ((err = pam_get_item(pamh, PAM_OLDAUTHTOK, 287 (void **) &oldpass)) < 0) 288 return (err); 289 290 if (!newpass && !oldpass) { 291 promptforold = 1; 292 promptfornew = 1; 293 } else { 294 /* 295 * OLDAUTHTOK not set, we're probably the first password 296 * module but the AUTHTOK is probably set from an auth mod 297 */ 298 if (newpass && !oldpass) { 299 oldpass = newpass; 300 newpass = NULL; 301 promptfornew = 1; 302 } 303 304 result = krb5_verifypw(pamh, user, oldpass, 305 DONT_DISP_POLICY, debug); 306 if (debug) 307 syslog(LOG_DEBUG, 308 "PAM-KRB5 (password): verifypw first %d", 309 result); 310 /* 311 * If this fails and is not bad passwd, then it might 312 * be a non-rpcsec_gss KDC so drop thru. 313 * 314 * (note in S9 change pw should work on non-rpcsec_gss KDCs 315 * such as MIT & MS) 316 */ 317 if (result != 0) 318 promptforold = 1; 319 } 320 321 if (promptforold) { 322 323 oldpass = get_passwd(pamh, 324 dgettext(TEXT_DOMAIN, 325 "Old Kerberos password: ")); 326 327 if (oldpass == NULL || oldpass[0] == '\0') { 328 /* Need a password to proceed */ 329 display_msg(pamh, PAM_ERROR_MSG, 330 dgettext(TEXT_DOMAIN, 331 "Need the old password" 332 " to proceed \n")); 333 free(oldpass); 334 return (PAM_AUTHTOK_ERR); 335 } 336 337 result = krb5_verifypw(pamh, user, oldpass, 338 DISP_POLICY, debug); 339 if (debug) 340 syslog(LOG_DEBUG, 341 "PAM-KRB5 (password): verifypw prforold %d", 342 result); 343 /* 344 * If it's a bad password, we are done. 345 * Else, continue and try the pwch with oldpass. 346 */ 347 if (result == 2) { 348 display_msg(pamh, PAM_ERROR_MSG, 349 dgettext(TEXT_DOMAIN, 350 "Old Kerberos" 351 " password incorrect\n")); 352 (void) memset(oldpass, 0, strlen(oldpass)); 353 free(oldpass); 354 return (PAM_AUTHTOK_ERR); 355 } 356 } 357 358 if (promptfornew) { 359 newpass = get_passwd(pamh, dgettext(TEXT_DOMAIN, 360 "New Kerberos password: ")); 361 362 if (newpass == NULL || newpass[0] == '\0') { 363 /* Need a password to proceed */ 364 display_msg(pamh, PAM_ERROR_MSG, 365 dgettext(TEXT_DOMAIN, 366 "Need a password to proceed \n")); 367 result = PAM_AUTHTOK_ERR; 368 goto out; 369 } 370 371 vnewpass = get_passwd(pamh, 372 dgettext(TEXT_DOMAIN, 373 "Re-enter new Kerberos password: ")); 374 375 if (vnewpass == NULL || vnewpass[0] == '\0') { 376 /* Need a password to proceed */ 377 display_msg(pamh, PAM_ERROR_MSG, 378 dgettext(TEXT_DOMAIN, 379 "Need a password to proceed \n")); 380 result = PAM_AUTHTOK_ERR; 381 goto out; 382 } 383 384 if (strcmp(newpass, vnewpass)) { 385 display_msg(pamh, PAM_ERROR_MSG, 386 dgettext(TEXT_DOMAIN, 387 "Passwords do not match \n")); 388 result = PAM_AUTHTOK_ERR; 389 goto out; 390 } 391 } 392 393 result = krb5_changepw(pamh, user, oldpass, newpass, debug); 394 if (result == PAM_SUCCESS) { 395 display_msg(pamh, PAM_TEXT_INFO, 396 dgettext(TEXT_DOMAIN, 397 "Kerberos password " 398 "successfully changed\n")); 399 400 get_set_creds(pamh, kmd, user, newpass, debug); 401 402 (void) pam_set_item(pamh, PAM_AUTHTOK, newpass); 403 (void) pam_set_item(pamh, PAM_OLDAUTHTOK, oldpass); 404 } 405 406 out: 407 if (promptforold && oldpass) { 408 (void) memset(oldpass, 0, strlen(oldpass)); 409 free(oldpass); 410 } 411 if (newpass) { 412 (void) memset(newpass, 0, strlen(newpass)); 413 free(newpass); 414 } 415 416 if (vnewpass) { 417 (void) memset(vnewpass, 0, strlen(vnewpass)); 418 free(vnewpass); 419 } 420 421 if (debug) 422 syslog(LOG_DEBUG, 423 "PAM-KRB5 (password): out: returns %d", 424 result); 425 426 return (result); 427 } 428 429 430 int 431 pam_sm_get_authtokattr( 432 /*ARGSUSED*/ 433 pam_handle_t *pamh, 434 char ***ga_getattr, 435 int repository, 436 const char *nisdomain, 437 int argc, 438 const char **argv) 439 { 440 return (PAM_SUCCESS); 441 } 442 443 int 444 pam_sm_set_authtokattr( 445 /*ARGSUSED*/ 446 pam_handle_t *pamh, 447 const char **pam_setattr, 448 int repository, 449 const char *nisdomain, 450 int argc, 451 const char **argv) 452 { 453 return (PAM_SUCCESS); 454 } 455 456 int 457 krb5_verifypw( 458 pam_handle_t *pamh, 459 char *princ_str, 460 char *old_password, 461 boolean_t disp_flag, 462 int debug) 463 { 464 kadm5_ret_t code; 465 krb5_principal princ = 0; 466 char admin_realm[1024]; 467 char kprinc[2*MAXHOSTNAMELEN]; 468 char *cpw_service; 469 kadm5_principal_ent_rec principal_entry; 470 kadm5_policy_ent_rec policy_entry; 471 void *server_handle; 472 krb5_context context; 473 kadm5_config_params params; 474 #define MSG_ROWS 5 475 char msgs[MSG_ROWS][PAM_MAX_MSG_SIZE]; 476 477 (void) memset((char *)¶ms, 0, sizeof (params)); 478 (void) memset(&principal_entry, 0, sizeof (principal_entry)); 479 (void) memset(&policy_entry, 0, sizeof (policy_entry)); 480 481 if (code = krb5_init_context(&context)) { 482 return (6); 483 } 484 485 if ((code = get_kmd_kuser(context, (const char *)princ_str, kprinc, 486 2*MAXHOSTNAMELEN)) != 0) { 487 return (code); 488 } 489 490 /* Need to get a krb5_principal struct */ 491 492 code = krb5_parse_name(context, kprinc, &princ); 493 494 if (code != 0) { 495 return (MISC_EXIT_STATUS); 496 } 497 498 if (strlen(old_password) == 0) { 499 krb5_free_principal(context, princ); 500 return (5); 501 } 502 503 (void) strlcpy(admin_realm, 504 krb5_princ_realm(context, princ)->data, 505 sizeof (admin_realm)); 506 507 params.mask |= KADM5_CONFIG_REALM; 508 params.realm = admin_realm; 509 510 511 if (kadm5_get_cpw_host_srv_name(context, admin_realm, &cpw_service)) { 512 syslog(LOG_ERR, 513 dgettext(TEXT_DOMAIN, 514 "PAM-KRB5 (password): unable to get host based " 515 "service name for realm %s\n"), 516 admin_realm); 517 return (3); 518 } 519 520 code = kadm5_init_with_password(kprinc, old_password, cpw_service, 521 ¶ms, KADM5_STRUCT_VERSION, 522 KADM5_API_VERSION_2, &server_handle); 523 if (code != 0) { 524 if (debug) 525 syslog(LOG_DEBUG, 526 "PAM-KRB5: krb5_verifypw: init_with_pw" 527 " failed: (%s)", error_message(code)); 528 krb5_free_principal(context, princ); 529 return ((code == KADM5_BAD_PASSWORD) ? 2 : 3); 530 } 531 532 if (disp_flag && 533 _kadm5_get_kpasswd_protocol(server_handle) == KRB5_CHGPWD_RPCSEC) { 534 /* 535 * Note: copy of this exists in login 536 * (kverify.c/get_verified_in_tkt). 537 */ 538 539 code = kadm5_get_principal(server_handle, princ, 540 &principal_entry, 541 KADM5_PRINCIPAL_NORMAL_MASK); 542 if (code != 0) { 543 krb5_free_principal(context, princ); 544 (void) kadm5_destroy(server_handle); 545 return ((code == KADM5_UNK_PRINC) ? 1 : 546 MISC_EXIT_STATUS); 547 } 548 549 if ((principal_entry.aux_attributes & KADM5_POLICY) != 0) { 550 code = kadm5_get_policy(server_handle, 551 principal_entry.policy, 552 &policy_entry); 553 if (code != 0) { 554 /* 555 * doesn't matter which error comes back, 556 * there's no nice recovery or need to 557 * differentiate to the user 558 */ 559 (void) kadm5_free_principal_ent(server_handle, 560 &principal_entry); 561 krb5_free_principal(context, princ); 562 (void) kadm5_destroy(server_handle); 563 return (MISC_EXIT_STATUS); 564 } 565 566 (void) snprintf(msgs[0], PAM_MAX_MSG_SIZE, 567 dgettext(TEXT_DOMAIN, "POLICY_EXPLANATION:")); 568 (void) snprintf(msgs[1], PAM_MAX_MSG_SIZE, 569 dgettext(TEXT_DOMAIN, 570 "Principal string is %s"), princ_str); 571 (void) snprintf(msgs[2], PAM_MAX_MSG_SIZE, 572 dgettext(TEXT_DOMAIN, "Policy Name is %s"), 573 principal_entry.policy); 574 (void) snprintf(msgs[3], PAM_MAX_MSG_SIZE, 575 dgettext(TEXT_DOMAIN, 576 "Minimum password length is %d"), 577 policy_entry.pw_min_length); 578 (void) snprintf(msgs[4], PAM_MAX_MSG_SIZE, 579 dgettext(TEXT_DOMAIN, 580 "Minimum password classes is %d"), 581 policy_entry.pw_min_classes); 582 display_msgs(pamh, PAM_TEXT_INFO, MSG_ROWS, msgs); 583 584 if (code = kadm5_free_principal_ent(server_handle, 585 &principal_entry)) { 586 (void) kadm5_free_policy_ent(server_handle, 587 &policy_entry); 588 krb5_free_principal(context, princ); 589 (void) kadm5_destroy(server_handle); 590 return (MISC_EXIT_STATUS); 591 } 592 if (code = kadm5_free_policy_ent(server_handle, 593 &policy_entry)) { 594 krb5_free_principal(context, princ); 595 596 (void) kadm5_destroy(server_handle); 597 return (MISC_EXIT_STATUS); 598 } 599 } else { 600 /* 601 * kpasswd *COULD* output something here to encourage 602 * the choice of good passwords, in the absence of 603 * an enforced policy. 604 */ 605 if (code = kadm5_free_principal_ent(server_handle, 606 &principal_entry)) { 607 krb5_free_principal(context, princ); 608 (void) kadm5_destroy(server_handle); 609 return (MISC_EXIT_STATUS); 610 } 611 } 612 } 613 krb5_free_principal(context, princ); 614 615 (void) kadm5_destroy(server_handle); 616 617 return (0); 618 } 619 620 /* 621 * Function: krb5_changepw 622 * 623 * Purpose: Initialize and call lower level routines to change a password 624 * 625 * Arguments: 626 * 627 * princ_str principal name to use, optional 628 * old_password old password 629 * new_password new password 630 * 631 * Returns: 632 * exit status of PAM_SUCCESS for success 633 * 1 principal unknown 634 * 2 old password wrong 635 * 3 cannot initialize admin server session 636 * 4 new passwd mismatch or error trying to change pw 637 * 5 password not typed 638 * 6 misc error 639 * 7 incorrect usage 640 * 641 * Requires: 642 * Passwords cannot be more than 255 characters long. 643 * 644 * Modifies: 645 * 646 * Changes the principal's password. 647 * 648 */ 649 static int 650 krb5_changepw( 651 pam_handle_t *pamh, 652 char *princ_str, 653 char *old_password, 654 char *new_password, 655 int debug) 656 { 657 kadm5_ret_t code; 658 krb5_principal princ = 0; 659 char msg_ret[1024], admin_realm[1024]; 660 char kprinc[2*MAXHOSTNAMELEN]; 661 char *cpw_service; 662 kadm5_principal_ent_rec principal_entry; 663 kadm5_policy_ent_rec policy_entry; 664 void *server_handle; 665 krb5_context context; 666 kadm5_config_params params; 667 668 (void) memset((char *)¶ms, 0, sizeof (params)); 669 (void) memset(&principal_entry, 0, sizeof (principal_entry)); 670 (void) memset(&policy_entry, 0, sizeof (policy_entry)); 671 672 if (code = krb5_init_context(&context)) { 673 return (6); 674 } 675 676 if ((code = get_kmd_kuser(context, (const char *)princ_str, kprinc, 677 2*MAXHOSTNAMELEN)) != 0) { 678 return (code); 679 } 680 681 /* Need to get a krb5_principal struct */ 682 683 code = krb5_parse_name(context, kprinc, &princ); 684 685 if (code != 0) { 686 return (MISC_EXIT_STATUS); 687 } 688 689 if (strlen(old_password) == 0) { 690 krb5_free_principal(context, princ); 691 return (5); 692 } 693 694 (void) snprintf(admin_realm, sizeof (admin_realm), "%s", 695 krb5_princ_realm(context, princ)->data); 696 params.mask |= KADM5_CONFIG_REALM; 697 params.realm = admin_realm; 698 699 700 if (kadm5_get_cpw_host_srv_name(context, admin_realm, &cpw_service)) { 701 syslog(LOG_ERR, 702 dgettext(TEXT_DOMAIN, 703 "PAM-KRB5 (password):unable to get host based " 704 "service name for realm %s\n"), 705 admin_realm); 706 return (3); 707 } 708 709 code = kadm5_init_with_password(kprinc, old_password, cpw_service, 710 ¶ms, KADM5_STRUCT_VERSION, 711 KADM5_API_VERSION_2, &server_handle); 712 free(cpw_service); 713 if (code != 0) { 714 if (debug) 715 syslog(LOG_DEBUG, 716 "PAM-KRB5 (password): changepw: " 717 "init_with_pw failed: (%s)", error_message(code)); 718 krb5_free_principal(context, princ); 719 return ((code == KADM5_BAD_PASSWORD) ? 2 : 3); 720 } 721 722 code = kadm5_chpass_principal_util(server_handle, princ, 723 new_password, 724 NULL /* don't need pw back */, 725 msg_ret, 726 sizeof (msg_ret)); 727 728 if (code) { 729 char msgs[2][PAM_MAX_MSG_SIZE]; 730 731 (void) snprintf(msgs[0], PAM_MAX_MSG_SIZE, "%s", 732 dgettext(TEXT_DOMAIN, 733 "Kerberos password not changed: ")); 734 (void) snprintf(msgs[1], PAM_MAX_MSG_SIZE, "%s", msg_ret); 735 736 display_msgs(pamh, PAM_ERROR_MSG, 2, msgs); 737 } 738 739 krb5_free_principal(context, princ); 740 741 (void) kadm5_destroy(server_handle); 742 743 if (debug) 744 syslog(LOG_DEBUG, 745 "PAM-KRB5 (password): changepw: end %d", code); 746 747 if (code == KRB5_LIBOS_CANTREADPWD) 748 return (5); 749 else if (code) 750 return (4); 751 else 752 return (PAM_SUCCESS); 753 } 754 755 static char * 756 get_passwd( 757 pam_handle_t *pamh, 758 char *prompt) 759 { 760 int err; 761 char *p; 762 763 err = __pam_get_authtok(pamh, PAM_PROMPT, 0, prompt, &p); 764 765 if (err != PAM_SUCCESS) { 766 return (NULL); 767 } 768 769 return (p); 770 } 771 772 773 static void 774 display_msgs(pam_handle_t *pamh, 775 int msg_style, int nmsg, char msgs[][PAM_MAX_MSG_SIZE]) 776 { 777 (void) __pam_display_msg(pamh, msg_style, nmsg, msgs, NULL); 778 } 779 780 781 static void 782 display_msg(pam_handle_t *pamh, int msg_style, char *msg) 783 { 784 char pam_msg[1][PAM_MAX_MSG_SIZE]; 785 786 (void) snprintf(pam_msg[0], PAM_MAX_MSG_SIZE, "%s", msg); 787 display_msgs(pamh, msg_style, 1, pam_msg); 788 } 789