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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Copyright 2020, Joyent, Inc. 28 */ 29 30 #include <syslog.h> 31 #include <dlfcn.h> 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 #include <stdlib.h> 35 #include <strings.h> 36 #include <malloc.h> 37 #include <unistd.h> 38 #include <fcntl.h> 39 #include <errno.h> 40 41 #include <security/pam_appl.h> 42 #include <security/pam_modules.h> 43 #include <sys/mman.h> 44 45 #include <libintl.h> 46 47 #include "pam_impl.h" 48 49 static char *pam_snames [PAM_NUM_MODULE_TYPES] = { 50 PAM_ACCOUNT_NAME, 51 PAM_AUTH_NAME, 52 PAM_PASSWORD_NAME, 53 PAM_SESSION_NAME 54 }; 55 56 static char *pam_inames [PAM_MAX_ITEMS] = { 57 /* NONE */ NULL, 58 /* PAM_SERVICE */ "service", 59 /* PAM_USER */ "user", 60 /* PAM_TTY */ "tty", 61 /* PAM_RHOST */ "rhost", 62 /* PAM_CONV */ "conv", 63 /* PAM_AUTHTOK */ "authtok", 64 /* PAM_OLDAUTHTOK */ "oldauthtok", 65 /* PAM_RUSER */ "ruser", 66 /* PAM_USER_PROMPT */ "user_prompt", 67 /* PAM_REPOSITORY */ "repository", 68 /* PAM_RESOURCE */ "resource", 69 /* PAM_AUSER */ "auser", 70 /* Undefined Items */ 71 }; 72 73 /* 74 * This extra definition is needed in order to build this library 75 * on pre-64-bit-aware systems. 76 */ 77 #if !defined(_LFS64_LARGEFILE) 78 #define stat64 stat 79 #endif /* !defined(_LFS64_LARGEFILE) */ 80 81 /* functions to dynamically load modules */ 82 static int load_modules(pam_handle_t *, int, char *, pamtab_t *); 83 static void *open_module(pam_handle_t *, char *); 84 static int load_function(void *, char *, int (**func)()); 85 86 /* functions to read and store the pam.conf configuration file */ 87 static int open_pam_conf(struct pam_fh **, pam_handle_t *, char *); 88 static void close_pam_conf(struct pam_fh *); 89 static int read_pam_conf(pam_handle_t *, char *); 90 static int get_pam_conf_entry(struct pam_fh *, pam_handle_t *, 91 pamtab_t **); 92 static char *read_next_token(char **); 93 static char *nextline(struct pam_fh *, pam_handle_t *, int *); 94 static int verify_pam_conf(pamtab_t *, char *); 95 96 /* functions to clean up and free memory */ 97 static void clean_up(pam_handle_t *); 98 static void free_pamconf(pamtab_t *); 99 static void free_pam_conf_info(pam_handle_t *); 100 static void free_env(env_list *); 101 102 /* convenience functions for I18N/L10N communication */ 103 104 static void free_resp(int, struct pam_response *); 105 static int do_conv(pam_handle_t *, int, int, 106 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], void *, 107 struct pam_response **); 108 109 static int log_priority; /* pam_trace syslog priority & facility */ 110 static int pam_debug = 0; 111 112 static char * 113 pam_trace_iname(int item_type, char *iname_buf) 114 { 115 char *name; 116 117 if (item_type <= 0 || 118 item_type >= PAM_MAX_ITEMS || 119 (name = pam_inames[item_type]) == NULL) { 120 (void) sprintf(iname_buf, "%d", item_type); 121 return (iname_buf); 122 } 123 return (name); 124 } 125 126 static char * 127 pam_trace_fname(int flag) 128 { 129 if (flag & PAM_BINDING) 130 return (PAM_BINDING_NAME); 131 if (flag & PAM_INCLUDE) 132 return (PAM_INCLUDE_NAME); 133 if (flag & PAM_OPTIONAL) 134 return (PAM_OPTIONAL_NAME); 135 if (flag & PAM_REQUIRED) 136 return (PAM_REQUIRED_NAME); 137 if (flag & PAM_REQUISITE) 138 return (PAM_REQUISITE_NAME); 139 if (flag & PAM_SUFFICIENT) 140 return (PAM_SUFFICIENT_NAME); 141 return ("bad flag name"); 142 } 143 144 static char * 145 pam_trace_cname(pam_handle_t *pamh) 146 { 147 if (pamh->pam_conf_name[pamh->include_depth] == NULL) 148 return ("NULL"); 149 return (pamh->pam_conf_name[pamh->include_depth]); 150 } 151 152 #include <deflt.h> 153 #include <stdarg.h> 154 /* 155 * pam_settrace - setup configuration for pam tracing 156 * 157 * turn on PAM debug if "magic" file exists 158 * if exists (original), pam_debug = PAM_DEBUG_DEFAULT, 159 * log_priority = LOG_DEBUG(7) and log_facility = LOG_AUTH(4). 160 * 161 * if has contents, keywork=value pairs: 162 * 163 * "log_priority=" 0-7, the pam_trace syslog priority to use 164 * (see sys/syslog.h) 165 * "log_facility=" 0-23, the pam_trace syslog facility to use 166 * (see sys/syslog.h) 167 * "debug_flags=" PAM_DEBUG_DEFAULT (0x0001), log traditional 168 * (original) debugging. 169 * Plus the logical or of: 170 * PAM_DEBUG_ITEM (0x0002), log item values and 171 * pam_get_item. 172 * PAM_DEBUG_MODULE (0x0004), log module return status. 173 * PAM_DEBUG_CONF (0x0008), log pam.conf parsing. 174 * PAM_DEBUG_DATA (0x0010), get/set_data. 175 * PAM_DEBUG_CONV (0x0020), conversation/response. 176 * 177 * If compiled with DEBUG: 178 * PAM_DEBUG_AUTHTOK (0x8000), display AUTHTOK value if 179 * PAM_DEBUG_ITEM is set and results from 180 * PAM_PROMPT_ECHO_OFF responses. 181 * USE CAREFULLY, THIS EXPOSES THE USER'S PASSWORDS. 182 * 183 * or set to 0 and off even if PAM_DEBUG file exists. 184 * 185 * Output has the general form: 186 * <whatever was set syslog> PAM[<pid>]: <interface>(<handle> and other info) 187 * <whatever was set syslog> PAM[<pid>]: details requested for <interface> call 188 * Where: <pid> is the process ID of the calling process. 189 * <handle> is the Hex value of the pam_handle associated with the 190 * call. 191 */ 192 193 static void 194 pam_settrace() 195 { 196 void *defp; 197 198 if ((defp = defopen_r(PAM_DEBUG)) != NULL) { 199 char *arg; 200 int code; 201 int facility = LOG_AUTH; 202 203 pam_debug = PAM_DEBUG_DEFAULT; 204 log_priority = LOG_DEBUG; 205 206 (void) defcntl_r(DC_SETFLAGS, DC_CASE, defp); 207 if ((arg = defread_r(LOG_PRIORITY, defp)) != NULL) { 208 code = (int)strtol(arg, NULL, 10); 209 if ((code & ~LOG_PRIMASK) == 0) { 210 log_priority = code; 211 } 212 } 213 if ((arg = defread_r(LOG_FACILITY, defp)) != NULL) { 214 code = (int)strtol(arg, NULL, 10); 215 if (code < LOG_NFACILITIES) { 216 facility = code << 3; 217 } 218 } 219 if ((arg = defread_r(DEBUG_FLAGS, defp)) != NULL) { 220 pam_debug = (int)strtol(arg, NULL, 0); 221 } 222 defclose_r(defp); 223 224 log_priority |= facility; 225 } 226 } 227 228 /* 229 * pam_trace - logs tracing messages 230 * 231 * flag = debug_flags from /etc/pam_debug 232 * format and args = message to print (PAM[<pid>]: is prepended). 233 * 234 * global log_priority = pam_trace syslog (log_priority | log_facility) 235 * from /etc/pam_debug 236 */ 237 /*PRINTFLIKE2*/ 238 static void 239 pam_trace(int flag, char *format, ...) 240 { 241 va_list args; 242 char message[1024]; 243 int savemask; 244 245 if ((pam_debug & flag) == 0) 246 return; 247 248 savemask = setlogmask(LOG_MASK(log_priority & LOG_PRIMASK)); 249 (void) snprintf(message, sizeof (message), "PAM[%ld]: %s", 250 (long)getpid(), format); 251 va_start(args, format); 252 (void) vsyslog(log_priority, message, args); 253 va_end(args); 254 (void) setlogmask(savemask); 255 } 256 257 /* 258 * __pam_log - logs PAM syslog messages 259 * 260 * priority = message priority 261 * format and args = message to log 262 */ 263 /*PRINTFLIKE2*/ 264 void 265 __pam_log(int priority, const char *format, ...) 266 { 267 va_list args; 268 int savemask = setlogmask(LOG_MASK(priority & LOG_PRIMASK)); 269 270 va_start(args, format); 271 (void) vsyslog(priority, format, args); 272 va_end(args); 273 (void) setlogmask(savemask); 274 } 275 276 277 /* 278 * pam_XXXXX routines 279 * 280 * These are the entry points to the authentication switch 281 */ 282 283 /* 284 * pam_start - initiate an authentication transaction and 285 * set parameter values to be used during the 286 * transaction 287 */ 288 289 int 290 pam_start(const char *service, const char *user, 291 const struct pam_conv *pam_conv, pam_handle_t **pamh) 292 { 293 int err; 294 295 *pamh = calloc(1, sizeof (struct pam_handle)); 296 297 pam_settrace(); 298 pam_trace(PAM_DEBUG_DEFAULT, 299 "pam_start(%s,%s,%p:%p) - debug = %x", 300 service ? service : "NULL", user ? user : "NULL", (void *)pam_conv, 301 (void *)*pamh, pam_debug); 302 303 if (*pamh == NULL) 304 return (PAM_BUF_ERR); 305 306 (*pamh)->pam_inmodule = RO_OK; /* OK to set RO items */ 307 if ((err = pam_set_item(*pamh, PAM_SERVICE, (void *)service)) 308 != PAM_SUCCESS) { 309 clean_up(*pamh); 310 *pamh = NULL; 311 return (err); 312 } 313 314 if ((err = pam_set_item(*pamh, PAM_USER, (void *)user)) 315 != PAM_SUCCESS) { 316 clean_up(*pamh); 317 *pamh = NULL; 318 return (err); 319 } 320 321 if ((err = pam_set_item(*pamh, PAM_CONV, (void *)pam_conv)) 322 != PAM_SUCCESS) { 323 clean_up(*pamh); 324 *pamh = NULL; 325 return (err); 326 } 327 328 (*pamh)->pam_inmodule = RW_OK; 329 return (PAM_SUCCESS); 330 } 331 332 /* 333 * pam_end - terminate an authentication transaction 334 */ 335 336 int 337 pam_end(pam_handle_t *pamh, int pam_status) 338 { 339 struct pam_module_data *psd, *p; 340 fd_list *expired; 341 fd_list *traverse; 342 env_list *env_expired; 343 env_list *env_traverse; 344 345 pam_trace(PAM_DEBUG_DEFAULT, 346 "pam_end(%p): status = %s", (void *)pamh, 347 pam_strerror(pamh, pam_status)); 348 349 if (pamh == NULL) 350 return (PAM_SYSTEM_ERR); 351 352 /* call the cleanup routines for module specific data */ 353 354 psd = pamh->ssd; 355 while (psd) { 356 if (psd->cleanup) { 357 psd->cleanup(pamh, psd->data, pam_status); 358 } 359 p = psd; 360 psd = p->next; 361 free(p->module_data_name); 362 free(p); 363 } 364 pamh->ssd = NULL; 365 366 /* dlclose all module fds */ 367 traverse = pamh->fd; 368 while (traverse) { 369 expired = traverse; 370 traverse = traverse->next; 371 (void) dlclose(expired->mh); 372 free(expired); 373 } 374 pamh->fd = 0; 375 376 /* remove all environment variables */ 377 env_traverse = pamh->pam_env; 378 while (env_traverse) { 379 env_expired = env_traverse; 380 env_traverse = env_traverse->next; 381 free_env(env_expired); 382 } 383 384 clean_up(pamh); 385 return (PAM_SUCCESS); 386 } 387 388 /* 389 * pam_set_item - set the value of a parameter that can be 390 * retrieved via a call to pam_get_item() 391 */ 392 393 int 394 pam_set_item(pam_handle_t *pamh, int item_type, const void *item) 395 { 396 struct pam_item *pip; 397 int size; 398 char iname_buf[PAM_MAX_MSG_SIZE]; 399 400 if (((pam_debug & PAM_DEBUG_ITEM) == 0) || (pamh == NULL)) { 401 pam_trace(PAM_DEBUG_DEFAULT, 402 "pam_set_item(%p:%s)", (void *)pamh, 403 pam_trace_iname(item_type, iname_buf)); 404 } 405 406 if (pamh == NULL) 407 return (PAM_SYSTEM_ERR); 408 409 /* check read only items */ 410 if ((item_type == PAM_SERVICE) && (pamh->pam_inmodule != RO_OK)) 411 return (PAM_PERM_DENIED); 412 413 /* 414 * Check that item_type is within valid range 415 */ 416 417 if (item_type <= 0 || item_type >= PAM_MAX_ITEMS) 418 return (PAM_SYMBOL_ERR); 419 420 pip = &(pamh->ps_item[item_type]); 421 422 switch (item_type) { 423 case PAM_AUTHTOK: 424 case PAM_OLDAUTHTOK: 425 if (pip->pi_addr != NULL) 426 (void) memset(pip->pi_addr, 0, pip->pi_size); 427 /*FALLTHROUGH*/ 428 case PAM_SERVICE: 429 case PAM_USER: 430 case PAM_TTY: 431 case PAM_RHOST: 432 case PAM_RUSER: 433 case PAM_USER_PROMPT: 434 case PAM_RESOURCE: 435 case PAM_AUSER: 436 if (pip->pi_addr != NULL) { 437 free(pip->pi_addr); 438 } 439 440 if (item == NULL) { 441 pip->pi_addr = NULL; 442 pip->pi_size = 0; 443 } else { 444 pip->pi_addr = strdup((char *)item); 445 if (pip->pi_addr == NULL) { 446 pip->pi_size = 0; 447 return (PAM_BUF_ERR); 448 } 449 pip->pi_size = strlen(pip->pi_addr); 450 } 451 break; 452 case PAM_CONV: 453 if (pip->pi_addr != NULL) 454 free(pip->pi_addr); 455 size = sizeof (struct pam_conv); 456 if ((pip->pi_addr = calloc(1, size)) == NULL) 457 return (PAM_BUF_ERR); 458 if (item != NULL) 459 (void) memcpy(pip->pi_addr, item, (unsigned int) size); 460 else 461 (void) memset(pip->pi_addr, 0, size); 462 pip->pi_size = size; 463 break; 464 case PAM_REPOSITORY: 465 if (pip->pi_addr != NULL) { 466 pam_repository_t *auth_rep; 467 468 auth_rep = (pam_repository_t *)pip->pi_addr; 469 if (auth_rep->type != NULL) 470 free(auth_rep->type); 471 if (auth_rep->scope != NULL) 472 free(auth_rep->scope); 473 free(auth_rep); 474 } 475 if (item != NULL) { 476 pam_repository_t *s, *d; 477 478 size = sizeof (struct pam_repository); 479 pip->pi_addr = calloc(1, size); 480 if (pip->pi_addr == NULL) 481 return (PAM_BUF_ERR); 482 483 s = (struct pam_repository *)item; 484 d = (struct pam_repository *)pip->pi_addr; 485 486 d->type = strdup(s->type); 487 if (d->type == NULL) 488 return (PAM_BUF_ERR); 489 d->scope = malloc(s->scope_len); 490 if (d->scope == NULL) 491 return (PAM_BUF_ERR); 492 (void) memcpy(d->scope, s->scope, s->scope_len); 493 d->scope_len = s->scope_len; 494 } 495 pip->pi_size = size; 496 break; 497 default: 498 return (PAM_SYMBOL_ERR); 499 } 500 switch (item_type) { 501 case PAM_CONV: 502 pam_trace(PAM_DEBUG_ITEM, "pam_set_item(%p:%s)=%p", 503 (void *)pamh, 504 pam_trace_iname(item_type, iname_buf), 505 item ? (void *)((struct pam_conv *)item)->conv : 506 (void *)0); 507 break; 508 case PAM_REPOSITORY: 509 pam_trace(PAM_DEBUG_ITEM, "pam_set_item(%p:%s)=%s", 510 (void *)pamh, 511 pam_trace_iname(item_type, iname_buf), 512 item ? (((struct pam_repository *)item)->type ? 513 ((struct pam_repository *)item)->type : "NULL") : 514 "NULL"); 515 break; 516 case PAM_AUTHTOK: 517 case PAM_OLDAUTHTOK: 518 #ifdef DEBUG 519 if (pam_debug & PAM_DEBUG_AUTHTOK) 520 pam_trace(PAM_DEBUG_ITEM, 521 "pam_set_item(%p:%s)=%s", (void *)pamh, 522 pam_trace_iname(item_type, iname_buf), 523 item ? (char *)item : "NULL"); 524 else 525 #endif /* DEBUG */ 526 pam_trace(PAM_DEBUG_ITEM, 527 "pam_set_item(%p:%s)=%s", (void *)pamh, 528 pam_trace_iname(item_type, iname_buf), 529 item ? "********" : "NULL"); 530 break; 531 default: 532 pam_trace(PAM_DEBUG_ITEM, "pam_set_item(%p:%s)=%s", 533 (void *)pamh, 534 pam_trace_iname(item_type, iname_buf), 535 item ? (char *)item : "NULL"); 536 } 537 538 return (PAM_SUCCESS); 539 } 540 541 /* 542 * pam_get_item - read the value of a parameter specified in 543 * the call to pam_set_item() 544 */ 545 546 int 547 pam_get_item(const pam_handle_t *pamh, int item_type, void **item) 548 { 549 struct pam_item *pip; 550 char iname_buf[PAM_MAX_MSG_SIZE]; 551 552 if (((pam_debug & PAM_DEBUG_ITEM) == 0) || (pamh == NULL)) { 553 pam_trace(PAM_DEBUG_ITEM, "pam_get_item(%p:%s)", 554 (void *)pamh, pam_trace_iname(item_type, iname_buf)); 555 } 556 557 if (pamh == NULL) 558 return (PAM_SYSTEM_ERR); 559 560 if (item_type <= 0 || item_type >= PAM_MAX_ITEMS) 561 return (PAM_SYMBOL_ERR); 562 563 if ((pamh->pam_inmodule != WO_OK) && 564 ((item_type == PAM_AUTHTOK || item_type == PAM_OLDAUTHTOK))) { 565 __pam_log(LOG_AUTH | LOG_NOTICE, "pam_get_item(%s) called from " 566 "a non module context", 567 pam_trace_iname(item_type, iname_buf)); 568 return (PAM_PERM_DENIED); 569 } 570 571 pip = (struct pam_item *)&(pamh->ps_item[item_type]); 572 573 *item = pip->pi_addr; 574 switch (item_type) { 575 case PAM_CONV: 576 pam_trace(PAM_DEBUG_ITEM, "pam_get_item(%p:%s)=%p", 577 (void *)pamh, 578 pam_trace_iname(item_type, iname_buf), 579 (void *)((struct pam_conv *)*item)->conv); 580 break; 581 case PAM_REPOSITORY: 582 pam_trace(PAM_DEBUG_ITEM, "pam_get_item(%p:%s)=%s", 583 (void *)pamh, 584 pam_trace_iname(item_type, iname_buf), 585 *item ? (((struct pam_repository *)*item)->type ? 586 ((struct pam_repository *)*item)->type : "NULL") : 587 "NULL"); 588 break; 589 case PAM_AUTHTOK: 590 case PAM_OLDAUTHTOK: 591 #ifdef DEBUG 592 if (pam_debug & PAM_DEBUG_AUTHTOK) 593 pam_trace(PAM_DEBUG_ITEM, 594 "pam_get_item(%p:%s)=%s", (void *)pamh, 595 pam_trace_iname(item_type, iname_buf), 596 *item ? *(char **)item : "NULL"); 597 else 598 #endif /* DEBUG */ 599 pam_trace(PAM_DEBUG_ITEM, 600 "pam_get_item(%p:%s)=%s", (void *)pamh, 601 pam_trace_iname(item_type, iname_buf), 602 *item ? "********" : "NULL"); 603 break; 604 default: 605 pam_trace(PAM_DEBUG_ITEM, "pam_get_item(%p:%s)=%s", 606 (void *)pamh, 607 pam_trace_iname(item_type, iname_buf), 608 *item ? *(char **)item : "NULL"); 609 } 610 611 return (PAM_SUCCESS); 612 } 613 614 /* 615 * parse_user_name - process the user response: ignore 616 * '\t' or ' ' before or after a user name. 617 * user_input is a null terminated string. 618 * *ret_username will be the user name. 619 */ 620 621 static int 622 parse_user_name(char *user_input, char **ret_username) 623 { 624 register char *ptr; 625 register int index = 0; 626 char username[PAM_MAX_RESP_SIZE]; 627 628 /* Set the default value for *ret_username */ 629 *ret_username = NULL; 630 631 /* 632 * Set the initial value for username - this is a buffer holds 633 * the user name. 634 */ 635 bzero((void *)username, PAM_MAX_RESP_SIZE); 636 637 /* 638 * The user_input is guaranteed to be terminated by a null character. 639 */ 640 ptr = user_input; 641 642 /* Skip all the leading whitespaces if there are any. */ 643 while ((*ptr == ' ') || (*ptr == '\t')) 644 ptr++; 645 646 if (*ptr == '\0') { 647 /* 648 * We should never get here since the user_input we got 649 * in pam_get_user() is not all whitespaces nor just "\0". 650 */ 651 return (PAM_BUF_ERR); 652 } 653 654 /* 655 * username will be the first string we get from user_input 656 * - we skip leading whitespaces and ignore trailing whitespaces 657 */ 658 while (*ptr != '\0') { 659 if ((*ptr == ' ') || (*ptr == '\t') || 660 (index >= PAM_MAX_RESP_SIZE)) { 661 break; 662 } else { 663 username[index] = *ptr; 664 index++; 665 ptr++; 666 } 667 } 668 669 /* ret_username will be freed in pam_get_user(). */ 670 if (index >= PAM_MAX_RESP_SIZE || 671 (*ret_username = strdup(username)) == NULL) 672 return (PAM_BUF_ERR); 673 return (PAM_SUCCESS); 674 } 675 676 /* 677 * Get the value of PAM_USER. If not set, then use the convenience function 678 * to prompt for the user. Use prompt if specified, else use PAM_USER_PROMPT 679 * if it is set, else use default. 680 */ 681 #define WHITESPACE 0 682 #define USERNAME 1 683 684 int 685 pam_get_user(pam_handle_t *pamh, char **user, const char *prompt_override) 686 { 687 int status; 688 char *prompt = NULL; 689 char *real_username; 690 struct pam_response *ret_resp = NULL; 691 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; 692 693 pam_trace(PAM_DEBUG_DEFAULT, 694 "pam_get_user(%p, %p, %s)", (void *)pamh, (void *)*user, 695 prompt_override ? prompt_override : "NULL"); 696 if (pamh == NULL) 697 return (PAM_SYSTEM_ERR); 698 699 if ((status = pam_get_item(pamh, PAM_USER, (void **)user)) 700 != PAM_SUCCESS) { 701 return (status); 702 } 703 704 /* if the user is set, return it */ 705 706 if (*user != NULL && *user[0] != '\0') { 707 return (PAM_SUCCESS); 708 } 709 710 /* 711 * if the module is requesting a special prompt, use it. 712 * else use PAM_USER_PROMPT. 713 */ 714 715 if (prompt_override != NULL) { 716 prompt = (char *)prompt_override; 717 } else { 718 status = pam_get_item(pamh, PAM_USER_PROMPT, (void**)&prompt); 719 if (status != PAM_SUCCESS) { 720 return (status); 721 } 722 } 723 724 /* if the prompt is not set, use default */ 725 726 if (prompt == NULL || prompt[0] == '\0') { 727 prompt = dgettext(TEXT_DOMAIN, "Please enter user name: "); 728 } 729 730 /* prompt for the user */ 731 732 (void) strncpy(messages[0], prompt, sizeof (messages[0])); 733 734 for (;;) { 735 int state = WHITESPACE; 736 737 status = do_conv(pamh, PAM_PROMPT_ECHO_ON, 1, messages, 738 NULL, &ret_resp); 739 740 if (status != PAM_SUCCESS) { 741 return (status); 742 } 743 744 if (ret_resp->resp && ret_resp->resp[0] != '\0') { 745 int len = strlen(ret_resp->resp); 746 int i; 747 748 for (i = 0; i < len; i++) { 749 if ((ret_resp->resp[i] != ' ') && 750 (ret_resp->resp[i] != '\t')) { 751 state = USERNAME; 752 break; 753 } 754 } 755 756 if (state == USERNAME) 757 break; 758 } 759 /* essentially empty response, try again */ 760 free_resp(1, ret_resp); 761 ret_resp = NULL; 762 } 763 764 /* set PAM_USER */ 765 /* Parse the user input to get the user name. */ 766 status = parse_user_name(ret_resp->resp, &real_username); 767 768 if (status != PAM_SUCCESS) { 769 if (real_username != NULL) 770 free(real_username); 771 free_resp(1, ret_resp); 772 return (status); 773 } 774 775 status = pam_set_item(pamh, PAM_USER, real_username); 776 777 free(real_username); 778 779 free_resp(1, ret_resp); 780 if (status != PAM_SUCCESS) { 781 return (status); 782 } 783 784 /* 785 * finally, get PAM_USER. We have to call pam_get_item to get 786 * the value of user because pam_set_item mallocs the memory. 787 */ 788 789 status = pam_get_item(pamh, PAM_USER, (void**)user); 790 return (status); 791 } 792 793 /* 794 * Set module specific data 795 */ 796 797 int 798 pam_set_data(pam_handle_t *pamh, const char *module_data_name, void *data, 799 void (*cleanup)(pam_handle_t *pamh, void *data, int pam_end_status)) 800 { 801 struct pam_module_data *psd; 802 803 pam_trace(PAM_DEBUG_DATA, 804 "pam_set_data(%p:%s:%d)=%p", (void *)pamh, 805 (module_data_name != NULL) ? module_data_name : "NULL", 806 (pamh != NULL) ? pamh->pam_inmodule : -1, data); 807 if (pamh == NULL || (pamh->pam_inmodule != WO_OK) || 808 module_data_name == NULL) { 809 return (PAM_SYSTEM_ERR); 810 } 811 812 /* check if module data already exists */ 813 814 for (psd = pamh->ssd; psd; psd = psd->next) { 815 if (strcmp(psd->module_data_name, module_data_name) == 0) { 816 /* clean up original data before setting the new data */ 817 if (psd->cleanup) { 818 psd->cleanup(pamh, psd->data, PAM_SUCCESS); 819 } 820 psd->data = (void *)data; 821 psd->cleanup = cleanup; 822 return (PAM_SUCCESS); 823 } 824 } 825 826 psd = malloc(sizeof (struct pam_module_data)); 827 if (psd == NULL) 828 return (PAM_BUF_ERR); 829 830 psd->module_data_name = strdup(module_data_name); 831 if (psd->module_data_name == NULL) { 832 free(psd); 833 return (PAM_BUF_ERR); 834 } 835 836 psd->data = (void *)data; 837 psd->cleanup = cleanup; 838 psd->next = pamh->ssd; 839 pamh->ssd = psd; 840 return (PAM_SUCCESS); 841 } 842 843 /* 844 * get module specific data 845 */ 846 847 int 848 pam_get_data(const pam_handle_t *pamh, const char *module_data_name, 849 const void **data) 850 { 851 struct pam_module_data *psd; 852 853 if (pamh == NULL || (pamh->pam_inmodule != WO_OK) || 854 module_data_name == NULL) { 855 pam_trace(PAM_DEBUG_DATA, 856 "pam_get_data(%p:%s:%d)=%p", (void *)pamh, 857 module_data_name ? module_data_name : "NULL", 858 pamh->pam_inmodule, *data); 859 return (PAM_SYSTEM_ERR); 860 } 861 862 for (psd = pamh->ssd; psd; psd = psd->next) { 863 if (strcmp(psd->module_data_name, module_data_name) == 0) { 864 *data = psd->data; 865 pam_trace(PAM_DEBUG_DATA, 866 "pam_get_data(%p:%s)=%p", (void *)pamh, 867 module_data_name, *data); 868 return (PAM_SUCCESS); 869 } 870 } 871 pam_trace(PAM_DEBUG_DATA, 872 "pam_get_data(%p:%s)=%s", (void *)pamh, module_data_name, 873 "PAM_NO_MODULE_DATA"); 874 875 return (PAM_NO_MODULE_DATA); 876 } 877 878 /* 879 * PAM equivalent to strerror() 880 */ 881 /* ARGSUSED */ 882 const char * 883 pam_strerror(pam_handle_t *pamh, int errnum) 884 { 885 switch (errnum) { 886 case PAM_SUCCESS: 887 return (dgettext(TEXT_DOMAIN, "Success")); 888 case PAM_OPEN_ERR: 889 return (dgettext(TEXT_DOMAIN, "Dlopen failure")); 890 case PAM_SYMBOL_ERR: 891 return (dgettext(TEXT_DOMAIN, "Symbol not found")); 892 case PAM_SERVICE_ERR: 893 return (dgettext(TEXT_DOMAIN, 894 "Error in underlying service module")); 895 case PAM_SYSTEM_ERR: 896 return (dgettext(TEXT_DOMAIN, "System error")); 897 case PAM_BUF_ERR: 898 return (dgettext(TEXT_DOMAIN, "Memory buffer error")); 899 case PAM_CONV_ERR: 900 return (dgettext(TEXT_DOMAIN, "Conversation failure")); 901 case PAM_PERM_DENIED: 902 return (dgettext(TEXT_DOMAIN, "Permission denied")); 903 case PAM_MAXTRIES: 904 return (dgettext(TEXT_DOMAIN, 905 "Maximum number of attempts exceeded")); 906 case PAM_AUTH_ERR: 907 return (dgettext(TEXT_DOMAIN, "Authentication failed")); 908 case PAM_NEW_AUTHTOK_REQD: 909 return (dgettext(TEXT_DOMAIN, "Get new authentication token")); 910 case PAM_CRED_INSUFFICIENT: 911 return (dgettext(TEXT_DOMAIN, "Insufficient credentials")); 912 case PAM_AUTHINFO_UNAVAIL: 913 return (dgettext(TEXT_DOMAIN, 914 "Can not retrieve authentication info")); 915 case PAM_USER_UNKNOWN: 916 return (dgettext(TEXT_DOMAIN, "No account present for user")); 917 case PAM_CRED_UNAVAIL: 918 return (dgettext(TEXT_DOMAIN, 919 "Can not retrieve user credentials")); 920 case PAM_CRED_EXPIRED: 921 return (dgettext(TEXT_DOMAIN, 922 "User credentials have expired")); 923 case PAM_CRED_ERR: 924 return (dgettext(TEXT_DOMAIN, 925 "Failure setting user credentials")); 926 case PAM_ACCT_EXPIRED: 927 return (dgettext(TEXT_DOMAIN, "User account has expired")); 928 case PAM_AUTHTOK_EXPIRED: 929 return (dgettext(TEXT_DOMAIN, "User password has expired")); 930 case PAM_SESSION_ERR: 931 return (dgettext(TEXT_DOMAIN, 932 "Can not make/remove entry for session")); 933 case PAM_AUTHTOK_ERR: 934 return (dgettext(TEXT_DOMAIN, 935 "Authentication token manipulation error")); 936 case PAM_AUTHTOK_RECOVERY_ERR: 937 return (dgettext(TEXT_DOMAIN, 938 "Authentication token can not be recovered")); 939 case PAM_AUTHTOK_LOCK_BUSY: 940 return (dgettext(TEXT_DOMAIN, 941 "Authentication token lock busy")); 942 case PAM_AUTHTOK_DISABLE_AGING: 943 return (dgettext(TEXT_DOMAIN, 944 "Authentication token aging disabled")); 945 case PAM_NO_MODULE_DATA: 946 return (dgettext(TEXT_DOMAIN, 947 "Module specific data not found")); 948 case PAM_IGNORE: 949 return (dgettext(TEXT_DOMAIN, "Ignore module")); 950 case PAM_ABORT: 951 return (dgettext(TEXT_DOMAIN, "General PAM failure ")); 952 case PAM_TRY_AGAIN: 953 return (dgettext(TEXT_DOMAIN, 954 "Unable to complete operation. Try again")); 955 default: 956 return (dgettext(TEXT_DOMAIN, "Unknown error")); 957 } 958 } 959 960 static void * 961 sm_name(int ind) 962 { 963 switch (ind) { 964 case PAM_AUTHENTICATE: 965 return (PAM_SM_AUTHENTICATE); 966 case PAM_SETCRED: 967 return (PAM_SM_SETCRED); 968 case PAM_ACCT_MGMT: 969 return (PAM_SM_ACCT_MGMT); 970 case PAM_OPEN_SESSION: 971 return (PAM_SM_OPEN_SESSION); 972 case PAM_CLOSE_SESSION: 973 return (PAM_SM_CLOSE_SESSION); 974 case PAM_CHAUTHTOK: 975 return (PAM_SM_CHAUTHTOK); 976 } 977 return (NULL); 978 } 979 980 static int 981 (*func(pamtab_t *modulep, int ind))() 982 { 983 void *funcp; 984 985 if ((funcp = modulep->function_ptr) == NULL) 986 return (NULL); 987 988 switch (ind) { 989 case PAM_AUTHENTICATE: 990 return (((struct auth_module *)funcp)->pam_sm_authenticate); 991 case PAM_SETCRED: 992 return (((struct auth_module *)funcp)->pam_sm_setcred); 993 case PAM_ACCT_MGMT: 994 return (((struct account_module *)funcp)->pam_sm_acct_mgmt); 995 case PAM_OPEN_SESSION: 996 return (((struct session_module *)funcp)->pam_sm_open_session); 997 case PAM_CLOSE_SESSION: 998 return (((struct session_module *)funcp)->pam_sm_close_session); 999 case PAM_CHAUTHTOK: 1000 return (((struct password_module *)funcp)->pam_sm_chauthtok); 1001 } 1002 return (NULL); 1003 } 1004 1005 /* 1006 * Run through the PAM service module stack for the given module type. 1007 */ 1008 static int 1009 run_stack(pam_handle_t *pamh, int flags, int type, int def_err, int ind, 1010 char *function_name) 1011 { 1012 int err = PAM_SYSTEM_ERR; /* preset */ 1013 int optional_error = 0; 1014 int required_error = 0; 1015 int success = 0; 1016 pamtab_t *modulep; 1017 int (*sm_func)(); 1018 1019 if (pamh == NULL) 1020 return (PAM_SYSTEM_ERR); 1021 1022 /* read initial entries from pam.conf */ 1023 if ((err = read_pam_conf(pamh, PAM_CONFIG)) != PAM_SUCCESS) { 1024 return (err); 1025 } 1026 1027 if ((modulep = 1028 pamh->pam_conf_info[pamh->include_depth][type]) == NULL) { 1029 __pam_log(LOG_AUTH | LOG_ERR, "%s no initial module present", 1030 pam_trace_cname(pamh)); 1031 goto exit_return; 1032 } 1033 1034 pamh->pam_inmodule = WO_OK; /* OK to get AUTHTOK */ 1035 include: 1036 pam_trace(PAM_DEBUG_MODULE, 1037 "[%d:%s]:run_stack:%s(%p, %x): %s", pamh->include_depth, 1038 pam_trace_cname(pamh), function_name, (void *)pamh, flags, 1039 modulep ? modulep->module_path : "NULL"); 1040 1041 while (modulep != NULL) { 1042 if (modulep->pam_flag & PAM_INCLUDE) { 1043 /* save the return location */ 1044 pamh->pam_conf_modulep[pamh->include_depth] = 1045 modulep->next; 1046 pam_trace(PAM_DEBUG_MODULE, 1047 "setting for include[%d:%p]", 1048 pamh->include_depth, (void *)modulep->next); 1049 if (pamh->include_depth++ >= PAM_MAX_INCLUDE) { 1050 __pam_log(LOG_AUTH | LOG_ERR, 1051 "run_stack: includes too deep %d " 1052 "found trying to include %s from %s, %d " 1053 "allowed", pamh->include_depth, 1054 modulep->module_path, pamh->pam_conf_name 1055 [PAM_MAX_INCLUDE] == NULL ? "NULL" : 1056 pamh->pam_conf_name[PAM_MAX_INCLUDE], 1057 PAM_MAX_INCLUDE); 1058 goto exit_return; 1059 } 1060 if ((err = read_pam_conf(pamh, 1061 modulep->module_path)) != PAM_SUCCESS) { 1062 __pam_log(LOG_AUTH | LOG_ERR, 1063 "run_stack[%d:%s]: can't read included " 1064 "conf %s", pamh->include_depth, 1065 pam_trace_cname(pamh), 1066 modulep->module_path); 1067 goto exit_return; 1068 } 1069 if ((modulep = pamh->pam_conf_info 1070 [pamh->include_depth][type]) == NULL) { 1071 __pam_log(LOG_AUTH | LOG_ERR, 1072 "run_stack[%d:%s]: no include module " 1073 "present %s", pamh->include_depth, 1074 pam_trace_cname(pamh), function_name); 1075 goto exit_return; 1076 } 1077 if (modulep->pam_flag & PAM_INCLUDE) { 1078 /* first line another include */ 1079 goto include; 1080 } 1081 pam_trace(PAM_DEBUG_DEFAULT, "include[%d:%s]" 1082 "(%p, %s)=%s", pamh->include_depth, 1083 pam_trace_cname(pamh), (void *)pamh, 1084 function_name, modulep->module_path); 1085 if ((err = load_modules(pamh, type, sm_name(ind), 1086 pamh->pam_conf_info 1087 [pamh->include_depth][type])) != PAM_SUCCESS) { 1088 pam_trace(PAM_DEBUG_DEFAULT, 1089 "[%d:%s]:%s(%p, %x): load_modules failed", 1090 pamh->include_depth, pam_trace_cname(pamh), 1091 function_name, (void *)pamh, flags); 1092 goto exit_return; 1093 } 1094 if ((modulep = pamh->pam_conf_info 1095 [pamh->include_depth][type]) == NULL) { 1096 __pam_log(LOG_AUTH | LOG_ERR, 1097 "%s no initial module present", 1098 pam_trace_cname(pamh)); 1099 goto exit_return; 1100 } 1101 } else if ((err = load_modules(pamh, type, sm_name(ind), 1102 modulep)) != PAM_SUCCESS) { 1103 pam_trace(PAM_DEBUG_DEFAULT, 1104 "[%d:%s]:%s(%p, %x): load_modules failed", 1105 pamh->include_depth, pam_trace_cname(pamh), 1106 function_name, (void *)pamh, flags); 1107 goto exit_return; 1108 } /* PAM_INCLUDE */ 1109 sm_func = func(modulep, ind); 1110 if (sm_func) { 1111 err = sm_func(pamh, flags, modulep->module_argc, 1112 (const char **)modulep->module_argv); 1113 1114 pam_trace(PAM_DEBUG_MODULE, 1115 "[%d:%s]:%s(%p, %x): %s returned %s", 1116 pamh->include_depth, pam_trace_cname(pamh), 1117 function_name, (void *)pamh, flags, 1118 modulep->module_path, pam_strerror(pamh, err)); 1119 1120 switch (err) { 1121 case PAM_IGNORE: 1122 /* do nothing */ 1123 break; 1124 case PAM_SUCCESS: 1125 if ((modulep->pam_flag & PAM_SUFFI_BIND) && 1126 !required_error) { 1127 pamh->pam_inmodule = RW_OK; 1128 pam_trace(PAM_DEBUG_MODULE, 1129 "[%d:%s]:%s(%p, %x): %s: success", 1130 pamh->include_depth, 1131 pam_trace_cname(pamh), 1132 function_name, (void *)pamh, flags, 1133 (modulep->pam_flag & PAM_BINDING) ? 1134 PAM_BINDING_NAME : 1135 PAM_SUFFICIENT_NAME); 1136 goto exit_return; 1137 } 1138 success = 1; 1139 break; 1140 case PAM_TRY_AGAIN: 1141 /* 1142 * We need to return immediately, and 1143 * we shouldn't reset the AUTHTOK item 1144 * since it is not an error per-se. 1145 */ 1146 pamh->pam_inmodule = RW_OK; 1147 pam_trace(PAM_DEBUG_MODULE, 1148 "[%d:%s]:%s(%p, %x): TRY_AGAIN: %s", 1149 pamh->include_depth, pam_trace_cname(pamh), 1150 function_name, (void *)pamh, flags, 1151 pam_strerror(pamh, required_error ? 1152 required_error : err)); 1153 err = required_error ? required_error : err; 1154 goto exit_return; 1155 default: 1156 if (modulep->pam_flag & PAM_REQUISITE) { 1157 pamh->pam_inmodule = RW_OK; 1158 pam_trace(PAM_DEBUG_MODULE, 1159 "[%d:%s]:%s(%p, %x): requisite: %s", 1160 pamh->include_depth, 1161 pam_trace_cname(pamh), 1162 function_name, (void *)pamh, flags, 1163 pam_strerror(pamh, 1164 required_error ? required_error : 1165 err)); 1166 err = required_error ? 1167 required_error : err; 1168 goto exit_return; 1169 } else if (modulep->pam_flag & PAM_REQRD_BIND) { 1170 if (!required_error) 1171 required_error = err; 1172 } else { 1173 if (!optional_error) 1174 optional_error = err; 1175 } 1176 pam_trace(PAM_DEBUG_DEFAULT, 1177 "[%d:%s]:%s(%p, %x): error %s", 1178 pamh->include_depth, pam_trace_cname(pamh), 1179 function_name, (void *)pamh, flags, 1180 pam_strerror(pamh, err)); 1181 break; 1182 } 1183 } 1184 modulep = modulep->next; 1185 } 1186 1187 pam_trace(PAM_DEBUG_MODULE, "[%d:%s]:stack_end:%s(%p, %x): %s %s: %s", 1188 pamh->include_depth, pam_trace_cname(pamh), function_name, 1189 (void *)pamh, flags, pamh->include_depth ? "included" : "final", 1190 required_error ? "required" : success ? "success" : 1191 optional_error ? "optional" : "default", 1192 pam_strerror(pamh, required_error ? required_error : 1193 success ? PAM_SUCCESS : optional_error ? optional_error : def_err)); 1194 if (pamh->include_depth > 0) { 1195 free_pam_conf_info(pamh); 1196 pamh->include_depth--; 1197 /* continue at next entry */ 1198 modulep = pamh->pam_conf_modulep[pamh->include_depth]; 1199 pam_trace(PAM_DEBUG_MODULE, "looping for include[%d:%p]", 1200 pamh->include_depth, (void *)modulep); 1201 goto include; 1202 } 1203 free_pam_conf_info(pamh); 1204 pamh->pam_inmodule = RW_OK; 1205 if (required_error != 0) 1206 return (required_error); 1207 else if (success != 0) 1208 return (PAM_SUCCESS); 1209 else if (optional_error != 0) 1210 return (optional_error); 1211 else 1212 return (def_err); 1213 1214 exit_return: 1215 /* 1216 * All done at whatever depth we're at. 1217 * Go back to not having read /etc/pam.conf 1218 */ 1219 while (pamh->include_depth > 0) { 1220 free_pam_conf_info(pamh); 1221 pamh->include_depth--; 1222 } 1223 free_pam_conf_info(pamh); 1224 pamh->pam_inmodule = RW_OK; 1225 return (err); 1226 } 1227 1228 /* 1229 * pam_authenticate - authenticate a user 1230 */ 1231 1232 int 1233 pam_authenticate(pam_handle_t *pamh, int flags) 1234 { 1235 int retval; 1236 1237 retval = run_stack(pamh, flags, PAM_AUTH_MODULE, PAM_AUTH_ERR, 1238 PAM_AUTHENTICATE, "pam_authenticate"); 1239 1240 if (retval != PAM_SUCCESS) 1241 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 1242 return (retval); 1243 } 1244 1245 /* 1246 * pam_setcred - modify or retrieve user credentials 1247 */ 1248 1249 int 1250 pam_setcred(pam_handle_t *pamh, int flags) 1251 { 1252 int retval; 1253 1254 retval = run_stack(pamh, flags, PAM_AUTH_MODULE, PAM_CRED_ERR, 1255 PAM_SETCRED, "pam_setcred"); 1256 1257 if (retval != PAM_SUCCESS) 1258 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 1259 return (retval); 1260 } 1261 1262 /* 1263 * pam_acct_mgmt - check password aging, account expiration 1264 */ 1265 1266 int 1267 pam_acct_mgmt(pam_handle_t *pamh, int flags) 1268 { 1269 int retval; 1270 1271 retval = run_stack(pamh, flags, PAM_ACCOUNT_MODULE, PAM_ACCT_EXPIRED, 1272 PAM_ACCT_MGMT, "pam_acct_mgmt"); 1273 1274 if (retval != PAM_SUCCESS && 1275 retval != PAM_NEW_AUTHTOK_REQD) { 1276 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 1277 } 1278 return (retval); 1279 } 1280 1281 /* 1282 * pam_open_session - begin session management 1283 */ 1284 1285 int 1286 pam_open_session(pam_handle_t *pamh, int flags) 1287 { 1288 int retval; 1289 1290 retval = run_stack(pamh, flags, PAM_SESSION_MODULE, PAM_SESSION_ERR, 1291 PAM_OPEN_SESSION, "pam_open_session"); 1292 1293 if (retval != PAM_SUCCESS) 1294 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 1295 return (retval); 1296 } 1297 1298 /* 1299 * pam_close_session - terminate session management 1300 */ 1301 1302 int 1303 pam_close_session(pam_handle_t *pamh, int flags) 1304 { 1305 int retval; 1306 1307 retval = run_stack(pamh, flags, PAM_SESSION_MODULE, PAM_SESSION_ERR, 1308 PAM_CLOSE_SESSION, "pam_close_session"); 1309 1310 if (retval != PAM_SUCCESS) 1311 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 1312 return (retval); 1313 } 1314 1315 /* 1316 * pam_chauthtok - change user authentication token 1317 */ 1318 1319 int 1320 pam_chauthtok(pam_handle_t *pamh, int flags) 1321 { 1322 int retval; 1323 1324 /* do not let apps use PAM_PRELIM_CHECK or PAM_UPDATE_AUTHTOK */ 1325 if (flags & (PAM_PRELIM_CHECK | PAM_UPDATE_AUTHTOK)) { 1326 pam_trace(PAM_DEBUG_DEFAULT, 1327 "pam_chauthtok(%p, %x): %s", (void *)pamh, flags, 1328 pam_strerror(pamh, PAM_SYMBOL_ERR)); 1329 return (PAM_SYMBOL_ERR); 1330 } 1331 1332 /* 1st pass: PRELIM CHECK */ 1333 retval = run_stack(pamh, flags | PAM_PRELIM_CHECK, PAM_PASSWORD_MODULE, 1334 PAM_AUTHTOK_ERR, PAM_CHAUTHTOK, "pam_chauthtok-prelim"); 1335 1336 if (retval == PAM_TRY_AGAIN) 1337 return (retval); 1338 1339 if (retval != PAM_SUCCESS) { 1340 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 1341 return (retval); 1342 } 1343 1344 /* 2nd pass: UPDATE AUTHTOK */ 1345 retval = run_stack(pamh, flags | PAM_UPDATE_AUTHTOK, 1346 PAM_PASSWORD_MODULE, PAM_AUTHTOK_ERR, PAM_CHAUTHTOK, 1347 "pam_chauthtok-update"); 1348 1349 if (retval != PAM_SUCCESS) 1350 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 1351 1352 return (retval); 1353 } 1354 1355 /* 1356 * pam_putenv - add an environment variable to the PAM handle 1357 * if name_value == 'NAME=VALUE' then set variable to the value 1358 * if name_value == 'NAME=' then set variable to an empty value 1359 * if name_value == 'NAME' then delete the variable 1360 */ 1361 1362 int 1363 pam_putenv(pam_handle_t *pamh, const char *name_value) 1364 { 1365 int error = PAM_SYSTEM_ERR; 1366 char *equal_sign = 0; 1367 char *name = NULL, *value = NULL, *tmp_value = NULL; 1368 env_list *traverse, *trail; 1369 1370 pam_trace(PAM_DEBUG_DEFAULT, 1371 "pam_putenv(%p, %s)", (void *)pamh, 1372 name_value ? name_value : "NULL"); 1373 1374 if (pamh == NULL || name_value == NULL) 1375 goto out; 1376 1377 /* see if we were passed 'NAME=VALUE', 'NAME=', or 'NAME' */ 1378 if ((equal_sign = strchr(name_value, '=')) != 0) { 1379 if ((name = calloc(equal_sign - name_value + 1, 1380 sizeof (char))) == 0) { 1381 error = PAM_BUF_ERR; 1382 goto out; 1383 } 1384 (void) strncpy(name, name_value, equal_sign - name_value); 1385 if ((value = strdup(++equal_sign)) == 0) { 1386 error = PAM_BUF_ERR; 1387 goto out; 1388 } 1389 } else { 1390 if ((name = strdup(name_value)) == 0) { 1391 error = PAM_BUF_ERR; 1392 goto out; 1393 } 1394 } 1395 1396 /* check to see if we already have this variable in the PAM handle */ 1397 traverse = pamh->pam_env; 1398 trail = traverse; 1399 while (traverse && strncmp(traverse->name, name, strlen(name))) { 1400 trail = traverse; 1401 traverse = traverse->next; 1402 } 1403 1404 if (traverse) { 1405 /* found a match */ 1406 if (value == 0) { 1407 /* remove the env variable */ 1408 if (pamh->pam_env == traverse) 1409 pamh->pam_env = traverse->next; 1410 else 1411 trail->next = traverse->next; 1412 free_env(traverse); 1413 } else if (strlen(value) == 0) { 1414 /* set env variable to empty value */ 1415 if ((tmp_value = strdup("")) == 0) { 1416 error = PAM_SYSTEM_ERR; 1417 goto out; 1418 } 1419 free(traverse->value); 1420 traverse->value = tmp_value; 1421 } else { 1422 /* set the new value */ 1423 if ((tmp_value = strdup(value)) == 0) { 1424 error = PAM_SYSTEM_ERR; 1425 goto out; 1426 } 1427 free(traverse->value); 1428 traverse->value = tmp_value; 1429 } 1430 1431 } else if (traverse == 0 && value) { 1432 /* 1433 * could not find a match in the PAM handle. 1434 * add the new value if there is one 1435 */ 1436 if ((traverse = calloc(1, sizeof (env_list))) == 0) { 1437 error = PAM_BUF_ERR; 1438 goto out; 1439 } 1440 if ((traverse->name = strdup(name)) == 0) { 1441 free_env(traverse); 1442 error = PAM_BUF_ERR; 1443 goto out; 1444 } 1445 if ((traverse->value = strdup(value)) == 0) { 1446 free_env(traverse); 1447 error = PAM_BUF_ERR; 1448 goto out; 1449 } 1450 if (trail == 0) { 1451 /* new head of list */ 1452 pamh->pam_env = traverse; 1453 } else { 1454 /* adding to end of list */ 1455 trail->next = traverse; 1456 } 1457 } 1458 1459 error = PAM_SUCCESS; 1460 out: 1461 if (error != PAM_SUCCESS) { 1462 if (traverse) { 1463 if (traverse->name) 1464 free(traverse->name); 1465 if (traverse->value) 1466 free(traverse->value); 1467 free(traverse); 1468 } 1469 } 1470 if (name) 1471 free(name); 1472 if (value) 1473 free(value); 1474 return (error); 1475 } 1476 1477 /* 1478 * pam_getenv - retrieve an environment variable from the PAM handle 1479 */ 1480 char * 1481 pam_getenv(pam_handle_t *pamh, const char *name) 1482 { 1483 int error = PAM_SYSTEM_ERR; 1484 env_list *traverse; 1485 1486 pam_trace(PAM_DEBUG_DEFAULT, 1487 "pam_getenv(%p, %p)", (void *)pamh, (void *)name); 1488 1489 if (pamh == NULL || name == NULL) 1490 goto out; 1491 1492 /* check to see if we already have this variable in the PAM handle */ 1493 traverse = pamh->pam_env; 1494 while (traverse && strncmp(traverse->name, name, strlen(name))) { 1495 traverse = traverse->next; 1496 } 1497 error = (traverse ? PAM_SUCCESS : PAM_SYSTEM_ERR); 1498 pam_trace(PAM_DEBUG_DEFAULT, 1499 "pam_getenv(%p, %s)=%s", (void *)pamh, name, 1500 traverse ? traverse->value : "NULL"); 1501 out: 1502 return (error ? NULL : strdup(traverse->value)); 1503 } 1504 1505 /* 1506 * pam_getenvlist - retrieve all environment variables from the PAM handle 1507 * in a NULL terminated array. On error, return NULL. 1508 */ 1509 char ** 1510 pam_getenvlist(pam_handle_t *pamh) 1511 { 1512 int error = PAM_SYSTEM_ERR; 1513 char **list = 0; 1514 int length = 0; 1515 env_list *traverse; 1516 char *tenv; 1517 size_t tenv_size; 1518 1519 pam_trace(PAM_DEBUG_DEFAULT, 1520 "pam_getenvlist(%p)", (void *)pamh); 1521 1522 if (pamh == NULL) 1523 goto out; 1524 1525 /* find out how many environment variables we have */ 1526 traverse = pamh->pam_env; 1527 while (traverse) { 1528 length++; 1529 traverse = traverse->next; 1530 } 1531 1532 /* allocate the array we will return to the caller */ 1533 if ((list = calloc(length + 1, sizeof (char *))) == NULL) { 1534 error = PAM_BUF_ERR; 1535 goto out; 1536 } 1537 1538 /* add the variables one by one */ 1539 length = 0; 1540 traverse = pamh->pam_env; 1541 while (traverse != NULL) { 1542 tenv_size = strlen(traverse->name) + 1543 strlen(traverse->value) + 2; /* name=val\0 */ 1544 if ((tenv = malloc(tenv_size)) == NULL) { 1545 error = PAM_BUF_ERR; 1546 goto out; 1547 } 1548 /*LINTED*/ 1549 (void) sprintf(tenv, "%s=%s", traverse->name, traverse->value); 1550 list[length++] = tenv; 1551 traverse = traverse->next; 1552 } 1553 list[length] = NULL; 1554 1555 error = PAM_SUCCESS; 1556 out: 1557 if (error != PAM_SUCCESS) { 1558 /* free the partially constructed list */ 1559 if (list) { 1560 length = 0; 1561 while (list[length] != NULL) { 1562 free(list[length]); 1563 length++; 1564 } 1565 free(list); 1566 } 1567 } 1568 return (error ? NULL : list); 1569 } 1570 1571 /* 1572 * Routines to load a requested module on demand 1573 */ 1574 1575 /* 1576 * load_modules - load the requested module. 1577 * if the dlopen or dlsym fail, then 1578 * the module is ignored. 1579 */ 1580 1581 static int 1582 load_modules(pam_handle_t *pamh, int type, char *function_name, 1583 pamtab_t *pam_entry) 1584 { 1585 void *mh; 1586 struct auth_module *authp; 1587 struct account_module *accountp; 1588 struct session_module *sessionp; 1589 struct password_module *passwdp; 1590 int loading_functions = 0; /* are we currently loading functions? */ 1591 1592 pam_trace(PAM_DEBUG_MODULE, "load_modules[%d:%s](%p, %s)=%s:%s", 1593 pamh->include_depth, pam_trace_cname(pamh), (void *)pamh, 1594 function_name, pam_trace_fname(pam_entry->pam_flag), 1595 pam_entry->module_path); 1596 1597 while (pam_entry != NULL) { 1598 pam_trace(PAM_DEBUG_DEFAULT, 1599 "while load_modules[%d:%s](%p, %s)=%s", 1600 pamh->include_depth, pam_trace_cname(pamh), (void *)pamh, 1601 function_name, pam_entry->module_path); 1602 1603 if (pam_entry->pam_flag & PAM_INCLUDE) { 1604 pam_trace(PAM_DEBUG_DEFAULT, 1605 "done load_modules[%d:%s](%p, %s)=%s", 1606 pamh->include_depth, pam_trace_cname(pamh), 1607 (void *)pamh, function_name, 1608 pam_entry->module_path); 1609 return (PAM_SUCCESS); 1610 } 1611 switch (type) { 1612 case PAM_AUTH_MODULE: 1613 1614 /* if the function has already been loaded, return */ 1615 authp = pam_entry->function_ptr; 1616 if (!loading_functions && 1617 (((strcmp(function_name, PAM_SM_AUTHENTICATE) 1618 == 0) && authp && authp->pam_sm_authenticate) || 1619 ((strcmp(function_name, PAM_SM_SETCRED) == 0) && 1620 authp && authp->pam_sm_setcred))) { 1621 return (PAM_SUCCESS); 1622 } 1623 1624 /* function has not been loaded yet */ 1625 loading_functions = 1; 1626 if (authp == NULL) { 1627 authp = calloc(1, sizeof (struct auth_module)); 1628 if (authp == NULL) 1629 return (PAM_BUF_ERR); 1630 } 1631 1632 /* if open_module fails, return error */ 1633 if ((mh = open_module(pamh, 1634 pam_entry->module_path)) == NULL) { 1635 __pam_log(LOG_AUTH | LOG_ERR, 1636 "load_modules[%d:%s]: can not open module " 1637 "%s", pamh->include_depth, 1638 pam_trace_cname(pamh), 1639 pam_entry->module_path); 1640 free(authp); 1641 return (PAM_OPEN_ERR); 1642 } 1643 1644 /* load the authentication function */ 1645 if (strcmp(function_name, PAM_SM_AUTHENTICATE) == 0) { 1646 if (load_function(mh, PAM_SM_AUTHENTICATE, 1647 &authp->pam_sm_authenticate) 1648 != PAM_SUCCESS) { 1649 /* return error if dlsym fails */ 1650 free(authp); 1651 return (PAM_SYMBOL_ERR); 1652 } 1653 1654 /* load the setcred function */ 1655 } else if (strcmp(function_name, PAM_SM_SETCRED) == 0) { 1656 if (load_function(mh, PAM_SM_SETCRED, 1657 &authp->pam_sm_setcred) != PAM_SUCCESS) { 1658 /* return error if dlsym fails */ 1659 free(authp); 1660 return (PAM_SYMBOL_ERR); 1661 } 1662 } 1663 pam_entry->function_ptr = authp; 1664 break; 1665 case PAM_ACCOUNT_MODULE: 1666 accountp = pam_entry->function_ptr; 1667 if (!loading_functions && 1668 (strcmp(function_name, PAM_SM_ACCT_MGMT) == 0) && 1669 accountp && accountp->pam_sm_acct_mgmt) { 1670 return (PAM_SUCCESS); 1671 } 1672 1673 /* 1674 * If functions are added to the account module, 1675 * verify that one of the other functions hasn't 1676 * already loaded it. See PAM_AUTH_MODULE code. 1677 */ 1678 loading_functions = 1; 1679 accountp = calloc(1, sizeof (struct account_module)); 1680 if (accountp == NULL) 1681 return (PAM_BUF_ERR); 1682 1683 /* if open_module fails, return error */ 1684 if ((mh = open_module(pamh, 1685 pam_entry->module_path)) == NULL) { 1686 __pam_log(LOG_AUTH | LOG_ERR, 1687 "load_modules[%d:%s]: can not open module " 1688 "%s", pamh->include_depth, 1689 pam_trace_cname(pamh), 1690 pam_entry->module_path); 1691 free(accountp); 1692 return (PAM_OPEN_ERR); 1693 } 1694 1695 if (load_function(mh, PAM_SM_ACCT_MGMT, 1696 &accountp->pam_sm_acct_mgmt) != PAM_SUCCESS) { 1697 __pam_log(LOG_AUTH | LOG_ERR, 1698 "load_modules[%d:%s]: pam_sm_acct_mgmt() " 1699 "missing", pamh->include_depth, 1700 pam_trace_cname(pamh)); 1701 free(accountp); 1702 return (PAM_SYMBOL_ERR); 1703 } 1704 pam_entry->function_ptr = accountp; 1705 break; 1706 case PAM_SESSION_MODULE: 1707 sessionp = pam_entry->function_ptr; 1708 if (!loading_functions && 1709 (((strcmp(function_name, 1710 PAM_SM_OPEN_SESSION) == 0) && 1711 sessionp && sessionp->pam_sm_open_session) || 1712 ((strcmp(function_name, 1713 PAM_SM_CLOSE_SESSION) == 0) && 1714 sessionp && sessionp->pam_sm_close_session))) { 1715 return (PAM_SUCCESS); 1716 } 1717 1718 loading_functions = 1; 1719 if (sessionp == NULL) { 1720 sessionp = calloc(1, 1721 sizeof (struct session_module)); 1722 if (sessionp == NULL) 1723 return (PAM_BUF_ERR); 1724 } 1725 1726 /* if open_module fails, return error */ 1727 if ((mh = open_module(pamh, 1728 pam_entry->module_path)) == NULL) { 1729 __pam_log(LOG_AUTH | LOG_ERR, 1730 "load_modules[%d:%s]: can not open module " 1731 "%s", pamh->include_depth, 1732 pam_trace_cname(pamh), 1733 pam_entry->module_path); 1734 free(sessionp); 1735 return (PAM_OPEN_ERR); 1736 } 1737 1738 if ((strcmp(function_name, PAM_SM_OPEN_SESSION) == 0) && 1739 load_function(mh, PAM_SM_OPEN_SESSION, 1740 &sessionp->pam_sm_open_session) != PAM_SUCCESS) { 1741 free(sessionp); 1742 return (PAM_SYMBOL_ERR); 1743 } else if ((strcmp(function_name, 1744 PAM_SM_CLOSE_SESSION) == 0) && 1745 load_function(mh, PAM_SM_CLOSE_SESSION, 1746 &sessionp->pam_sm_close_session) != PAM_SUCCESS) { 1747 free(sessionp); 1748 return (PAM_SYMBOL_ERR); 1749 } 1750 pam_entry->function_ptr = sessionp; 1751 break; 1752 case PAM_PASSWORD_MODULE: 1753 passwdp = pam_entry->function_ptr; 1754 if (!loading_functions && 1755 (strcmp(function_name, PAM_SM_CHAUTHTOK) == 0) && 1756 passwdp && passwdp->pam_sm_chauthtok) { 1757 return (PAM_SUCCESS); 1758 } 1759 1760 /* 1761 * If functions are added to the password module, 1762 * verify that one of the other functions hasn't 1763 * already loaded it. See PAM_AUTH_MODULE code. 1764 */ 1765 loading_functions = 1; 1766 passwdp = calloc(1, sizeof (struct password_module)); 1767 if (passwdp == NULL) 1768 return (PAM_BUF_ERR); 1769 1770 /* if open_module fails, continue */ 1771 if ((mh = open_module(pamh, 1772 pam_entry->module_path)) == NULL) { 1773 __pam_log(LOG_AUTH | LOG_ERR, 1774 "load_modules[%d:%s]: can not open module " 1775 "%s", pamh->include_depth, 1776 pam_trace_cname(pamh), 1777 pam_entry->module_path); 1778 free(passwdp); 1779 return (PAM_OPEN_ERR); 1780 } 1781 1782 if (load_function(mh, PAM_SM_CHAUTHTOK, 1783 &passwdp->pam_sm_chauthtok) != PAM_SUCCESS) { 1784 free(passwdp); 1785 return (PAM_SYMBOL_ERR); 1786 } 1787 pam_entry->function_ptr = passwdp; 1788 break; 1789 default: 1790 pam_trace(PAM_DEBUG_DEFAULT, 1791 "load_modules[%d:%s](%p, %s): unsupported type %d", 1792 pamh->include_depth, pam_trace_cname(pamh), 1793 (void *)pamh, function_name, type); 1794 break; 1795 } 1796 1797 pam_entry = pam_entry->next; 1798 } /* while */ 1799 1800 pam_trace(PAM_DEBUG_MODULE, "load_modules[%d:%s](%p, %s)=done", 1801 pamh->include_depth, pam_trace_cname(pamh), (void *)pamh, 1802 function_name); 1803 1804 return (PAM_SUCCESS); 1805 } 1806 1807 /* 1808 * open_module - Open the module first checking for 1809 * propers modes and ownerships on the file. 1810 */ 1811 1812 static void * 1813 open_module(pam_handle_t *pamh, char *module_so) 1814 { 1815 struct stat64 stb; 1816 char *errmsg; 1817 void *lfd; 1818 fd_list *module_fds = 0; 1819 fd_list *trail = 0; 1820 fd_list *traverse = 0; 1821 1822 /* Check the ownership and file modes */ 1823 if (stat64(module_so, &stb) < 0) { 1824 __pam_log(LOG_AUTH | LOG_ERR, 1825 "open_module[%d:%s]: stat(%s) failed: %s", 1826 pamh->include_depth, pam_trace_cname(pamh), module_so, 1827 strerror(errno)); 1828 return (NULL); 1829 } 1830 if (stb.st_uid != (uid_t)0) { 1831 __pam_log(LOG_AUTH | LOG_ALERT, 1832 "open_module[%d:%s]: Owner of the module %s is not root", 1833 pamh->include_depth, pam_trace_cname(pamh), module_so); 1834 return (NULL); 1835 } 1836 if (stb.st_mode & S_IWGRP) { 1837 __pam_log(LOG_AUTH | LOG_ALERT, 1838 "open_module[%d:%s]: module %s writable by group", 1839 pamh->include_depth, pam_trace_cname(pamh), module_so); 1840 return (NULL); 1841 } 1842 if (stb.st_mode & S_IWOTH) { 1843 __pam_log(LOG_AUTH | LOG_ALERT, 1844 "open_module[%d:%s]: module %s writable by world", 1845 pamh->include_depth, pam_trace_cname(pamh), module_so); 1846 return (NULL); 1847 } 1848 1849 /* 1850 * Perform the dlopen() 1851 */ 1852 lfd = (void *)dlopen(module_so, RTLD_LAZY); 1853 1854 if (lfd == NULL) { 1855 errmsg = dlerror(); 1856 __pam_log(LOG_AUTH | LOG_ERR, "open_module[%d:%s]: %s " 1857 "failed: %s", pamh->include_depth, pam_trace_cname(pamh), 1858 module_so, errmsg != NULL ? errmsg : "Unknown error"); 1859 return (NULL); 1860 } else { 1861 /* add this fd to the pam handle */ 1862 if ((module_fds = calloc(1, sizeof (fd_list))) == 0) { 1863 (void) dlclose(lfd); 1864 lfd = 0; 1865 return (NULL); 1866 } 1867 module_fds->mh = lfd; 1868 1869 if (pamh->fd == 0) { 1870 /* adding new head of list */ 1871 pamh->fd = module_fds; 1872 } else { 1873 /* appending to end of list */ 1874 traverse = pamh->fd; 1875 while (traverse) { 1876 trail = traverse; 1877 traverse = traverse->next; 1878 } 1879 trail->next = module_fds; 1880 } 1881 } 1882 1883 return (lfd); 1884 } 1885 1886 /* 1887 * load_function - call dlsym() to resolve the function address 1888 */ 1889 static int 1890 load_function(void *lfd, char *name, int (**func)()) 1891 { 1892 char *errmsg = NULL; 1893 1894 if (lfd == NULL) 1895 return (PAM_SYMBOL_ERR); 1896 1897 *func = (int (*)())dlsym(lfd, name); 1898 if (*func == NULL) { 1899 errmsg = dlerror(); 1900 __pam_log(LOG_AUTH | LOG_ERR, "dlsym failed %s: error %s", 1901 name, errmsg != NULL ? errmsg : "Unknown error"); 1902 return (PAM_SYMBOL_ERR); 1903 } 1904 1905 pam_trace(PAM_DEBUG_DEFAULT, 1906 "load_function: successful load of %s", name); 1907 return (PAM_SUCCESS); 1908 } 1909 1910 /* 1911 * Routines to read the pam.conf configuration file 1912 */ 1913 1914 /* 1915 * open_pam_conf - open the pam.conf config file 1916 */ 1917 1918 static int 1919 open_pam_conf(struct pam_fh **pam_fh, pam_handle_t *pamh, char *config) 1920 { 1921 struct stat64 stb; 1922 int fd; 1923 1924 if ((fd = open(config, O_RDONLY)) == -1) { 1925 __pam_log(LOG_AUTH | LOG_ALERT, 1926 "open_pam_conf[%d:%s]: open(%s) failed: %s", 1927 pamh->include_depth, pam_trace_cname(pamh), config, 1928 strerror(errno)); 1929 return (0); 1930 } 1931 /* Check the ownership and file modes */ 1932 if (fstat64(fd, &stb) < 0) { 1933 __pam_log(LOG_AUTH | LOG_ALERT, 1934 "open_pam_conf[%d:%s]: stat(%s) failed: %s", 1935 pamh->include_depth, pam_trace_cname(pamh), config, 1936 strerror(errno)); 1937 (void) close(fd); 1938 return (0); 1939 } 1940 if (stb.st_uid != (uid_t)0) { 1941 __pam_log(LOG_AUTH | LOG_ALERT, 1942 "open_pam_conf[%d:%s]: Owner of %s is not root", 1943 pamh->include_depth, pam_trace_cname(pamh), config); 1944 (void) close(fd); 1945 return (0); 1946 } 1947 if (stb.st_mode & S_IWGRP) { 1948 __pam_log(LOG_AUTH | LOG_ALERT, 1949 "open_pam_conf[%d:%s]: %s writable by group", 1950 pamh->include_depth, pam_trace_cname(pamh), config); 1951 (void) close(fd); 1952 return (0); 1953 } 1954 if (stb.st_mode & S_IWOTH) { 1955 __pam_log(LOG_AUTH | LOG_ALERT, 1956 "open_pam_conf[%d:%s]: %s writable by world", 1957 pamh->include_depth, pam_trace_cname(pamh), config); 1958 (void) close(fd); 1959 return (0); 1960 } 1961 if ((*pam_fh = calloc(1, sizeof (struct pam_fh))) == NULL) { 1962 (void) close(fd); 1963 return (0); 1964 } 1965 (*pam_fh)->fconfig = fd; 1966 (*pam_fh)->bufsize = (size_t)stb.st_size; 1967 if (((*pam_fh)->data = mmap(0, (*pam_fh)->bufsize, PROT_READ, 1968 MAP_PRIVATE, (*pam_fh)->fconfig, 0)) == MAP_FAILED) { 1969 (void) close(fd); 1970 free (*pam_fh); 1971 return (0); 1972 } 1973 (*pam_fh)->bufferp = (*pam_fh)->data; 1974 1975 return (1); 1976 } 1977 1978 /* 1979 * close_pam_conf - close pam.conf 1980 */ 1981 1982 static void 1983 close_pam_conf(struct pam_fh *pam_fh) 1984 { 1985 (void) munmap(pam_fh->data, pam_fh->bufsize); 1986 (void) close(pam_fh->fconfig); 1987 free(pam_fh); 1988 } 1989 1990 /* 1991 * read_pam_conf - read in each entry in pam.conf and store info 1992 * under the pam handle. 1993 */ 1994 1995 static int 1996 read_pam_conf(pam_handle_t *pamh, char *config) 1997 { 1998 struct pam_fh *pam_fh; 1999 pamtab_t *pamentp; 2000 pamtab_t *tpament; 2001 char *service; 2002 int error; 2003 int i = pamh->include_depth; /* include depth */ 2004 /* 2005 * service types: 2006 * error (-1), "auth" (0), "account" (1), "session" (2), "password" (3) 2007 */ 2008 int service_found[PAM_NUM_MODULE_TYPES+1] = {0, 0, 0, 0, 0}; 2009 2010 (void) pam_get_item(pamh, PAM_SERVICE, (void **)&service); 2011 if (service == NULL || *service == '\0') { 2012 __pam_log(LOG_AUTH | LOG_ERR, "No service name"); 2013 return (PAM_SYSTEM_ERR); 2014 } 2015 2016 pamh->pam_conf_name[i] = strdup(config); 2017 pam_trace(PAM_DEBUG_CONF, "read_pam_conf[%d:%s](%p) open(%s)", 2018 i, pam_trace_cname(pamh), (void *)pamh, config); 2019 if (open_pam_conf(&pam_fh, pamh, config) == 0) { 2020 return (PAM_SYSTEM_ERR); 2021 } 2022 2023 while ((error = 2024 get_pam_conf_entry(pam_fh, pamh, &pamentp)) == PAM_SUCCESS && 2025 pamentp) { 2026 2027 /* See if entry is this service and valid */ 2028 if (verify_pam_conf(pamentp, service)) { 2029 pam_trace(PAM_DEBUG_CONF, 2030 "read_pam_conf[%d:%s](%p): bad entry error %s", 2031 i, pam_trace_cname(pamh), (void *)pamh, service); 2032 2033 error = PAM_SYSTEM_ERR; 2034 free_pamconf(pamentp); 2035 goto out; 2036 } 2037 if (strcasecmp(pamentp->pam_service, service) == 0) { 2038 pam_trace(PAM_DEBUG_CONF, 2039 "read_pam_conf[%d:%s](%p): processing %s", 2040 i, pam_trace_cname(pamh), (void *)pamh, service); 2041 /* process first service entry */ 2042 if (service_found[pamentp->pam_type + 1] == 0) { 2043 /* purge "other" entries */ 2044 while ((tpament = pamh->pam_conf_info[i] 2045 [pamentp->pam_type]) != NULL) { 2046 pam_trace(PAM_DEBUG_CONF, 2047 "read_pam_conf(%p): purging " 2048 "\"other\"[%d:%s][%s]", 2049 (void *)pamh, i, 2050 pam_trace_cname(pamh), 2051 pam_snames[pamentp->pam_type]); 2052 pamh->pam_conf_info[i] 2053 [pamentp->pam_type] = tpament->next; 2054 free_pamconf(tpament); 2055 } 2056 /* add first service entry */ 2057 pam_trace(PAM_DEBUG_CONF, 2058 "read_pam_conf(%p): adding 1st " 2059 "%s[%d:%s][%s]", 2060 (void *)pamh, service, i, 2061 pam_trace_cname(pamh), 2062 pam_snames[pamentp->pam_type]); 2063 pamh->pam_conf_info[i][pamentp->pam_type] = 2064 pamentp; 2065 service_found[pamentp->pam_type + 1] = 1; 2066 } else { 2067 /* append more service entries */ 2068 pam_trace(PAM_DEBUG_CONF, 2069 "read_pam_conf(%p): adding more " 2070 "%s[%d:%s][%s]", 2071 (void *)pamh, service, i, 2072 pam_trace_cname(pamh), 2073 pam_snames[pamentp->pam_type]); 2074 tpament = 2075 pamh->pam_conf_info[i][pamentp->pam_type]; 2076 while (tpament->next != NULL) { 2077 tpament = tpament->next; 2078 } 2079 tpament->next = pamentp; 2080 } 2081 } else if (service_found[pamentp->pam_type + 1] == 0) { 2082 /* See if "other" entry available and valid */ 2083 if (verify_pam_conf(pamentp, "other")) { 2084 pam_trace(PAM_DEBUG_CONF, 2085 "read_pam_conf(%p): bad entry error %s " 2086 "\"other\"[%d:%s]", 2087 (void *)pamh, service, i, 2088 pam_trace_cname(pamh)); 2089 error = PAM_SYSTEM_ERR; 2090 free_pamconf(pamentp); 2091 goto out; 2092 } 2093 if (strcasecmp(pamentp->pam_service, "other") == 0) { 2094 pam_trace(PAM_DEBUG_CONF, 2095 "read_pam_conf(%p): processing " 2096 "\"other\"[%d:%s]", (void *)pamh, i, 2097 pam_trace_cname(pamh)); 2098 if ((tpament = pamh->pam_conf_info[i] 2099 [pamentp->pam_type]) == NULL) { 2100 /* add first "other" entry */ 2101 pam_trace(PAM_DEBUG_CONF, 2102 "read_pam_conf(%p): adding 1st " 2103 "other[%d:%s][%s]", (void *)pamh, i, 2104 pam_trace_cname(pamh), 2105 pam_snames[pamentp->pam_type]); 2106 pamh->pam_conf_info[i] 2107 [pamentp->pam_type] = pamentp; 2108 } else { 2109 /* append more "other" entries */ 2110 pam_trace(PAM_DEBUG_CONF, 2111 "read_pam_conf(%p): adding more " 2112 "other[%d:%s][%s]", (void *)pamh, i, 2113 pam_trace_cname(pamh), 2114 pam_snames[pamentp->pam_type]); 2115 while (tpament->next != NULL) { 2116 tpament = tpament->next; 2117 } 2118 tpament->next = pamentp; 2119 } 2120 } else { 2121 /* irrelevant entry */ 2122 free_pamconf(pamentp); 2123 } 2124 } else { 2125 /* irrelevant entry */ 2126 free_pamconf(pamentp); 2127 } 2128 } 2129 out: 2130 (void) close_pam_conf(pam_fh); 2131 if (error != PAM_SUCCESS) 2132 free_pam_conf_info(pamh); 2133 return (error); 2134 } 2135 2136 /* 2137 * get_pam_conf_entry - get a pam.conf entry 2138 */ 2139 2140 static int 2141 get_pam_conf_entry(struct pam_fh *pam_fh, pam_handle_t *pamh, pamtab_t **pam) 2142 { 2143 char *cp, *arg; 2144 int argc; 2145 char *tmp, *tmp_free; 2146 int i; 2147 char *current_line = NULL; 2148 int error = PAM_SYSTEM_ERR; /* preset to error */ 2149 int err; 2150 2151 /* get the next line from pam.conf */ 2152 if ((cp = nextline(pam_fh, pamh, &err)) == NULL) { 2153 /* no more lines in pam.conf ==> return */ 2154 error = PAM_SUCCESS; 2155 *pam = NULL; 2156 goto out; 2157 } 2158 2159 if ((*pam = calloc(1, sizeof (pamtab_t))) == NULL) { 2160 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory"); 2161 goto out; 2162 } 2163 2164 /* copy full line for error reporting */ 2165 if ((current_line = strdup(cp)) == NULL) { 2166 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory"); 2167 goto out; 2168 } 2169 2170 pam_trace(PAM_DEBUG_CONF, 2171 "pam.conf[%s] entry:\t%s", pam_trace_cname(pamh), current_line); 2172 2173 /* get service name (e.g. login, su, passwd) */ 2174 if ((arg = read_next_token(&cp)) == 0) { 2175 __pam_log(LOG_AUTH | LOG_CRIT, 2176 "illegal pam.conf[%s] entry: %s: missing SERVICE NAME", 2177 pam_trace_cname(pamh), current_line); 2178 goto out; 2179 } 2180 if (((*pam)->pam_service = strdup(arg)) == 0) { 2181 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory"); 2182 goto out; 2183 } 2184 2185 /* get module type (e.g. authentication, acct mgmt) */ 2186 if ((arg = read_next_token(&cp)) == 0) { 2187 __pam_log(LOG_AUTH | LOG_CRIT, 2188 "illegal pam.conf[%s] entry: %s: missing MODULE TYPE", 2189 pam_trace_cname(pamh), current_line); 2190 (*pam)->pam_type = -1; /* 0 is a valid value */ 2191 goto getflag; 2192 } 2193 if (strcasecmp(arg, PAM_AUTH_NAME) == 0) { 2194 (*pam)->pam_type = PAM_AUTH_MODULE; 2195 } else if (strcasecmp(arg, PAM_ACCOUNT_NAME) == 0) { 2196 (*pam)->pam_type = PAM_ACCOUNT_MODULE; 2197 } else if (strcasecmp(arg, PAM_SESSION_NAME) == 0) { 2198 (*pam)->pam_type = PAM_SESSION_MODULE; 2199 } else if (strcasecmp(arg, PAM_PASSWORD_NAME) == 0) { 2200 (*pam)->pam_type = PAM_PASSWORD_MODULE; 2201 } else { 2202 /* error */ 2203 __pam_log(LOG_AUTH | LOG_CRIT, 2204 "illegal pam.conf[%s] entry: %s: invalid module " 2205 "type: %s", pam_trace_cname(pamh), current_line, arg); 2206 (*pam)->pam_type = -1; /* 0 is a valid value */ 2207 } 2208 2209 getflag: 2210 /* get pam flag (e.g., requisite, required, sufficient, optional) */ 2211 if ((arg = read_next_token(&cp)) == 0) { 2212 __pam_log(LOG_AUTH | LOG_CRIT, 2213 "illegal pam.conf[%s] entry: %s: missing CONTROL FLAG", 2214 pam_trace_cname(pamh), current_line); 2215 goto getpath; 2216 } 2217 if (strcasecmp(arg, PAM_BINDING_NAME) == 0) { 2218 (*pam)->pam_flag = PAM_BINDING; 2219 } else if (strcasecmp(arg, PAM_INCLUDE_NAME) == 0) { 2220 (*pam)->pam_flag = PAM_INCLUDE; 2221 } else if (strcasecmp(arg, PAM_OPTIONAL_NAME) == 0) { 2222 (*pam)->pam_flag = PAM_OPTIONAL; 2223 } else if (strcasecmp(arg, PAM_REQUIRED_NAME) == 0) { 2224 (*pam)->pam_flag = PAM_REQUIRED; 2225 } else if (strcasecmp(arg, PAM_REQUISITE_NAME) == 0) { 2226 (*pam)->pam_flag = PAM_REQUISITE; 2227 } else if (strcasecmp(arg, PAM_SUFFICIENT_NAME) == 0) { 2228 (*pam)->pam_flag = PAM_SUFFICIENT; 2229 } else { 2230 /* error */ 2231 __pam_log(LOG_AUTH | LOG_CRIT, 2232 "illegal pam.conf[%s] entry: %s", 2233 pam_trace_cname(pamh), current_line); 2234 __pam_log(LOG_AUTH | LOG_CRIT, 2235 "\tinvalid control flag: %s", arg); 2236 } 2237 2238 getpath: 2239 /* get module path (e.g. /usr/lib/security/pam_unix_auth.so.1) */ 2240 if ((arg = read_next_token(&cp)) == 0) { 2241 __pam_log(LOG_AUTH | LOG_CRIT, 2242 "illegal pam.conf[%s] entry: %s: missing MODULE PATH", 2243 pam_trace_cname(pamh), current_line); 2244 error = PAM_SUCCESS; /* success */ 2245 goto out; 2246 } 2247 if (arg[0] != '/') { 2248 size_t len; 2249 /* 2250 * If module path does not start with "/", then 2251 * prepend PAM_LIB_DIR (/usr/lib/security/). 2252 */ 2253 /* sizeof (PAM_LIB_DIR) has room for '\0' */ 2254 len = sizeof (PAM_LIB_DIR) + sizeof (PAM_ISA_DIR) + strlen(arg); 2255 if (((*pam)->module_path = malloc(len)) == NULL) { 2256 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory"); 2257 goto out; 2258 } 2259 if ((*pam)->pam_flag & PAM_INCLUDE) { 2260 (void) snprintf((*pam)->module_path, len, "%s%s", 2261 PAM_LIB_DIR, arg); 2262 } else { 2263 (void) snprintf((*pam)->module_path, len, "%s%s%s", 2264 PAM_LIB_DIR, PAM_ISA_DIR, arg); 2265 } 2266 } else { 2267 /* Full path provided for module */ 2268 char *isa; 2269 2270 /* Check for Instruction Set Architecture indicator */ 2271 if ((isa = strstr(arg, PAM_ISA)) != NULL) { 2272 size_t len; 2273 len = strlen(arg) - (sizeof (PAM_ISA)-1) + 2274 sizeof (PAM_ISA_DIR); 2275 2276 /* substitute the architecture dependent path */ 2277 if (((*pam)->module_path = malloc(len)) == NULL) { 2278 __pam_log(LOG_AUTH | LOG_ERR, 2279 "strdup: out of memory"); 2280 goto out; 2281 } 2282 *isa = '\000'; 2283 isa += strlen(PAM_ISA); 2284 (void) snprintf((*pam)->module_path, len, "%s%s%s", 2285 arg, PAM_ISA_DIR, isa); 2286 } else if (((*pam)->module_path = strdup(arg)) == 0) { 2287 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory"); 2288 goto out; 2289 } 2290 } 2291 2292 /* count the number of module-specific options first */ 2293 argc = 0; 2294 if ((tmp = strdup(cp)) == NULL) { 2295 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory"); 2296 goto out; 2297 } 2298 tmp_free = tmp; 2299 for (arg = read_next_token(&tmp); arg; arg = read_next_token(&tmp)) 2300 argc++; 2301 free(tmp_free); 2302 2303 /* allocate array for the module-specific options */ 2304 if (argc > 0) { 2305 if (((*pam)->module_argv = 2306 calloc(argc+1, sizeof (char *))) == 0) { 2307 __pam_log(LOG_AUTH | LOG_ERR, "calloc: out of memory"); 2308 goto out; 2309 } 2310 i = 0; 2311 for (arg = read_next_token(&cp); arg; 2312 arg = read_next_token(&cp)) { 2313 (*pam)->module_argv[i] = strdup(arg); 2314 if ((*pam)->module_argv[i] == NULL) { 2315 __pam_log(LOG_AUTH | LOG_ERR, "strdup failed"); 2316 goto out; 2317 } 2318 i++; 2319 } 2320 (*pam)->module_argv[argc] = NULL; 2321 } 2322 (*pam)->module_argc = argc; 2323 2324 error = PAM_SUCCESS; /* success */ 2325 (*pam)->pam_err = err; /* was the line truncated */ 2326 2327 out: 2328 if (current_line) 2329 free(current_line); 2330 if (error != PAM_SUCCESS) { 2331 /* on error free this */ 2332 if (*pam) 2333 free_pamconf(*pam); 2334 } 2335 return (error); 2336 } 2337 2338 2339 /* 2340 * read_next_token - skip tab and space characters and return the next token 2341 */ 2342 2343 static char * 2344 read_next_token(char **cpp) 2345 { 2346 register char *cp = *cpp; 2347 char *start; 2348 2349 if (cp == (char *)0) { 2350 *cpp = (char *)0; 2351 return ((char *)0); 2352 } 2353 while (*cp == ' ' || *cp == '\t') 2354 cp++; 2355 if (*cp == '\0') { 2356 *cpp = (char *)0; 2357 return ((char *)0); 2358 } 2359 start = cp; 2360 while (*cp && *cp != ' ' && *cp != '\t') 2361 cp++; 2362 if (*cp != '\0') 2363 *cp++ = '\0'; 2364 *cpp = cp; 2365 return (start); 2366 } 2367 2368 static char * 2369 pam_conf_strnchr(char *sp, int c, intptr_t count) 2370 { 2371 while (count) { 2372 if (*sp == (char)c) 2373 return ((char *)sp); 2374 else { 2375 sp++; 2376 count--; 2377 } 2378 }; 2379 return (NULL); 2380 } 2381 2382 /* 2383 * nextline - skip all blank lines and comments 2384 */ 2385 2386 static char * 2387 nextline(struct pam_fh *pam_fh, pam_handle_t *pamh, int *err) 2388 { 2389 char *ll; 2390 int find_a_line = 0; 2391 char *data = pam_fh->data; 2392 char *bufferp = pam_fh->bufferp; 2393 char *bufferendp = &data[pam_fh->bufsize]; 2394 size_t input_len; 2395 2396 /* 2397 * Skip the blank line, comment line 2398 */ 2399 while (!find_a_line) { 2400 /* if we are at the end of the buffer, there is no next line */ 2401 if (bufferp == bufferendp) 2402 return (NULL); 2403 2404 /* skip blank line */ 2405 while (*bufferp == '\n') { 2406 /* 2407 * If we are at the end of the buffer, there is 2408 * no next line. 2409 */ 2410 if (++bufferp == bufferendp) { 2411 return (NULL); 2412 } 2413 /* else we check *bufferp again */ 2414 } 2415 2416 /* skip comment line */ 2417 while (*bufferp == '#') { 2418 if ((ll = pam_conf_strnchr(bufferp, '\n', 2419 bufferendp - bufferp)) != NULL) { 2420 bufferp = ll; 2421 } else { 2422 /* 2423 * this comment line the last line. 2424 * no next line 2425 */ 2426 return (NULL); 2427 } 2428 2429 /* 2430 * If we are at the end of the buffer, there is 2431 * no next line. 2432 */ 2433 if (bufferp == bufferendp) { 2434 return (NULL); 2435 } 2436 } 2437 2438 if ((*bufferp != '\n') && (*bufferp != '#')) { 2439 find_a_line = 1; 2440 } 2441 } 2442 2443 *err = PAM_SUCCESS; 2444 /* now we find one line */ 2445 if ((ll = pam_conf_strnchr(bufferp, '\n', bufferendp - bufferp)) 2446 != NULL) { 2447 if ((input_len = ll - bufferp) >= sizeof (pam_fh->line)) { 2448 __pam_log(LOG_AUTH | LOG_ERR, 2449 "nextline[%d:%s]: pam.conf line too long %.256s", 2450 pamh->include_depth, pam_trace_cname(pamh), 2451 bufferp); 2452 input_len = sizeof (pam_fh->line) - 1; 2453 *err = PAM_SERVICE_ERR; 2454 } 2455 (void) strncpy(pam_fh->line, bufferp, input_len); 2456 pam_fh->line[input_len] = '\0'; 2457 pam_fh->bufferp = ll++; 2458 } else { 2459 ll = bufferendp; 2460 if ((input_len = ll - bufferp) >= sizeof (pam_fh->line)) { 2461 __pam_log(LOG_AUTH | LOG_ERR, 2462 "nextline[%d:%s]: pam.conf line too long %.256s", 2463 pamh->include_depth, pam_trace_cname(pamh), 2464 bufferp); 2465 input_len = sizeof (pam_fh->line) - 1; 2466 *err = PAM_SERVICE_ERR; 2467 } 2468 (void) strncpy(pam_fh->line, bufferp, input_len); 2469 pam_fh->line[input_len] = '\0'; 2470 pam_fh->bufferp = ll; 2471 } 2472 2473 return (pam_fh->line); 2474 } 2475 2476 /* 2477 * verify_pam_conf - verify that the pam_conf entry is filled in. 2478 * 2479 * True = Error if there is no service. 2480 * True = Error if there is a service and it matches the requested service 2481 * but, the type, flag, line overflow, or path is in error. 2482 */ 2483 2484 static int 2485 verify_pam_conf(pamtab_t *pam, char *service) 2486 { 2487 return ((pam->pam_service == (char *)NULL) || 2488 ((strcasecmp(pam->pam_service, service) == 0) && 2489 ((pam->pam_type == -1) || 2490 (pam->pam_flag == 0) || 2491 (pam->pam_err != PAM_SUCCESS) || 2492 (pam->module_path == (char *)NULL)))); 2493 } 2494 2495 /* 2496 * Routines to free allocated storage 2497 */ 2498 2499 /* 2500 * clean_up - free allocated storage in the pam handle 2501 */ 2502 2503 static void 2504 clean_up(pam_handle_t *pamh) 2505 { 2506 int i; 2507 pam_repository_t *auth_rep; 2508 2509 if (pamh) { 2510 while (pamh->include_depth >= 0) { 2511 free_pam_conf_info(pamh); 2512 pamh->include_depth--; 2513 } 2514 2515 /* Cleanup PAM_REPOSITORY structure */ 2516 auth_rep = pamh->ps_item[PAM_REPOSITORY].pi_addr; 2517 if (auth_rep != NULL) { 2518 if (auth_rep->type != NULL) 2519 free(auth_rep->type); 2520 if (auth_rep->scope != NULL) 2521 free(auth_rep->scope); 2522 } 2523 2524 for (i = 0; i < PAM_MAX_ITEMS; i++) { 2525 if (pamh->ps_item[i].pi_addr != NULL) { 2526 if (i == PAM_AUTHTOK || i == PAM_OLDAUTHTOK) { 2527 (void) memset(pamh->ps_item[i].pi_addr, 2528 0, pamh->ps_item[i].pi_size); 2529 } 2530 free(pamh->ps_item[i].pi_addr); 2531 } 2532 } 2533 free(pamh); 2534 } 2535 } 2536 2537 /* 2538 * free_pamconf - free memory used to store pam.conf entry 2539 */ 2540 2541 static void 2542 free_pamconf(pamtab_t *cp) 2543 { 2544 int i; 2545 2546 if (cp) { 2547 if (cp->pam_service) 2548 free(cp->pam_service); 2549 if (cp->module_path) 2550 free(cp->module_path); 2551 for (i = 0; i < cp->module_argc; i++) { 2552 if (cp->module_argv[i]) 2553 free(cp->module_argv[i]); 2554 } 2555 if (cp->module_argc > 0) 2556 free(cp->module_argv); 2557 if (cp->function_ptr) 2558 free(cp->function_ptr); 2559 2560 free(cp); 2561 } 2562 } 2563 2564 /* 2565 * free_pam_conf_info - free memory used to store all pam.conf info 2566 * under the pam handle 2567 */ 2568 2569 static void 2570 free_pam_conf_info(pam_handle_t *pamh) 2571 { 2572 pamtab_t *pamentp; 2573 pamtab_t *pament_trail; 2574 int i = pamh->include_depth; 2575 int j; 2576 2577 for (j = 0; j < PAM_NUM_MODULE_TYPES; j++) { 2578 pamentp = pamh->pam_conf_info[i][j]; 2579 pamh->pam_conf_info[i][j] = NULL; 2580 pament_trail = pamentp; 2581 while (pamentp) { 2582 pamentp = pamentp->next; 2583 free_pamconf(pament_trail); 2584 pament_trail = pamentp; 2585 } 2586 } 2587 if (pamh->pam_conf_name[i] != NULL) { 2588 free(pamh->pam_conf_name[i]); 2589 pamh->pam_conf_name[i] = NULL; 2590 } 2591 } 2592 2593 static void 2594 free_env(env_list *pam_env) 2595 { 2596 if (pam_env) { 2597 if (pam_env->name) 2598 free(pam_env->name); 2599 if (pam_env->value) 2600 free(pam_env->value); 2601 free(pam_env); 2602 } 2603 } 2604 2605 /* 2606 * Internal convenience functions for Solaris PAM service modules. 2607 */ 2608 2609 #include <libintl.h> 2610 #include <nl_types.h> 2611 #include <synch.h> 2612 #include <locale.h> 2613 #include <thread.h> 2614 2615 typedef struct pam_msg_data { 2616 nl_catd fd; 2617 } pam_msg_data_t; 2618 2619 /* 2620 * free_resp(): 2621 * free storage for responses used in the call back "pam_conv" functions 2622 */ 2623 2624 void 2625 free_resp(int num_msg, struct pam_response *resp) 2626 { 2627 int i; 2628 struct pam_response *r; 2629 2630 if (resp) { 2631 r = resp; 2632 for (i = 0; i < num_msg; i++, r++) { 2633 if (r->resp) { 2634 /* clear before freeing -- may be a password */ 2635 bzero(r->resp, strlen(r->resp)); 2636 free(r->resp); 2637 r->resp = NULL; 2638 } 2639 } 2640 free(resp); 2641 } 2642 } 2643 2644 static int 2645 do_conv(pam_handle_t *pamh, int msg_style, int num_msg, 2646 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], void *conv_apdp, 2647 struct pam_response *ret_respp[]) 2648 { 2649 struct pam_message *msg; 2650 struct pam_message *m; 2651 int i; 2652 int k; 2653 int retcode; 2654 struct pam_conv *pam_convp; 2655 2656 if ((retcode = pam_get_item(pamh, PAM_CONV, 2657 (void **)&pam_convp)) != PAM_SUCCESS) { 2658 return (retcode); 2659 } 2660 2661 /* 2662 * When pam_set_item() is called to set PAM_CONV and the 2663 * item is NULL, memset(pip->pi_addr, 0, size) is called. 2664 * So at this point, we should check whether pam_convp->conv 2665 * is NULL or not. 2666 */ 2667 if ((pam_convp == NULL) || (pam_convp->conv == NULL)) 2668 return (PAM_SYSTEM_ERR); 2669 2670 i = 0; 2671 k = num_msg; 2672 2673 msg = calloc(num_msg, sizeof (struct pam_message)); 2674 if (msg == NULL) { 2675 return (PAM_BUF_ERR); 2676 } 2677 m = msg; 2678 2679 while (k--) { 2680 /* 2681 * fill out the message structure to display prompt message 2682 */ 2683 m->msg_style = msg_style; 2684 m->msg = messages[i]; 2685 pam_trace(PAM_DEBUG_CONV, 2686 "pam_conv_msg(%p:%d[%d]=%s)", 2687 (void *)pamh, msg_style, i, messages[i]); 2688 m++; 2689 i++; 2690 } 2691 2692 /* 2693 * The UNIX pam modules always calls __pam_get_authtok() and 2694 * __pam_display_msg() with a NULL pointer as the conv_apdp. 2695 * In case the conv_apdp is NULL and the pam_convp->appdata_ptr 2696 * is not NULL, we should pass the pam_convp->appdata_ptr 2697 * to the conversation function. 2698 */ 2699 if (conv_apdp == NULL && pam_convp->appdata_ptr != NULL) 2700 conv_apdp = pam_convp->appdata_ptr; 2701 2702 /* 2703 * Call conv function to display the prompt. 2704 */ 2705 retcode = (pam_convp->conv)(num_msg, &msg, ret_respp, conv_apdp); 2706 pam_trace(PAM_DEBUG_CONV, 2707 "pam_conv_resp(%p pam_conv = %s) ret_respp = %p", 2708 (void *)pamh, pam_strerror(pamh, retcode), (void *)ret_respp); 2709 if (*ret_respp == NULL) { 2710 pam_trace(PAM_DEBUG_CONV, 2711 "pam_conv_resp(%p No response requested)", (void *)pamh); 2712 } else if ((pam_debug & (PAM_DEBUG_CONV | PAM_DEBUG_AUTHTOK)) != 0) { 2713 struct pam_response *r = *ret_respp; 2714 2715 for (i = 0; i < num_msg; i++, r++) { 2716 if (r->resp == NULL) { 2717 pam_trace(PAM_DEBUG_CONV, 2718 "pam_conv_resp(%p:" 2719 "[%d] NULL response string)", 2720 (void *)pamh, i); 2721 } else { 2722 if (msg_style == PAM_PROMPT_ECHO_OFF) { 2723 #ifdef DEBUG 2724 pam_trace(PAM_DEBUG_AUTHTOK, 2725 "pam_conv_resp(%p:[%d]=%s, " 2726 "code=%d)", 2727 (void *)pamh, i, r->resp, 2728 r->resp_retcode); 2729 #endif /* DEBUG */ 2730 pam_trace(PAM_DEBUG_CONV, 2731 "pam_conv_resp(%p:[%d] len=%lu, " 2732 "code=%d)", 2733 (void *)pamh, i, 2734 (ulong_t)strlen(r->resp), 2735 r->resp_retcode); 2736 } else { 2737 pam_trace(PAM_DEBUG_CONV, 2738 "pam_conv_resp(%p:[%d]=%s, " 2739 "code=%d)", 2740 (void *)pamh, i, r->resp, 2741 r->resp_retcode); 2742 } 2743 } 2744 } 2745 } 2746 2747 if (msg) 2748 free(msg); 2749 return (retcode); 2750 } 2751 2752 /* 2753 * __pam_display_msg(): 2754 * display message by calling the call back functions 2755 * provided by the application through "pam_conv" structure 2756 */ 2757 2758 int 2759 __pam_display_msg(pam_handle_t *pamh, int msg_style, int num_msg, 2760 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], void *conv_apdp) 2761 { 2762 struct pam_response *ret_respp = NULL; 2763 int ret; 2764 2765 ret = do_conv(pamh, msg_style, num_msg, messages, 2766 conv_apdp, &ret_respp); 2767 2768 if (ret_respp != NULL) 2769 free_resp(num_msg, ret_respp); 2770 2771 return (ret); 2772 } 2773 2774 /* 2775 * __pam_get_authtok() 2776 * retrieves a password of at most PASS_MAX length from the pam 2777 * handle (pam_get_item) or from the input stream (do_conv). 2778 * 2779 * This function allocates memory for the new authtok. 2780 * Applications calling this function are responsible for 2781 * freeing this memory. 2782 * 2783 * If "source" is 2784 * PAM_HANDLE 2785 * and "type" is: 2786 * PAM_AUTHTOK - password is taken from pam handle (PAM_AUTHTOK) 2787 * PAM_OLDAUTHTOK - password is taken from pam handle (PAM_OLDAUTHTOK) 2788 * 2789 * If "source" is 2790 * PAM_PROMPT 2791 * and "type" is: 2792 * 0: Prompt for new passwd, do not even attempt 2793 * to store it in the pam handle. 2794 * PAM_AUTHTOK: Prompt for new passwd, store in pam handle as 2795 * PAM_AUTHTOK item if this value is not already set. 2796 * PAM_OLDAUTHTOK: Prompt for new passwd, store in pam handle as 2797 * PAM_OLDAUTHTOK item if this value is not 2798 * already set. 2799 */ 2800 int 2801 __pam_get_authtok(pam_handle_t *pamh, int source, int type, char *prompt, 2802 char **authtok) 2803 { 2804 int error = PAM_SYSTEM_ERR; 2805 char *new_password = NULL; 2806 struct pam_response *ret_resp = NULL; 2807 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; 2808 2809 if ((*authtok = calloc(PASS_MAX+1, sizeof (char))) == NULL) 2810 return (PAM_BUF_ERR); 2811 2812 if (prompt == NULL) 2813 prompt = dgettext(TEXT_DOMAIN, "password: "); 2814 2815 switch (source) { 2816 case PAM_HANDLE: 2817 2818 /* get password from pam handle item list */ 2819 2820 switch (type) { 2821 case PAM_AUTHTOK: 2822 case PAM_OLDAUTHTOK: 2823 2824 if ((error = pam_get_item(pamh, type, 2825 (void **)&new_password)) != PAM_SUCCESS) 2826 goto err_ret; 2827 2828 if (new_password == NULL || new_password[0] == '\0') { 2829 free(*authtok); 2830 *authtok = NULL; 2831 } else { 2832 (void) strlcpy(*authtok, new_password, 2833 PASS_MAX+1); 2834 } 2835 break; 2836 default: 2837 __pam_log(LOG_AUTH | LOG_ERR, 2838 "__pam_get_authtok() invalid type: %d", type); 2839 error = PAM_SYMBOL_ERR; 2840 goto err_ret; 2841 } 2842 break; 2843 case PAM_PROMPT: 2844 2845 /* 2846 * Prompt for new password and save in pam handle item list 2847 * if the that item is not already set. 2848 */ 2849 2850 (void) strncpy(messages[0], prompt, sizeof (messages[0])); 2851 if ((error = do_conv(pamh, PAM_PROMPT_ECHO_OFF, 1, messages, 2852 NULL, &ret_resp)) != PAM_SUCCESS) 2853 goto err_ret; 2854 2855 if (ret_resp->resp == NULL) { 2856 /* getpass didn't return anything */ 2857 error = PAM_SYSTEM_ERR; 2858 goto err_ret; 2859 } 2860 2861 /* save the new password if this item was NULL */ 2862 if (type) { 2863 if ((error = pam_get_item(pamh, type, 2864 (void **)&new_password)) != PAM_SUCCESS) { 2865 free_resp(1, ret_resp); 2866 goto err_ret; 2867 } 2868 if (new_password == NULL) 2869 (void) pam_set_item(pamh, type, ret_resp->resp); 2870 } 2871 2872 (void) strlcpy(*authtok, ret_resp->resp, PASS_MAX+1); 2873 free_resp(1, ret_resp); 2874 break; 2875 default: 2876 __pam_log(LOG_AUTH | LOG_ERR, 2877 "__pam_get_authtok() invalid source: %d", source); 2878 error = PAM_SYMBOL_ERR; 2879 goto err_ret; 2880 } 2881 2882 return (PAM_SUCCESS); 2883 2884 err_ret: 2885 bzero(*authtok, PASS_MAX+1); 2886 free(*authtok); 2887 *authtok = NULL; 2888 return (error); 2889 } 2890