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