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 (c) 2019, 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 break; 661 else { 662 username[index] = *ptr; 663 index++; 664 ptr++; 665 } 666 } 667 668 /* ret_username will be freed in pam_get_user(). */ 669 if ((*ret_username = malloc(index + 1)) == NULL) 670 return (PAM_BUF_ERR); 671 (void) strcpy(*ret_username, username); 672 return (PAM_SUCCESS); 673 } 674 675 /* 676 * Get the value of PAM_USER. If not set, then use the convenience function 677 * to prompt for the user. Use prompt if specified, else use PAM_USER_PROMPT 678 * if it is set, else use default. 679 */ 680 #define WHITESPACE 0 681 #define USERNAME 1 682 683 int 684 pam_get_user(pam_handle_t *pamh, char **user, const char *prompt_override) 685 { 686 int status; 687 char *prompt = NULL; 688 char *real_username; 689 struct pam_response *ret_resp = NULL; 690 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; 691 692 pam_trace(PAM_DEBUG_DEFAULT, 693 "pam_get_user(%p, %p, %s)", (void *)pamh, (void *)*user, 694 prompt_override ? prompt_override : "NULL"); 695 if (pamh == NULL) 696 return (PAM_SYSTEM_ERR); 697 698 if ((status = pam_get_item(pamh, PAM_USER, (void **)user)) 699 != PAM_SUCCESS) { 700 return (status); 701 } 702 703 /* if the user is set, return it */ 704 705 if (*user != NULL && *user[0] != '\0') { 706 return (PAM_SUCCESS); 707 } 708 709 /* 710 * if the module is requesting a special prompt, use it. 711 * else use PAM_USER_PROMPT. 712 */ 713 714 if (prompt_override != NULL) { 715 prompt = (char *)prompt_override; 716 } else { 717 status = pam_get_item(pamh, PAM_USER_PROMPT, (void**)&prompt); 718 if (status != PAM_SUCCESS) { 719 return (status); 720 } 721 } 722 723 /* if the prompt is not set, use default */ 724 725 if (prompt == NULL || prompt[0] == '\0') { 726 prompt = dgettext(TEXT_DOMAIN, "Please enter user name: "); 727 } 728 729 /* prompt for the user */ 730 731 (void) strncpy(messages[0], prompt, sizeof (messages[0])); 732 733 for (;;) { 734 int state = WHITESPACE; 735 736 status = do_conv(pamh, PAM_PROMPT_ECHO_ON, 1, messages, 737 NULL, &ret_resp); 738 739 if (status != PAM_SUCCESS) { 740 return (status); 741 } 742 743 if (ret_resp->resp && ret_resp->resp[0] != '\0') { 744 int len = strlen(ret_resp->resp); 745 int i; 746 747 for (i = 0; i < len; i++) { 748 if ((ret_resp->resp[i] != ' ') && 749 (ret_resp->resp[i] != '\t')) { 750 state = USERNAME; 751 break; 752 } 753 } 754 755 if (state == USERNAME) 756 break; 757 } 758 /* essentially empty response, try again */ 759 free_resp(1, ret_resp); 760 ret_resp = NULL; 761 } 762 763 /* set PAM_USER */ 764 /* Parse the user input to get the user name. */ 765 status = parse_user_name(ret_resp->resp, &real_username); 766 767 if (status != PAM_SUCCESS) { 768 if (real_username != NULL) 769 free(real_username); 770 free_resp(1, ret_resp); 771 return (status); 772 } 773 774 status = pam_set_item(pamh, PAM_USER, real_username); 775 776 free(real_username); 777 778 free_resp(1, ret_resp); 779 if (status != PAM_SUCCESS) { 780 return (status); 781 } 782 783 /* 784 * finally, get PAM_USER. We have to call pam_get_item to get 785 * the value of user because pam_set_item mallocs the memory. 786 */ 787 788 status = pam_get_item(pamh, PAM_USER, (void**)user); 789 return (status); 790 } 791 792 /* 793 * Set module specific data 794 */ 795 796 int 797 pam_set_data(pam_handle_t *pamh, const char *module_data_name, void *data, 798 void (*cleanup)(pam_handle_t *pamh, void *data, int pam_end_status)) 799 { 800 struct pam_module_data *psd; 801 802 pam_trace(PAM_DEBUG_DATA, 803 "pam_set_data(%p:%s:%d)=%p", (void *)pamh, 804 (module_data_name != NULL) ? module_data_name : "NULL", 805 (pamh != NULL) ? pamh->pam_inmodule : -1, data); 806 if (pamh == NULL || (pamh->pam_inmodule != WO_OK) || 807 module_data_name == NULL) { 808 return (PAM_SYSTEM_ERR); 809 } 810 811 /* check if module data already exists */ 812 813 for (psd = pamh->ssd; psd; psd = psd->next) { 814 if (strcmp(psd->module_data_name, module_data_name) == 0) { 815 /* clean up original data before setting the new data */ 816 if (psd->cleanup) { 817 psd->cleanup(pamh, psd->data, PAM_SUCCESS); 818 } 819 psd->data = (void *)data; 820 psd->cleanup = cleanup; 821 return (PAM_SUCCESS); 822 } 823 } 824 825 psd = malloc(sizeof (struct pam_module_data)); 826 if (psd == NULL) 827 return (PAM_BUF_ERR); 828 829 psd->module_data_name = strdup(module_data_name); 830 if (psd->module_data_name == NULL) { 831 free(psd); 832 return (PAM_BUF_ERR); 833 } 834 835 psd->data = (void *)data; 836 psd->cleanup = cleanup; 837 psd->next = pamh->ssd; 838 pamh->ssd = psd; 839 return (PAM_SUCCESS); 840 } 841 842 /* 843 * get module specific data 844 */ 845 846 int 847 pam_get_data(const pam_handle_t *pamh, const char *module_data_name, 848 const void **data) 849 { 850 struct pam_module_data *psd; 851 852 if (pamh == NULL || (pamh->pam_inmodule != WO_OK) || 853 module_data_name == NULL) { 854 pam_trace(PAM_DEBUG_DATA, 855 "pam_get_data(%p:%s:%d)=%p", (void *)pamh, 856 module_data_name ? module_data_name : "NULL", 857 pamh->pam_inmodule, *data); 858 return (PAM_SYSTEM_ERR); 859 } 860 861 for (psd = pamh->ssd; psd; psd = psd->next) { 862 if (strcmp(psd->module_data_name, module_data_name) == 0) { 863 *data = psd->data; 864 pam_trace(PAM_DEBUG_DATA, 865 "pam_get_data(%p:%s)=%p", (void *)pamh, 866 module_data_name, *data); 867 return (PAM_SUCCESS); 868 } 869 } 870 pam_trace(PAM_DEBUG_DATA, 871 "pam_get_data(%p:%s)=%s", (void *)pamh, module_data_name, 872 "PAM_NO_MODULE_DATA"); 873 874 return (PAM_NO_MODULE_DATA); 875 } 876 877 /* 878 * PAM equivalent to strerror() 879 */ 880 /* ARGSUSED */ 881 const char * 882 pam_strerror(pam_handle_t *pamh, int errnum) 883 { 884 switch (errnum) { 885 case PAM_SUCCESS: 886 return (dgettext(TEXT_DOMAIN, "Success")); 887 case PAM_OPEN_ERR: 888 return (dgettext(TEXT_DOMAIN, "Dlopen failure")); 889 case PAM_SYMBOL_ERR: 890 return (dgettext(TEXT_DOMAIN, "Symbol not found")); 891 case PAM_SERVICE_ERR: 892 return (dgettext(TEXT_DOMAIN, 893 "Error in underlying service module")); 894 case PAM_SYSTEM_ERR: 895 return (dgettext(TEXT_DOMAIN, "System error")); 896 case PAM_BUF_ERR: 897 return (dgettext(TEXT_DOMAIN, "Memory buffer error")); 898 case PAM_CONV_ERR: 899 return (dgettext(TEXT_DOMAIN, "Conversation failure")); 900 case PAM_PERM_DENIED: 901 return (dgettext(TEXT_DOMAIN, "Permission denied")); 902 case PAM_MAXTRIES: 903 return (dgettext(TEXT_DOMAIN, 904 "Maximum number of attempts exceeded")); 905 case PAM_AUTH_ERR: 906 return (dgettext(TEXT_DOMAIN, "Authentication failed")); 907 case PAM_NEW_AUTHTOK_REQD: 908 return (dgettext(TEXT_DOMAIN, "Get new authentication token")); 909 case PAM_CRED_INSUFFICIENT: 910 return (dgettext(TEXT_DOMAIN, "Insufficient credentials")); 911 case PAM_AUTHINFO_UNAVAIL: 912 return (dgettext(TEXT_DOMAIN, 913 "Can not retrieve authentication info")); 914 case PAM_USER_UNKNOWN: 915 return (dgettext(TEXT_DOMAIN, "No account present for user")); 916 case PAM_CRED_UNAVAIL: 917 return (dgettext(TEXT_DOMAIN, 918 "Can not retrieve user credentials")); 919 case PAM_CRED_EXPIRED: 920 return (dgettext(TEXT_DOMAIN, 921 "User credentials have expired")); 922 case PAM_CRED_ERR: 923 return (dgettext(TEXT_DOMAIN, 924 "Failure setting user credentials")); 925 case PAM_ACCT_EXPIRED: 926 return (dgettext(TEXT_DOMAIN, "User account has expired")); 927 case PAM_AUTHTOK_EXPIRED: 928 return (dgettext(TEXT_DOMAIN, "User password has expired")); 929 case PAM_SESSION_ERR: 930 return (dgettext(TEXT_DOMAIN, 931 "Can not make/remove entry for session")); 932 case PAM_AUTHTOK_ERR: 933 return (dgettext(TEXT_DOMAIN, 934 "Authentication token manipulation error")); 935 case PAM_AUTHTOK_RECOVERY_ERR: 936 return (dgettext(TEXT_DOMAIN, 937 "Authentication token can not be recovered")); 938 case PAM_AUTHTOK_LOCK_BUSY: 939 return (dgettext(TEXT_DOMAIN, 940 "Authentication token lock busy")); 941 case PAM_AUTHTOK_DISABLE_AGING: 942 return (dgettext(TEXT_DOMAIN, 943 "Authentication token aging disabled")); 944 case PAM_NO_MODULE_DATA: 945 return (dgettext(TEXT_DOMAIN, 946 "Module specific data not found")); 947 case PAM_IGNORE: 948 return (dgettext(TEXT_DOMAIN, "Ignore module")); 949 case PAM_ABORT: 950 return (dgettext(TEXT_DOMAIN, "General PAM failure ")); 951 case PAM_TRY_AGAIN: 952 return (dgettext(TEXT_DOMAIN, 953 "Unable to complete operation. Try again")); 954 default: 955 return (dgettext(TEXT_DOMAIN, "Unknown error")); 956 } 957 } 958 959 static void * 960 sm_name(int ind) 961 { 962 switch (ind) { 963 case PAM_AUTHENTICATE: 964 return (PAM_SM_AUTHENTICATE); 965 case PAM_SETCRED: 966 return (PAM_SM_SETCRED); 967 case PAM_ACCT_MGMT: 968 return (PAM_SM_ACCT_MGMT); 969 case PAM_OPEN_SESSION: 970 return (PAM_SM_OPEN_SESSION); 971 case PAM_CLOSE_SESSION: 972 return (PAM_SM_CLOSE_SESSION); 973 case PAM_CHAUTHTOK: 974 return (PAM_SM_CHAUTHTOK); 975 } 976 return (NULL); 977 } 978 979 static int 980 (*func(pamtab_t *modulep, int ind))() 981 { 982 void *funcp; 983 984 if ((funcp = modulep->function_ptr) == NULL) 985 return (NULL); 986 987 switch (ind) { 988 case PAM_AUTHENTICATE: 989 return (((struct auth_module *)funcp)->pam_sm_authenticate); 990 case PAM_SETCRED: 991 return (((struct auth_module *)funcp)->pam_sm_setcred); 992 case PAM_ACCT_MGMT: 993 return (((struct account_module *)funcp)->pam_sm_acct_mgmt); 994 case PAM_OPEN_SESSION: 995 return (((struct session_module *)funcp)->pam_sm_open_session); 996 case PAM_CLOSE_SESSION: 997 return (((struct session_module *)funcp)->pam_sm_close_session); 998 case PAM_CHAUTHTOK: 999 return (((struct password_module *)funcp)->pam_sm_chauthtok); 1000 } 1001 return (NULL); 1002 } 1003 1004 /* 1005 * Run through the PAM service module stack for the given module type. 1006 */ 1007 static int 1008 run_stack(pam_handle_t *pamh, int flags, int type, int def_err, int ind, 1009 char *function_name) 1010 { 1011 int err = PAM_SYSTEM_ERR; /* preset */ 1012 int optional_error = 0; 1013 int required_error = 0; 1014 int success = 0; 1015 pamtab_t *modulep; 1016 int (*sm_func)(); 1017 1018 if (pamh == NULL) 1019 return (PAM_SYSTEM_ERR); 1020 1021 /* read initial entries from pam.conf */ 1022 if ((err = read_pam_conf(pamh, PAM_CONFIG)) != PAM_SUCCESS) { 1023 return (err); 1024 } 1025 1026 if ((modulep = 1027 pamh->pam_conf_info[pamh->include_depth][type]) == NULL) { 1028 __pam_log(LOG_AUTH | LOG_ERR, "%s no initial module present", 1029 pam_trace_cname(pamh)); 1030 goto exit_return; 1031 } 1032 1033 pamh->pam_inmodule = WO_OK; /* OK to get AUTHTOK */ 1034 include: 1035 pam_trace(PAM_DEBUG_MODULE, 1036 "[%d:%s]:run_stack:%s(%p, %x): %s", pamh->include_depth, 1037 pam_trace_cname(pamh), function_name, (void *)pamh, flags, 1038 modulep ? modulep->module_path : "NULL"); 1039 1040 while (modulep != NULL) { 1041 if (modulep->pam_flag & PAM_INCLUDE) { 1042 /* save the return location */ 1043 pamh->pam_conf_modulep[pamh->include_depth] = 1044 modulep->next; 1045 pam_trace(PAM_DEBUG_MODULE, 1046 "setting for include[%d:%p]", 1047 pamh->include_depth, (void *)modulep->next); 1048 if (pamh->include_depth++ >= PAM_MAX_INCLUDE) { 1049 __pam_log(LOG_AUTH | LOG_ERR, 1050 "run_stack: includes too deep %d " 1051 "found trying to include %s from %s, %d " 1052 "allowed", pamh->include_depth, 1053 modulep->module_path, pamh->pam_conf_name 1054 [PAM_MAX_INCLUDE] == NULL ? "NULL" : 1055 pamh->pam_conf_name[PAM_MAX_INCLUDE], 1056 PAM_MAX_INCLUDE); 1057 goto exit_return; 1058 } 1059 if ((err = read_pam_conf(pamh, 1060 modulep->module_path)) != PAM_SUCCESS) { 1061 __pam_log(LOG_AUTH | LOG_ERR, 1062 "run_stack[%d:%s]: can't read included " 1063 "conf %s", pamh->include_depth, 1064 pam_trace_cname(pamh), 1065 modulep->module_path); 1066 goto exit_return; 1067 } 1068 if ((modulep = pamh->pam_conf_info 1069 [pamh->include_depth][type]) == NULL) { 1070 __pam_log(LOG_AUTH | LOG_ERR, 1071 "run_stack[%d:%s]: no include module " 1072 "present %s", pamh->include_depth, 1073 pam_trace_cname(pamh), function_name); 1074 goto exit_return; 1075 } 1076 if (modulep->pam_flag & PAM_INCLUDE) { 1077 /* first line another include */ 1078 goto include; 1079 } 1080 pam_trace(PAM_DEBUG_DEFAULT, "include[%d:%s]" 1081 "(%p, %s)=%s", pamh->include_depth, 1082 pam_trace_cname(pamh), (void *)pamh, 1083 function_name, modulep->module_path); 1084 if ((err = load_modules(pamh, type, sm_name(ind), 1085 pamh->pam_conf_info 1086 [pamh->include_depth][type])) != PAM_SUCCESS) { 1087 pam_trace(PAM_DEBUG_DEFAULT, 1088 "[%d:%s]:%s(%p, %x): load_modules failed", 1089 pamh->include_depth, pam_trace_cname(pamh), 1090 function_name, (void *)pamh, flags); 1091 goto exit_return; 1092 } 1093 if ((modulep = pamh->pam_conf_info 1094 [pamh->include_depth][type]) == NULL) { 1095 __pam_log(LOG_AUTH | LOG_ERR, 1096 "%s no initial module present", 1097 pam_trace_cname(pamh)); 1098 goto exit_return; 1099 } 1100 } else if ((err = load_modules(pamh, type, sm_name(ind), 1101 modulep)) != PAM_SUCCESS) { 1102 pam_trace(PAM_DEBUG_DEFAULT, 1103 "[%d:%s]:%s(%p, %x): load_modules failed", 1104 pamh->include_depth, pam_trace_cname(pamh), 1105 function_name, (void *)pamh, flags); 1106 goto exit_return; 1107 } /* PAM_INCLUDE */ 1108 sm_func = func(modulep, ind); 1109 if (sm_func) { 1110 err = sm_func(pamh, flags, modulep->module_argc, 1111 (const char **)modulep->module_argv); 1112 1113 pam_trace(PAM_DEBUG_MODULE, 1114 "[%d:%s]:%s(%p, %x): %s returned %s", 1115 pamh->include_depth, pam_trace_cname(pamh), 1116 function_name, (void *)pamh, flags, 1117 modulep->module_path, pam_strerror(pamh, err)); 1118 1119 switch (err) { 1120 case PAM_IGNORE: 1121 /* do nothing */ 1122 break; 1123 case PAM_SUCCESS: 1124 if ((modulep->pam_flag & PAM_SUFFI_BIND) && 1125 !required_error) { 1126 pamh->pam_inmodule = RW_OK; 1127 pam_trace(PAM_DEBUG_MODULE, 1128 "[%d:%s]:%s(%p, %x): %s: success", 1129 pamh->include_depth, 1130 pam_trace_cname(pamh), 1131 function_name, (void *)pamh, flags, 1132 (modulep->pam_flag & PAM_BINDING) ? 1133 PAM_BINDING_NAME : 1134 PAM_SUFFICIENT_NAME); 1135 goto exit_return; 1136 } 1137 success = 1; 1138 break; 1139 case PAM_TRY_AGAIN: 1140 /* 1141 * We need to return immediately, and 1142 * we shouldn't reset the AUTHTOK item 1143 * since it is not an error per-se. 1144 */ 1145 pamh->pam_inmodule = RW_OK; 1146 pam_trace(PAM_DEBUG_MODULE, 1147 "[%d:%s]:%s(%p, %x): TRY_AGAIN: %s", 1148 pamh->include_depth, pam_trace_cname(pamh), 1149 function_name, (void *)pamh, flags, 1150 pam_strerror(pamh, required_error ? 1151 required_error : err)); 1152 err = required_error ? required_error : err; 1153 goto exit_return; 1154 default: 1155 if (modulep->pam_flag & PAM_REQUISITE) { 1156 pamh->pam_inmodule = RW_OK; 1157 pam_trace(PAM_DEBUG_MODULE, 1158 "[%d:%s]:%s(%p, %x): requisite: %s", 1159 pamh->include_depth, 1160 pam_trace_cname(pamh), 1161 function_name, (void *)pamh, flags, 1162 pam_strerror(pamh, 1163 required_error ? required_error : 1164 err)); 1165 err = required_error ? 1166 required_error : err; 1167 goto exit_return; 1168 } else if (modulep->pam_flag & PAM_REQRD_BIND) { 1169 if (!required_error) 1170 required_error = err; 1171 } else { 1172 if (!optional_error) 1173 optional_error = err; 1174 } 1175 pam_trace(PAM_DEBUG_DEFAULT, 1176 "[%d:%s]:%s(%p, %x): error %s", 1177 pamh->include_depth, pam_trace_cname(pamh), 1178 function_name, (void *)pamh, flags, 1179 pam_strerror(pamh, err)); 1180 break; 1181 } 1182 } 1183 modulep = modulep->next; 1184 } 1185 1186 pam_trace(PAM_DEBUG_MODULE, "[%d:%s]:stack_end:%s(%p, %x): %s %s: %s", 1187 pamh->include_depth, pam_trace_cname(pamh), function_name, 1188 (void *)pamh, flags, pamh->include_depth ? "included" : "final", 1189 required_error ? "required" : success ? "success" : 1190 optional_error ? "optional" : "default", 1191 pam_strerror(pamh, required_error ? required_error : 1192 success ? PAM_SUCCESS : optional_error ? optional_error : def_err)); 1193 if (pamh->include_depth > 0) { 1194 free_pam_conf_info(pamh); 1195 pamh->include_depth--; 1196 /* continue at next entry */ 1197 modulep = pamh->pam_conf_modulep[pamh->include_depth]; 1198 pam_trace(PAM_DEBUG_MODULE, "looping for include[%d:%p]", 1199 pamh->include_depth, (void *)modulep); 1200 goto include; 1201 } 1202 free_pam_conf_info(pamh); 1203 pamh->pam_inmodule = RW_OK; 1204 if (required_error != 0) 1205 return (required_error); 1206 else if (success != 0) 1207 return (PAM_SUCCESS); 1208 else if (optional_error != 0) 1209 return (optional_error); 1210 else 1211 return (def_err); 1212 1213 exit_return: 1214 /* 1215 * All done at whatever depth we're at. 1216 * Go back to not having read /etc/pam.conf 1217 */ 1218 while (pamh->include_depth > 0) { 1219 free_pam_conf_info(pamh); 1220 pamh->include_depth--; 1221 } 1222 free_pam_conf_info(pamh); 1223 pamh->pam_inmodule = RW_OK; 1224 return (err); 1225 } 1226 1227 /* 1228 * pam_authenticate - authenticate a user 1229 */ 1230 1231 int 1232 pam_authenticate(pam_handle_t *pamh, int flags) 1233 { 1234 int retval; 1235 1236 retval = run_stack(pamh, flags, PAM_AUTH_MODULE, PAM_AUTH_ERR, 1237 PAM_AUTHENTICATE, "pam_authenticate"); 1238 1239 if (retval != PAM_SUCCESS) 1240 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 1241 return (retval); 1242 } 1243 1244 /* 1245 * pam_setcred - modify or retrieve user credentials 1246 */ 1247 1248 int 1249 pam_setcred(pam_handle_t *pamh, int flags) 1250 { 1251 int retval; 1252 1253 retval = run_stack(pamh, flags, PAM_AUTH_MODULE, PAM_CRED_ERR, 1254 PAM_SETCRED, "pam_setcred"); 1255 1256 if (retval != PAM_SUCCESS) 1257 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 1258 return (retval); 1259 } 1260 1261 /* 1262 * pam_acct_mgmt - check password aging, account expiration 1263 */ 1264 1265 int 1266 pam_acct_mgmt(pam_handle_t *pamh, int flags) 1267 { 1268 int retval; 1269 1270 retval = run_stack(pamh, flags, PAM_ACCOUNT_MODULE, PAM_ACCT_EXPIRED, 1271 PAM_ACCT_MGMT, "pam_acct_mgmt"); 1272 1273 if (retval != PAM_SUCCESS && 1274 retval != PAM_NEW_AUTHTOK_REQD) { 1275 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 1276 } 1277 return (retval); 1278 } 1279 1280 /* 1281 * pam_open_session - begin session management 1282 */ 1283 1284 int 1285 pam_open_session(pam_handle_t *pamh, int flags) 1286 { 1287 int retval; 1288 1289 retval = run_stack(pamh, flags, PAM_SESSION_MODULE, PAM_SESSION_ERR, 1290 PAM_OPEN_SESSION, "pam_open_session"); 1291 1292 if (retval != PAM_SUCCESS) 1293 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 1294 return (retval); 1295 } 1296 1297 /* 1298 * pam_close_session - terminate session management 1299 */ 1300 1301 int 1302 pam_close_session(pam_handle_t *pamh, int flags) 1303 { 1304 int retval; 1305 1306 retval = run_stack(pamh, flags, PAM_SESSION_MODULE, PAM_SESSION_ERR, 1307 PAM_CLOSE_SESSION, "pam_close_session"); 1308 1309 if (retval != PAM_SUCCESS) 1310 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 1311 return (retval); 1312 } 1313 1314 /* 1315 * pam_chauthtok - change user authentication token 1316 */ 1317 1318 int 1319 pam_chauthtok(pam_handle_t *pamh, int flags) 1320 { 1321 int retval; 1322 1323 /* do not let apps use PAM_PRELIM_CHECK or PAM_UPDATE_AUTHTOK */ 1324 if (flags & (PAM_PRELIM_CHECK | PAM_UPDATE_AUTHTOK)) { 1325 pam_trace(PAM_DEBUG_DEFAULT, 1326 "pam_chauthtok(%p, %x): %s", (void *)pamh, flags, 1327 pam_strerror(pamh, PAM_SYMBOL_ERR)); 1328 return (PAM_SYMBOL_ERR); 1329 } 1330 1331 /* 1st pass: PRELIM CHECK */ 1332 retval = run_stack(pamh, flags | PAM_PRELIM_CHECK, PAM_PASSWORD_MODULE, 1333 PAM_AUTHTOK_ERR, PAM_CHAUTHTOK, "pam_chauthtok-prelim"); 1334 1335 if (retval == PAM_TRY_AGAIN) 1336 return (retval); 1337 1338 if (retval != PAM_SUCCESS) { 1339 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 1340 return (retval); 1341 } 1342 1343 /* 2nd pass: UPDATE AUTHTOK */ 1344 retval = run_stack(pamh, flags | PAM_UPDATE_AUTHTOK, 1345 PAM_PASSWORD_MODULE, PAM_AUTHTOK_ERR, PAM_CHAUTHTOK, 1346 "pam_chauthtok-update"); 1347 1348 if (retval != PAM_SUCCESS) 1349 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 1350 1351 return (retval); 1352 } 1353 1354 /* 1355 * pam_putenv - add an environment variable to the PAM handle 1356 * if name_value == 'NAME=VALUE' then set variable to the value 1357 * if name_value == 'NAME=' then set variable to an empty value 1358 * if name_value == 'NAME' then delete the variable 1359 */ 1360 1361 int 1362 pam_putenv(pam_handle_t *pamh, const char *name_value) 1363 { 1364 int error = PAM_SYSTEM_ERR; 1365 char *equal_sign = 0; 1366 char *name = NULL, *value = NULL, *tmp_value = NULL; 1367 env_list *traverse, *trail; 1368 1369 pam_trace(PAM_DEBUG_DEFAULT, 1370 "pam_putenv(%p, %s)", (void *)pamh, 1371 name_value ? name_value : "NULL"); 1372 1373 if (pamh == NULL || name_value == NULL) 1374 goto out; 1375 1376 /* see if we were passed 'NAME=VALUE', 'NAME=', or 'NAME' */ 1377 if ((equal_sign = strchr(name_value, '=')) != 0) { 1378 if ((name = calloc(equal_sign - name_value + 1, 1379 sizeof (char))) == 0) { 1380 error = PAM_BUF_ERR; 1381 goto out; 1382 } 1383 (void) strncpy(name, name_value, equal_sign - name_value); 1384 if ((value = strdup(++equal_sign)) == 0) { 1385 error = PAM_BUF_ERR; 1386 goto out; 1387 } 1388 } else { 1389 if ((name = strdup(name_value)) == 0) { 1390 error = PAM_BUF_ERR; 1391 goto out; 1392 } 1393 } 1394 1395 /* check to see if we already have this variable in the PAM handle */ 1396 traverse = pamh->pam_env; 1397 trail = traverse; 1398 while (traverse && strncmp(traverse->name, name, strlen(name))) { 1399 trail = traverse; 1400 traverse = traverse->next; 1401 } 1402 1403 if (traverse) { 1404 /* found a match */ 1405 if (value == 0) { 1406 /* remove the env variable */ 1407 if (pamh->pam_env == traverse) 1408 pamh->pam_env = traverse->next; 1409 else 1410 trail->next = traverse->next; 1411 free_env(traverse); 1412 } else if (strlen(value) == 0) { 1413 /* set env variable to empty value */ 1414 if ((tmp_value = strdup("")) == 0) { 1415 error = PAM_SYSTEM_ERR; 1416 goto out; 1417 } 1418 free(traverse->value); 1419 traverse->value = tmp_value; 1420 } else { 1421 /* set the new value */ 1422 if ((tmp_value = strdup(value)) == 0) { 1423 error = PAM_SYSTEM_ERR; 1424 goto out; 1425 } 1426 free(traverse->value); 1427 traverse->value = tmp_value; 1428 } 1429 1430 } else if (traverse == 0 && value) { 1431 /* 1432 * could not find a match in the PAM handle. 1433 * add the new value if there is one 1434 */ 1435 if ((traverse = calloc(1, sizeof (env_list))) == 0) { 1436 error = PAM_BUF_ERR; 1437 goto out; 1438 } 1439 if ((traverse->name = strdup(name)) == 0) { 1440 free_env(traverse); 1441 error = PAM_BUF_ERR; 1442 goto out; 1443 } 1444 if ((traverse->value = strdup(value)) == 0) { 1445 free_env(traverse); 1446 error = PAM_BUF_ERR; 1447 goto out; 1448 } 1449 if (trail == 0) { 1450 /* new head of list */ 1451 pamh->pam_env = traverse; 1452 } else { 1453 /* adding to end of list */ 1454 trail->next = traverse; 1455 } 1456 } 1457 1458 error = PAM_SUCCESS; 1459 out: 1460 if (error != PAM_SUCCESS) { 1461 if (traverse) { 1462 if (traverse->name) 1463 free(traverse->name); 1464 if (traverse->value) 1465 free(traverse->value); 1466 free(traverse); 1467 } 1468 } 1469 if (name) 1470 free(name); 1471 if (value) 1472 free(value); 1473 return (error); 1474 } 1475 1476 /* 1477 * pam_getenv - retrieve an environment variable from the PAM handle 1478 */ 1479 char * 1480 pam_getenv(pam_handle_t *pamh, const char *name) 1481 { 1482 int error = PAM_SYSTEM_ERR; 1483 env_list *traverse; 1484 1485 pam_trace(PAM_DEBUG_DEFAULT, 1486 "pam_getenv(%p, %p)", (void *)pamh, (void *)name); 1487 1488 if (pamh == NULL || name == NULL) 1489 goto out; 1490 1491 /* check to see if we already have this variable in the PAM handle */ 1492 traverse = pamh->pam_env; 1493 while (traverse && strncmp(traverse->name, name, strlen(name))) { 1494 traverse = traverse->next; 1495 } 1496 error = (traverse ? PAM_SUCCESS : PAM_SYSTEM_ERR); 1497 pam_trace(PAM_DEBUG_DEFAULT, 1498 "pam_getenv(%p, %s)=%s", (void *)pamh, name, 1499 traverse ? traverse->value : "NULL"); 1500 out: 1501 return (error ? NULL : strdup(traverse->value)); 1502 } 1503 1504 /* 1505 * pam_getenvlist - retrieve all environment variables from the PAM handle 1506 * in a NULL terminated array. On error, return NULL. 1507 */ 1508 char ** 1509 pam_getenvlist(pam_handle_t *pamh) 1510 { 1511 int error = PAM_SYSTEM_ERR; 1512 char **list = 0; 1513 int length = 0; 1514 env_list *traverse; 1515 char *tenv; 1516 size_t tenv_size; 1517 1518 pam_trace(PAM_DEBUG_DEFAULT, 1519 "pam_getenvlist(%p)", (void *)pamh); 1520 1521 if (pamh == NULL) 1522 goto out; 1523 1524 /* find out how many environment variables we have */ 1525 traverse = pamh->pam_env; 1526 while (traverse) { 1527 length++; 1528 traverse = traverse->next; 1529 } 1530 1531 /* allocate the array we will return to the caller */ 1532 if ((list = calloc(length + 1, sizeof (char *))) == NULL) { 1533 error = PAM_BUF_ERR; 1534 goto out; 1535 } 1536 1537 /* add the variables one by one */ 1538 length = 0; 1539 traverse = pamh->pam_env; 1540 while (traverse != NULL) { 1541 tenv_size = strlen(traverse->name) + 1542 strlen(traverse->value) + 2; /* name=val\0 */ 1543 if ((tenv = malloc(tenv_size)) == NULL) { 1544 error = PAM_BUF_ERR; 1545 goto out; 1546 } 1547 /*LINTED*/ 1548 (void) sprintf(tenv, "%s=%s", traverse->name, traverse->value); 1549 list[length++] = tenv; 1550 traverse = traverse->next; 1551 } 1552 list[length] = NULL; 1553 1554 error = PAM_SUCCESS; 1555 out: 1556 if (error != PAM_SUCCESS) { 1557 /* free the partially constructed list */ 1558 if (list) { 1559 length = 0; 1560 while (list[length] != NULL) { 1561 free(list[length]); 1562 length++; 1563 } 1564 free(list); 1565 } 1566 } 1567 return (error ? NULL : list); 1568 } 1569 1570 /* 1571 * Routines to load a requested module on demand 1572 */ 1573 1574 /* 1575 * load_modules - load the requested module. 1576 * if the dlopen or dlsym fail, then 1577 * the module is ignored. 1578 */ 1579 1580 static int 1581 load_modules(pam_handle_t *pamh, int type, char *function_name, 1582 pamtab_t *pam_entry) 1583 { 1584 void *mh; 1585 struct auth_module *authp; 1586 struct account_module *accountp; 1587 struct session_module *sessionp; 1588 struct password_module *passwdp; 1589 int loading_functions = 0; /* are we currently loading functions? */ 1590 1591 pam_trace(PAM_DEBUG_MODULE, "load_modules[%d:%s](%p, %s)=%s:%s", 1592 pamh->include_depth, pam_trace_cname(pamh), (void *)pamh, 1593 function_name, pam_trace_fname(pam_entry->pam_flag), 1594 pam_entry->module_path); 1595 1596 while (pam_entry != NULL) { 1597 pam_trace(PAM_DEBUG_DEFAULT, 1598 "while load_modules[%d:%s](%p, %s)=%s", 1599 pamh->include_depth, pam_trace_cname(pamh), (void *)pamh, 1600 function_name, pam_entry->module_path); 1601 1602 if (pam_entry->pam_flag & PAM_INCLUDE) { 1603 pam_trace(PAM_DEBUG_DEFAULT, 1604 "done load_modules[%d:%s](%p, %s)=%s", 1605 pamh->include_depth, pam_trace_cname(pamh), 1606 (void *)pamh, function_name, 1607 pam_entry->module_path); 1608 return (PAM_SUCCESS); 1609 } 1610 switch (type) { 1611 case PAM_AUTH_MODULE: 1612 1613 /* if the function has already been loaded, return */ 1614 authp = pam_entry->function_ptr; 1615 if (!loading_functions && 1616 (((strcmp(function_name, PAM_SM_AUTHENTICATE) 1617 == 0) && authp && authp->pam_sm_authenticate) || 1618 ((strcmp(function_name, PAM_SM_SETCRED) == 0) && 1619 authp && authp->pam_sm_setcred))) { 1620 return (PAM_SUCCESS); 1621 } 1622 1623 /* function has not been loaded yet */ 1624 loading_functions = 1; 1625 if (authp == NULL) { 1626 authp = calloc(1, sizeof (struct auth_module)); 1627 if (authp == NULL) 1628 return (PAM_BUF_ERR); 1629 } 1630 1631 /* if open_module fails, return error */ 1632 if ((mh = open_module(pamh, 1633 pam_entry->module_path)) == NULL) { 1634 __pam_log(LOG_AUTH | LOG_ERR, 1635 "load_modules[%d:%s]: can not open module " 1636 "%s", pamh->include_depth, 1637 pam_trace_cname(pamh), 1638 pam_entry->module_path); 1639 free(authp); 1640 return (PAM_OPEN_ERR); 1641 } 1642 1643 /* load the authentication function */ 1644 if (strcmp(function_name, PAM_SM_AUTHENTICATE) == 0) { 1645 if (load_function(mh, PAM_SM_AUTHENTICATE, 1646 &authp->pam_sm_authenticate) 1647 != PAM_SUCCESS) { 1648 /* return error if dlsym fails */ 1649 free(authp); 1650 return (PAM_SYMBOL_ERR); 1651 } 1652 1653 /* load the setcred function */ 1654 } else if (strcmp(function_name, PAM_SM_SETCRED) == 0) { 1655 if (load_function(mh, PAM_SM_SETCRED, 1656 &authp->pam_sm_setcred) != PAM_SUCCESS) { 1657 /* return error if dlsym fails */ 1658 free(authp); 1659 return (PAM_SYMBOL_ERR); 1660 } 1661 } 1662 pam_entry->function_ptr = authp; 1663 break; 1664 case PAM_ACCOUNT_MODULE: 1665 accountp = pam_entry->function_ptr; 1666 if (!loading_functions && 1667 (strcmp(function_name, PAM_SM_ACCT_MGMT) == 0) && 1668 accountp && accountp->pam_sm_acct_mgmt) { 1669 return (PAM_SUCCESS); 1670 } 1671 1672 /* 1673 * If functions are added to the account module, 1674 * verify that one of the other functions hasn't 1675 * already loaded it. See PAM_AUTH_MODULE code. 1676 */ 1677 loading_functions = 1; 1678 accountp = calloc(1, sizeof (struct account_module)); 1679 if (accountp == NULL) 1680 return (PAM_BUF_ERR); 1681 1682 /* if open_module fails, return error */ 1683 if ((mh = open_module(pamh, 1684 pam_entry->module_path)) == NULL) { 1685 __pam_log(LOG_AUTH | LOG_ERR, 1686 "load_modules[%d:%s]: can not open module " 1687 "%s", pamh->include_depth, 1688 pam_trace_cname(pamh), 1689 pam_entry->module_path); 1690 free(accountp); 1691 return (PAM_OPEN_ERR); 1692 } 1693 1694 if (load_function(mh, PAM_SM_ACCT_MGMT, 1695 &accountp->pam_sm_acct_mgmt) != PAM_SUCCESS) { 1696 __pam_log(LOG_AUTH | LOG_ERR, 1697 "load_modules[%d:%s]: pam_sm_acct_mgmt() " 1698 "missing", pamh->include_depth, 1699 pam_trace_cname(pamh)); 1700 free(accountp); 1701 return (PAM_SYMBOL_ERR); 1702 } 1703 pam_entry->function_ptr = accountp; 1704 break; 1705 case PAM_SESSION_MODULE: 1706 sessionp = pam_entry->function_ptr; 1707 if (!loading_functions && 1708 (((strcmp(function_name, 1709 PAM_SM_OPEN_SESSION) == 0) && 1710 sessionp && sessionp->pam_sm_open_session) || 1711 ((strcmp(function_name, 1712 PAM_SM_CLOSE_SESSION) == 0) && 1713 sessionp && sessionp->pam_sm_close_session))) { 1714 return (PAM_SUCCESS); 1715 } 1716 1717 loading_functions = 1; 1718 if (sessionp == NULL) { 1719 sessionp = calloc(1, 1720 sizeof (struct session_module)); 1721 if (sessionp == NULL) 1722 return (PAM_BUF_ERR); 1723 } 1724 1725 /* if open_module fails, return error */ 1726 if ((mh = open_module(pamh, 1727 pam_entry->module_path)) == NULL) { 1728 __pam_log(LOG_AUTH | LOG_ERR, 1729 "load_modules[%d:%s]: can not open module " 1730 "%s", pamh->include_depth, 1731 pam_trace_cname(pamh), 1732 pam_entry->module_path); 1733 free(sessionp); 1734 return (PAM_OPEN_ERR); 1735 } 1736 1737 if ((strcmp(function_name, PAM_SM_OPEN_SESSION) == 0) && 1738 load_function(mh, PAM_SM_OPEN_SESSION, 1739 &sessionp->pam_sm_open_session) != PAM_SUCCESS) { 1740 free(sessionp); 1741 return (PAM_SYMBOL_ERR); 1742 } else if ((strcmp(function_name, 1743 PAM_SM_CLOSE_SESSION) == 0) && 1744 load_function(mh, PAM_SM_CLOSE_SESSION, 1745 &sessionp->pam_sm_close_session) != PAM_SUCCESS) { 1746 free(sessionp); 1747 return (PAM_SYMBOL_ERR); 1748 } 1749 pam_entry->function_ptr = sessionp; 1750 break; 1751 case PAM_PASSWORD_MODULE: 1752 passwdp = pam_entry->function_ptr; 1753 if (!loading_functions && 1754 (strcmp(function_name, PAM_SM_CHAUTHTOK) == 0) && 1755 passwdp && passwdp->pam_sm_chauthtok) { 1756 return (PAM_SUCCESS); 1757 } 1758 1759 /* 1760 * If functions are added to the password module, 1761 * verify that one of the other functions hasn't 1762 * already loaded it. See PAM_AUTH_MODULE code. 1763 */ 1764 loading_functions = 1; 1765 passwdp = calloc(1, sizeof (struct password_module)); 1766 if (passwdp == NULL) 1767 return (PAM_BUF_ERR); 1768 1769 /* if open_module fails, continue */ 1770 if ((mh = open_module(pamh, 1771 pam_entry->module_path)) == NULL) { 1772 __pam_log(LOG_AUTH | LOG_ERR, 1773 "load_modules[%d:%s]: can not open module " 1774 "%s", pamh->include_depth, 1775 pam_trace_cname(pamh), 1776 pam_entry->module_path); 1777 free(passwdp); 1778 return (PAM_OPEN_ERR); 1779 } 1780 1781 if (load_function(mh, PAM_SM_CHAUTHTOK, 1782 &passwdp->pam_sm_chauthtok) != PAM_SUCCESS) { 1783 free(passwdp); 1784 return (PAM_SYMBOL_ERR); 1785 } 1786 pam_entry->function_ptr = passwdp; 1787 break; 1788 default: 1789 pam_trace(PAM_DEBUG_DEFAULT, 1790 "load_modules[%d:%s](%p, %s): unsupported type %d", 1791 pamh->include_depth, pam_trace_cname(pamh), 1792 (void *)pamh, function_name, type); 1793 break; 1794 } 1795 1796 pam_entry = pam_entry->next; 1797 } /* while */ 1798 1799 pam_trace(PAM_DEBUG_MODULE, "load_modules[%d:%s](%p, %s)=done", 1800 pamh->include_depth, pam_trace_cname(pamh), (void *)pamh, 1801 function_name); 1802 1803 return (PAM_SUCCESS); 1804 } 1805 1806 /* 1807 * open_module - Open the module first checking for 1808 * propers modes and ownerships on the file. 1809 */ 1810 1811 static void * 1812 open_module(pam_handle_t *pamh, char *module_so) 1813 { 1814 struct stat64 stb; 1815 char *errmsg; 1816 void *lfd; 1817 fd_list *module_fds = 0; 1818 fd_list *trail = 0; 1819 fd_list *traverse = 0; 1820 1821 /* Check the ownership and file modes */ 1822 if (stat64(module_so, &stb) < 0) { 1823 __pam_log(LOG_AUTH | LOG_ERR, 1824 "open_module[%d:%s]: stat(%s) failed: %s", 1825 pamh->include_depth, pam_trace_cname(pamh), module_so, 1826 strerror(errno)); 1827 return (NULL); 1828 } 1829 if (stb.st_uid != (uid_t)0) { 1830 __pam_log(LOG_AUTH | LOG_ALERT, 1831 "open_module[%d:%s]: Owner of the module %s is not root", 1832 pamh->include_depth, pam_trace_cname(pamh), module_so); 1833 return (NULL); 1834 } 1835 if (stb.st_mode & S_IWGRP) { 1836 __pam_log(LOG_AUTH | LOG_ALERT, 1837 "open_module[%d:%s]: module %s writable by group", 1838 pamh->include_depth, pam_trace_cname(pamh), module_so); 1839 return (NULL); 1840 } 1841 if (stb.st_mode & S_IWOTH) { 1842 __pam_log(LOG_AUTH | LOG_ALERT, 1843 "open_module[%d:%s]: module %s writable by world", 1844 pamh->include_depth, pam_trace_cname(pamh), module_so); 1845 return (NULL); 1846 } 1847 1848 /* 1849 * Perform the dlopen() 1850 */ 1851 lfd = (void *)dlopen(module_so, RTLD_LAZY); 1852 1853 if (lfd == NULL) { 1854 errmsg = dlerror(); 1855 __pam_log(LOG_AUTH | LOG_ERR, "open_module[%d:%s]: %s " 1856 "failed: %s", pamh->include_depth, pam_trace_cname(pamh), 1857 module_so, errmsg != NULL ? errmsg : "Unknown error"); 1858 return (NULL); 1859 } else { 1860 /* add this fd to the pam handle */ 1861 if ((module_fds = calloc(1, sizeof (fd_list))) == 0) { 1862 (void) dlclose(lfd); 1863 lfd = 0; 1864 return (NULL); 1865 } 1866 module_fds->mh = lfd; 1867 1868 if (pamh->fd == 0) { 1869 /* adding new head of list */ 1870 pamh->fd = module_fds; 1871 } else { 1872 /* appending to end of list */ 1873 traverse = pamh->fd; 1874 while (traverse) { 1875 trail = traverse; 1876 traverse = traverse->next; 1877 } 1878 trail->next = module_fds; 1879 } 1880 } 1881 1882 return (lfd); 1883 } 1884 1885 /* 1886 * load_function - call dlsym() to resolve the function address 1887 */ 1888 static int 1889 load_function(void *lfd, char *name, int (**func)()) 1890 { 1891 char *errmsg = NULL; 1892 1893 if (lfd == NULL) 1894 return (PAM_SYMBOL_ERR); 1895 1896 *func = (int (*)())dlsym(lfd, name); 1897 if (*func == NULL) { 1898 errmsg = dlerror(); 1899 __pam_log(LOG_AUTH | LOG_ERR, "dlsym failed %s: error %s", 1900 name, errmsg != NULL ? errmsg : "Unknown error"); 1901 return (PAM_SYMBOL_ERR); 1902 } 1903 1904 pam_trace(PAM_DEBUG_DEFAULT, 1905 "load_function: successful load of %s", name); 1906 return (PAM_SUCCESS); 1907 } 1908 1909 /* 1910 * Routines to read the pam.conf configuration file 1911 */ 1912 1913 /* 1914 * open_pam_conf - open the pam.conf config file 1915 */ 1916 1917 static int 1918 open_pam_conf(struct pam_fh **pam_fh, pam_handle_t *pamh, char *config) 1919 { 1920 struct stat64 stb; 1921 int fd; 1922 1923 if ((fd = open(config, O_RDONLY)) == -1) { 1924 __pam_log(LOG_AUTH | LOG_ALERT, 1925 "open_pam_conf[%d:%s]: open(%s) failed: %s", 1926 pamh->include_depth, pam_trace_cname(pamh), config, 1927 strerror(errno)); 1928 return (0); 1929 } 1930 /* Check the ownership and file modes */ 1931 if (fstat64(fd, &stb) < 0) { 1932 __pam_log(LOG_AUTH | LOG_ALERT, 1933 "open_pam_conf[%d:%s]: stat(%s) failed: %s", 1934 pamh->include_depth, pam_trace_cname(pamh), config, 1935 strerror(errno)); 1936 (void) close(fd); 1937 return (0); 1938 } 1939 if (stb.st_uid != (uid_t)0) { 1940 __pam_log(LOG_AUTH | LOG_ALERT, 1941 "open_pam_conf[%d:%s]: Owner of %s is not root", 1942 pamh->include_depth, pam_trace_cname(pamh), config); 1943 (void) close(fd); 1944 return (0); 1945 } 1946 if (stb.st_mode & S_IWGRP) { 1947 __pam_log(LOG_AUTH | LOG_ALERT, 1948 "open_pam_conf[%d:%s]: %s writable by group", 1949 pamh->include_depth, pam_trace_cname(pamh), config); 1950 (void) close(fd); 1951 return (0); 1952 } 1953 if (stb.st_mode & S_IWOTH) { 1954 __pam_log(LOG_AUTH | LOG_ALERT, 1955 "open_pam_conf[%d:%s]: %s writable by world", 1956 pamh->include_depth, pam_trace_cname(pamh), config); 1957 (void) close(fd); 1958 return (0); 1959 } 1960 if ((*pam_fh = calloc(1, sizeof (struct pam_fh))) == NULL) { 1961 (void) close(fd); 1962 return (0); 1963 } 1964 (*pam_fh)->fconfig = fd; 1965 (*pam_fh)->bufsize = (size_t)stb.st_size; 1966 if (((*pam_fh)->data = mmap(0, (*pam_fh)->bufsize, PROT_READ, 1967 MAP_PRIVATE, (*pam_fh)->fconfig, 0)) == MAP_FAILED) { 1968 (void) close(fd); 1969 free (*pam_fh); 1970 return (0); 1971 } 1972 (*pam_fh)->bufferp = (*pam_fh)->data; 1973 1974 return (1); 1975 } 1976 1977 /* 1978 * close_pam_conf - close pam.conf 1979 */ 1980 1981 static void 1982 close_pam_conf(struct pam_fh *pam_fh) 1983 { 1984 (void) munmap(pam_fh->data, pam_fh->bufsize); 1985 (void) close(pam_fh->fconfig); 1986 free(pam_fh); 1987 } 1988 1989 /* 1990 * read_pam_conf - read in each entry in pam.conf and store info 1991 * under the pam handle. 1992 */ 1993 1994 static int 1995 read_pam_conf(pam_handle_t *pamh, char *config) 1996 { 1997 struct pam_fh *pam_fh; 1998 pamtab_t *pamentp; 1999 pamtab_t *tpament; 2000 char *service; 2001 int error; 2002 int i = pamh->include_depth; /* include depth */ 2003 /* 2004 * service types: 2005 * error (-1), "auth" (0), "account" (1), "session" (2), "password" (3) 2006 */ 2007 int service_found[PAM_NUM_MODULE_TYPES+1] = {0, 0, 0, 0, 0}; 2008 2009 (void) pam_get_item(pamh, PAM_SERVICE, (void **)&service); 2010 if (service == NULL || *service == '\0') { 2011 __pam_log(LOG_AUTH | LOG_ERR, "No service name"); 2012 return (PAM_SYSTEM_ERR); 2013 } 2014 2015 pamh->pam_conf_name[i] = strdup(config); 2016 pam_trace(PAM_DEBUG_CONF, "read_pam_conf[%d:%s](%p) open(%s)", 2017 i, pam_trace_cname(pamh), (void *)pamh, config); 2018 if (open_pam_conf(&pam_fh, pamh, config) == 0) { 2019 return (PAM_SYSTEM_ERR); 2020 } 2021 2022 while ((error = 2023 get_pam_conf_entry(pam_fh, pamh, &pamentp)) == PAM_SUCCESS && 2024 pamentp) { 2025 2026 /* See if entry is this service and valid */ 2027 if (verify_pam_conf(pamentp, service)) { 2028 pam_trace(PAM_DEBUG_CONF, 2029 "read_pam_conf[%d:%s](%p): bad entry error %s", 2030 i, pam_trace_cname(pamh), (void *)pamh, service); 2031 2032 error = PAM_SYSTEM_ERR; 2033 free_pamconf(pamentp); 2034 goto out; 2035 } 2036 if (strcasecmp(pamentp->pam_service, service) == 0) { 2037 pam_trace(PAM_DEBUG_CONF, 2038 "read_pam_conf[%d:%s](%p): processing %s", 2039 i, pam_trace_cname(pamh), (void *)pamh, service); 2040 /* process first service entry */ 2041 if (service_found[pamentp->pam_type + 1] == 0) { 2042 /* purge "other" entries */ 2043 while ((tpament = pamh->pam_conf_info[i] 2044 [pamentp->pam_type]) != NULL) { 2045 pam_trace(PAM_DEBUG_CONF, 2046 "read_pam_conf(%p): purging " 2047 "\"other\"[%d:%s][%s]", 2048 (void *)pamh, i, 2049 pam_trace_cname(pamh), 2050 pam_snames[pamentp->pam_type]); 2051 pamh->pam_conf_info[i] 2052 [pamentp->pam_type] = tpament->next; 2053 free_pamconf(tpament); 2054 } 2055 /* add first service entry */ 2056 pam_trace(PAM_DEBUG_CONF, 2057 "read_pam_conf(%p): adding 1st " 2058 "%s[%d:%s][%s]", 2059 (void *)pamh, service, i, 2060 pam_trace_cname(pamh), 2061 pam_snames[pamentp->pam_type]); 2062 pamh->pam_conf_info[i][pamentp->pam_type] = 2063 pamentp; 2064 service_found[pamentp->pam_type + 1] = 1; 2065 } else { 2066 /* append more service entries */ 2067 pam_trace(PAM_DEBUG_CONF, 2068 "read_pam_conf(%p): adding more " 2069 "%s[%d:%s][%s]", 2070 (void *)pamh, service, i, 2071 pam_trace_cname(pamh), 2072 pam_snames[pamentp->pam_type]); 2073 tpament = 2074 pamh->pam_conf_info[i][pamentp->pam_type]; 2075 while (tpament->next != NULL) { 2076 tpament = tpament->next; 2077 } 2078 tpament->next = pamentp; 2079 } 2080 } else if (service_found[pamentp->pam_type + 1] == 0) { 2081 /* See if "other" entry available and valid */ 2082 if (verify_pam_conf(pamentp, "other")) { 2083 pam_trace(PAM_DEBUG_CONF, 2084 "read_pam_conf(%p): bad entry error %s " 2085 "\"other\"[%d:%s]", 2086 (void *)pamh, service, i, 2087 pam_trace_cname(pamh)); 2088 error = PAM_SYSTEM_ERR; 2089 free_pamconf(pamentp); 2090 goto out; 2091 } 2092 if (strcasecmp(pamentp->pam_service, "other") == 0) { 2093 pam_trace(PAM_DEBUG_CONF, 2094 "read_pam_conf(%p): processing " 2095 "\"other\"[%d:%s]", (void *)pamh, i, 2096 pam_trace_cname(pamh)); 2097 if ((tpament = pamh->pam_conf_info[i] 2098 [pamentp->pam_type]) == NULL) { 2099 /* add first "other" entry */ 2100 pam_trace(PAM_DEBUG_CONF, 2101 "read_pam_conf(%p): adding 1st " 2102 "other[%d:%s][%s]", (void *)pamh, i, 2103 pam_trace_cname(pamh), 2104 pam_snames[pamentp->pam_type]); 2105 pamh->pam_conf_info[i] 2106 [pamentp->pam_type] = pamentp; 2107 } else { 2108 /* append more "other" entries */ 2109 pam_trace(PAM_DEBUG_CONF, 2110 "read_pam_conf(%p): adding more " 2111 "other[%d:%s][%s]", (void *)pamh, i, 2112 pam_trace_cname(pamh), 2113 pam_snames[pamentp->pam_type]); 2114 while (tpament->next != NULL) { 2115 tpament = tpament->next; 2116 } 2117 tpament->next = pamentp; 2118 } 2119 } else { 2120 /* irrelevant entry */ 2121 free_pamconf(pamentp); 2122 } 2123 } else { 2124 /* irrelevant entry */ 2125 free_pamconf(pamentp); 2126 } 2127 } 2128 out: 2129 (void) close_pam_conf(pam_fh); 2130 if (error != PAM_SUCCESS) 2131 free_pam_conf_info(pamh); 2132 return (error); 2133 } 2134 2135 /* 2136 * get_pam_conf_entry - get a pam.conf entry 2137 */ 2138 2139 static int 2140 get_pam_conf_entry(struct pam_fh *pam_fh, pam_handle_t *pamh, pamtab_t **pam) 2141 { 2142 char *cp, *arg; 2143 int argc; 2144 char *tmp, *tmp_free; 2145 int i; 2146 char *current_line = NULL; 2147 int error = PAM_SYSTEM_ERR; /* preset to error */ 2148 int err; 2149 2150 /* get the next line from pam.conf */ 2151 if ((cp = nextline(pam_fh, pamh, &err)) == NULL) { 2152 /* no more lines in pam.conf ==> return */ 2153 error = PAM_SUCCESS; 2154 *pam = NULL; 2155 goto out; 2156 } 2157 2158 if ((*pam = calloc(1, sizeof (pamtab_t))) == NULL) { 2159 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory"); 2160 goto out; 2161 } 2162 2163 /* copy full line for error reporting */ 2164 if ((current_line = strdup(cp)) == NULL) { 2165 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory"); 2166 goto out; 2167 } 2168 2169 pam_trace(PAM_DEBUG_CONF, 2170 "pam.conf[%s] entry:\t%s", pam_trace_cname(pamh), current_line); 2171 2172 /* get service name (e.g. login, su, passwd) */ 2173 if ((arg = read_next_token(&cp)) == 0) { 2174 __pam_log(LOG_AUTH | LOG_CRIT, 2175 "illegal pam.conf[%s] entry: %s: missing SERVICE NAME", 2176 pam_trace_cname(pamh), current_line); 2177 goto out; 2178 } 2179 if (((*pam)->pam_service = strdup(arg)) == 0) { 2180 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory"); 2181 goto out; 2182 } 2183 2184 /* get module type (e.g. authentication, acct mgmt) */ 2185 if ((arg = read_next_token(&cp)) == 0) { 2186 __pam_log(LOG_AUTH | LOG_CRIT, 2187 "illegal pam.conf[%s] entry: %s: missing MODULE TYPE", 2188 pam_trace_cname(pamh), current_line); 2189 (*pam)->pam_type = -1; /* 0 is a valid value */ 2190 goto getflag; 2191 } 2192 if (strcasecmp(arg, PAM_AUTH_NAME) == 0) { 2193 (*pam)->pam_type = PAM_AUTH_MODULE; 2194 } else if (strcasecmp(arg, PAM_ACCOUNT_NAME) == 0) { 2195 (*pam)->pam_type = PAM_ACCOUNT_MODULE; 2196 } else if (strcasecmp(arg, PAM_SESSION_NAME) == 0) { 2197 (*pam)->pam_type = PAM_SESSION_MODULE; 2198 } else if (strcasecmp(arg, PAM_PASSWORD_NAME) == 0) { 2199 (*pam)->pam_type = PAM_PASSWORD_MODULE; 2200 } else { 2201 /* error */ 2202 __pam_log(LOG_AUTH | LOG_CRIT, 2203 "illegal pam.conf[%s] entry: %s: invalid module " 2204 "type: %s", pam_trace_cname(pamh), current_line, arg); 2205 (*pam)->pam_type = -1; /* 0 is a valid value */ 2206 } 2207 2208 getflag: 2209 /* get pam flag (e.g., requisite, required, sufficient, optional) */ 2210 if ((arg = read_next_token(&cp)) == 0) { 2211 __pam_log(LOG_AUTH | LOG_CRIT, 2212 "illegal pam.conf[%s] entry: %s: missing CONTROL FLAG", 2213 pam_trace_cname(pamh), current_line); 2214 goto getpath; 2215 } 2216 if (strcasecmp(arg, PAM_BINDING_NAME) == 0) { 2217 (*pam)->pam_flag = PAM_BINDING; 2218 } else if (strcasecmp(arg, PAM_INCLUDE_NAME) == 0) { 2219 (*pam)->pam_flag = PAM_INCLUDE; 2220 } else if (strcasecmp(arg, PAM_OPTIONAL_NAME) == 0) { 2221 (*pam)->pam_flag = PAM_OPTIONAL; 2222 } else if (strcasecmp(arg, PAM_REQUIRED_NAME) == 0) { 2223 (*pam)->pam_flag = PAM_REQUIRED; 2224 } else if (strcasecmp(arg, PAM_REQUISITE_NAME) == 0) { 2225 (*pam)->pam_flag = PAM_REQUISITE; 2226 } else if (strcasecmp(arg, PAM_SUFFICIENT_NAME) == 0) { 2227 (*pam)->pam_flag = PAM_SUFFICIENT; 2228 } else { 2229 /* error */ 2230 __pam_log(LOG_AUTH | LOG_CRIT, 2231 "illegal pam.conf[%s] entry: %s", 2232 pam_trace_cname(pamh), current_line); 2233 __pam_log(LOG_AUTH | LOG_CRIT, 2234 "\tinvalid control flag: %s", arg); 2235 } 2236 2237 getpath: 2238 /* get module path (e.g. /usr/lib/security/pam_unix_auth.so.1) */ 2239 if ((arg = read_next_token(&cp)) == 0) { 2240 __pam_log(LOG_AUTH | LOG_CRIT, 2241 "illegal pam.conf[%s] entry: %s: missing MODULE PATH", 2242 pam_trace_cname(pamh), current_line); 2243 error = PAM_SUCCESS; /* success */ 2244 goto out; 2245 } 2246 if (arg[0] != '/') { 2247 size_t len; 2248 /* 2249 * If module path does not start with "/", then 2250 * prepend PAM_LIB_DIR (/usr/lib/security/). 2251 */ 2252 /* sizeof (PAM_LIB_DIR) has room for '\0' */ 2253 len = sizeof (PAM_LIB_DIR) + sizeof (PAM_ISA_DIR) + strlen(arg); 2254 if (((*pam)->module_path = malloc(len)) == NULL) { 2255 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory"); 2256 goto out; 2257 } 2258 if ((*pam)->pam_flag & PAM_INCLUDE) { 2259 (void) snprintf((*pam)->module_path, len, "%s%s", 2260 PAM_LIB_DIR, arg); 2261 } else { 2262 (void) snprintf((*pam)->module_path, len, "%s%s%s", 2263 PAM_LIB_DIR, PAM_ISA_DIR, arg); 2264 } 2265 } else { 2266 /* Full path provided for module */ 2267 char *isa; 2268 2269 /* Check for Instruction Set Architecture indicator */ 2270 if ((isa = strstr(arg, PAM_ISA)) != NULL) { 2271 size_t len; 2272 len = strlen(arg) - (sizeof (PAM_ISA)-1) + 2273 sizeof (PAM_ISA_DIR); 2274 2275 /* substitute the architecture dependent path */ 2276 if (((*pam)->module_path = malloc(len)) == NULL) { 2277 __pam_log(LOG_AUTH | LOG_ERR, 2278 "strdup: out of memory"); 2279 goto out; 2280 } 2281 *isa = '\000'; 2282 isa += strlen(PAM_ISA); 2283 (void) snprintf((*pam)->module_path, len, "%s%s%s", 2284 arg, PAM_ISA_DIR, isa); 2285 } else if (((*pam)->module_path = strdup(arg)) == 0) { 2286 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory"); 2287 goto out; 2288 } 2289 } 2290 2291 /* count the number of module-specific options first */ 2292 argc = 0; 2293 if ((tmp = strdup(cp)) == NULL) { 2294 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory"); 2295 goto out; 2296 } 2297 tmp_free = tmp; 2298 for (arg = read_next_token(&tmp); arg; arg = read_next_token(&tmp)) 2299 argc++; 2300 free(tmp_free); 2301 2302 /* allocate array for the module-specific options */ 2303 if (argc > 0) { 2304 if (((*pam)->module_argv = 2305 calloc(argc+1, sizeof (char *))) == 0) { 2306 __pam_log(LOG_AUTH | LOG_ERR, "calloc: out of memory"); 2307 goto out; 2308 } 2309 i = 0; 2310 for (arg = read_next_token(&cp); arg; 2311 arg = read_next_token(&cp)) { 2312 (*pam)->module_argv[i] = strdup(arg); 2313 if ((*pam)->module_argv[i] == NULL) { 2314 __pam_log(LOG_AUTH | LOG_ERR, "strdup failed"); 2315 goto out; 2316 } 2317 i++; 2318 } 2319 (*pam)->module_argv[argc] = NULL; 2320 } 2321 (*pam)->module_argc = argc; 2322 2323 error = PAM_SUCCESS; /* success */ 2324 (*pam)->pam_err = err; /* was the line truncated */ 2325 2326 out: 2327 if (current_line) 2328 free(current_line); 2329 if (error != PAM_SUCCESS) { 2330 /* on error free this */ 2331 if (*pam) 2332 free_pamconf(*pam); 2333 } 2334 return (error); 2335 } 2336 2337 2338 /* 2339 * read_next_token - skip tab and space characters and return the next token 2340 */ 2341 2342 static char * 2343 read_next_token(char **cpp) 2344 { 2345 register char *cp = *cpp; 2346 char *start; 2347 2348 if (cp == (char *)0) { 2349 *cpp = (char *)0; 2350 return ((char *)0); 2351 } 2352 while (*cp == ' ' || *cp == '\t') 2353 cp++; 2354 if (*cp == '\0') { 2355 *cpp = (char *)0; 2356 return ((char *)0); 2357 } 2358 start = cp; 2359 while (*cp && *cp != ' ' && *cp != '\t') 2360 cp++; 2361 if (*cp != '\0') 2362 *cp++ = '\0'; 2363 *cpp = cp; 2364 return (start); 2365 } 2366 2367 static char * 2368 pam_conf_strnchr(char *sp, int c, intptr_t count) 2369 { 2370 while (count) { 2371 if (*sp == (char)c) 2372 return ((char *)sp); 2373 else { 2374 sp++; 2375 count--; 2376 } 2377 }; 2378 return (NULL); 2379 } 2380 2381 /* 2382 * nextline - skip all blank lines and comments 2383 */ 2384 2385 static char * 2386 nextline(struct pam_fh *pam_fh, pam_handle_t *pamh, int *err) 2387 { 2388 char *ll; 2389 int find_a_line = 0; 2390 char *data = pam_fh->data; 2391 char *bufferp = pam_fh->bufferp; 2392 char *bufferendp = &data[pam_fh->bufsize]; 2393 size_t input_len; 2394 2395 /* 2396 * Skip the blank line, comment line 2397 */ 2398 while (!find_a_line) { 2399 /* if we are at the end of the buffer, there is no next line */ 2400 if (bufferp == bufferendp) 2401 return (NULL); 2402 2403 /* skip blank line */ 2404 while (*bufferp == '\n') { 2405 /* 2406 * If we are at the end of the buffer, there is 2407 * no next line. 2408 */ 2409 if (++bufferp == bufferendp) { 2410 return (NULL); 2411 } 2412 /* else we check *bufferp again */ 2413 } 2414 2415 /* skip comment line */ 2416 while (*bufferp == '#') { 2417 if ((ll = pam_conf_strnchr(bufferp, '\n', 2418 bufferendp - bufferp)) != NULL) { 2419 bufferp = ll; 2420 } else { 2421 /* 2422 * this comment line the last line. 2423 * no next line 2424 */ 2425 return (NULL); 2426 } 2427 2428 /* 2429 * If we are at the end of the buffer, there is 2430 * no next line. 2431 */ 2432 if (bufferp == bufferendp) { 2433 return (NULL); 2434 } 2435 } 2436 2437 if ((*bufferp != '\n') && (*bufferp != '#')) { 2438 find_a_line = 1; 2439 } 2440 } 2441 2442 *err = PAM_SUCCESS; 2443 /* now we find one line */ 2444 if ((ll = pam_conf_strnchr(bufferp, '\n', bufferendp - bufferp)) 2445 != NULL) { 2446 if ((input_len = ll - bufferp) >= sizeof (pam_fh->line)) { 2447 __pam_log(LOG_AUTH | LOG_ERR, 2448 "nextline[%d:%s]: pam.conf line too long %.256s", 2449 pamh->include_depth, pam_trace_cname(pamh), 2450 bufferp); 2451 input_len = sizeof (pam_fh->line) - 1; 2452 *err = PAM_SERVICE_ERR; 2453 } 2454 (void) strncpy(pam_fh->line, bufferp, input_len); 2455 pam_fh->line[input_len] = '\0'; 2456 pam_fh->bufferp = ll++; 2457 } else { 2458 ll = bufferendp; 2459 if ((input_len = ll - bufferp) >= sizeof (pam_fh->line)) { 2460 __pam_log(LOG_AUTH | LOG_ERR, 2461 "nextline[%d:%s]: pam.conf line too long %.256s", 2462 pamh->include_depth, pam_trace_cname(pamh), 2463 bufferp); 2464 input_len = sizeof (pam_fh->line) - 1; 2465 *err = PAM_SERVICE_ERR; 2466 } 2467 (void) strncpy(pam_fh->line, bufferp, input_len); 2468 pam_fh->line[input_len] = '\0'; 2469 pam_fh->bufferp = ll; 2470 } 2471 2472 return (pam_fh->line); 2473 } 2474 2475 /* 2476 * verify_pam_conf - verify that the pam_conf entry is filled in. 2477 * 2478 * True = Error if there is no service. 2479 * True = Error if there is a service and it matches the requested service 2480 * but, the type, flag, line overflow, or path is in error. 2481 */ 2482 2483 static int 2484 verify_pam_conf(pamtab_t *pam, char *service) 2485 { 2486 return ((pam->pam_service == (char *)NULL) || 2487 ((strcasecmp(pam->pam_service, service) == 0) && 2488 ((pam->pam_type == -1) || 2489 (pam->pam_flag == 0) || 2490 (pam->pam_err != PAM_SUCCESS) || 2491 (pam->module_path == (char *)NULL)))); 2492 } 2493 2494 /* 2495 * Routines to free allocated storage 2496 */ 2497 2498 /* 2499 * clean_up - free allocated storage in the pam handle 2500 */ 2501 2502 static void 2503 clean_up(pam_handle_t *pamh) 2504 { 2505 int i; 2506 pam_repository_t *auth_rep; 2507 2508 if (pamh) { 2509 while (pamh->include_depth >= 0) { 2510 free_pam_conf_info(pamh); 2511 pamh->include_depth--; 2512 } 2513 2514 /* Cleanup PAM_REPOSITORY structure */ 2515 auth_rep = pamh->ps_item[PAM_REPOSITORY].pi_addr; 2516 if (auth_rep != NULL) { 2517 if (auth_rep->type != NULL) 2518 free(auth_rep->type); 2519 if (auth_rep->scope != NULL) 2520 free(auth_rep->scope); 2521 } 2522 2523 for (i = 0; i < PAM_MAX_ITEMS; i++) { 2524 if (pamh->ps_item[i].pi_addr != NULL) { 2525 if (i == PAM_AUTHTOK || i == PAM_OLDAUTHTOK) { 2526 (void) memset(pamh->ps_item[i].pi_addr, 2527 0, pamh->ps_item[i].pi_size); 2528 } 2529 free(pamh->ps_item[i].pi_addr); 2530 } 2531 } 2532 free(pamh); 2533 } 2534 } 2535 2536 /* 2537 * free_pamconf - free memory used to store pam.conf entry 2538 */ 2539 2540 static void 2541 free_pamconf(pamtab_t *cp) 2542 { 2543 int i; 2544 2545 if (cp) { 2546 if (cp->pam_service) 2547 free(cp->pam_service); 2548 if (cp->module_path) 2549 free(cp->module_path); 2550 for (i = 0; i < cp->module_argc; i++) { 2551 if (cp->module_argv[i]) 2552 free(cp->module_argv[i]); 2553 } 2554 if (cp->module_argc > 0) 2555 free(cp->module_argv); 2556 if (cp->function_ptr) 2557 free(cp->function_ptr); 2558 2559 free(cp); 2560 } 2561 } 2562 2563 /* 2564 * free_pam_conf_info - free memory used to store all pam.conf info 2565 * under the pam handle 2566 */ 2567 2568 static void 2569 free_pam_conf_info(pam_handle_t *pamh) 2570 { 2571 pamtab_t *pamentp; 2572 pamtab_t *pament_trail; 2573 int i = pamh->include_depth; 2574 int j; 2575 2576 for (j = 0; j < PAM_NUM_MODULE_TYPES; j++) { 2577 pamentp = pamh->pam_conf_info[i][j]; 2578 pamh->pam_conf_info[i][j] = NULL; 2579 pament_trail = pamentp; 2580 while (pamentp) { 2581 pamentp = pamentp->next; 2582 free_pamconf(pament_trail); 2583 pament_trail = pamentp; 2584 } 2585 } 2586 if (pamh->pam_conf_name[i] != NULL) { 2587 free(pamh->pam_conf_name[i]); 2588 pamh->pam_conf_name[i] = NULL; 2589 } 2590 } 2591 2592 static void 2593 free_env(env_list *pam_env) 2594 { 2595 if (pam_env) { 2596 if (pam_env->name) 2597 free(pam_env->name); 2598 if (pam_env->value) 2599 free(pam_env->value); 2600 free(pam_env); 2601 } 2602 } 2603 2604 /* 2605 * Internal convenience functions for Solaris PAM service modules. 2606 */ 2607 2608 #include <libintl.h> 2609 #include <nl_types.h> 2610 #include <synch.h> 2611 #include <locale.h> 2612 #include <thread.h> 2613 2614 typedef struct pam_msg_data { 2615 nl_catd fd; 2616 } pam_msg_data_t; 2617 2618 /* 2619 * free_resp(): 2620 * free storage for responses used in the call back "pam_conv" functions 2621 */ 2622 2623 void 2624 free_resp(int num_msg, struct pam_response *resp) 2625 { 2626 int i; 2627 struct pam_response *r; 2628 2629 if (resp) { 2630 r = resp; 2631 for (i = 0; i < num_msg; i++, r++) { 2632 if (r->resp) { 2633 /* clear before freeing -- may be a password */ 2634 bzero(r->resp, strlen(r->resp)); 2635 free(r->resp); 2636 r->resp = NULL; 2637 } 2638 } 2639 free(resp); 2640 } 2641 } 2642 2643 static int 2644 do_conv(pam_handle_t *pamh, int msg_style, int num_msg, 2645 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], void *conv_apdp, 2646 struct pam_response *ret_respp[]) 2647 { 2648 struct pam_message *msg; 2649 struct pam_message *m; 2650 int i; 2651 int k; 2652 int retcode; 2653 struct pam_conv *pam_convp; 2654 2655 if ((retcode = pam_get_item(pamh, PAM_CONV, 2656 (void **)&pam_convp)) != PAM_SUCCESS) { 2657 return (retcode); 2658 } 2659 2660 /* 2661 * When pam_set_item() is called to set PAM_CONV and the 2662 * item is NULL, memset(pip->pi_addr, 0, size) is called. 2663 * So at this point, we should check whether pam_convp->conv 2664 * is NULL or not. 2665 */ 2666 if ((pam_convp == NULL) || (pam_convp->conv == NULL)) 2667 return (PAM_SYSTEM_ERR); 2668 2669 i = 0; 2670 k = num_msg; 2671 2672 msg = calloc(num_msg, sizeof (struct pam_message)); 2673 if (msg == NULL) { 2674 return (PAM_BUF_ERR); 2675 } 2676 m = msg; 2677 2678 while (k--) { 2679 /* 2680 * fill out the message structure to display prompt message 2681 */ 2682 m->msg_style = msg_style; 2683 m->msg = messages[i]; 2684 pam_trace(PAM_DEBUG_CONV, 2685 "pam_conv_msg(%p:%d[%d]=%s)", 2686 (void *)pamh, msg_style, i, messages[i]); 2687 m++; 2688 i++; 2689 } 2690 2691 /* 2692 * The UNIX pam modules always calls __pam_get_authtok() and 2693 * __pam_display_msg() with a NULL pointer as the conv_apdp. 2694 * In case the conv_apdp is NULL and the pam_convp->appdata_ptr 2695 * is not NULL, we should pass the pam_convp->appdata_ptr 2696 * to the conversation function. 2697 */ 2698 if (conv_apdp == NULL && pam_convp->appdata_ptr != NULL) 2699 conv_apdp = pam_convp->appdata_ptr; 2700 2701 /* 2702 * Call conv function to display the prompt. 2703 */ 2704 retcode = (pam_convp->conv)(num_msg, &msg, ret_respp, conv_apdp); 2705 pam_trace(PAM_DEBUG_CONV, 2706 "pam_conv_resp(%p pam_conv = %s) ret_respp = %p", 2707 (void *)pamh, pam_strerror(pamh, retcode), (void *)ret_respp); 2708 if (*ret_respp == NULL) { 2709 pam_trace(PAM_DEBUG_CONV, 2710 "pam_conv_resp(%p No response requested)", (void *)pamh); 2711 } else if ((pam_debug & (PAM_DEBUG_CONV | PAM_DEBUG_AUTHTOK)) != 0) { 2712 struct pam_response *r = *ret_respp; 2713 2714 for (i = 0; i < num_msg; i++, r++) { 2715 if (r->resp == NULL) { 2716 pam_trace(PAM_DEBUG_CONV, 2717 "pam_conv_resp(%p:" 2718 "[%d] NULL response string)", 2719 (void *)pamh, i); 2720 } else { 2721 if (msg_style == PAM_PROMPT_ECHO_OFF) { 2722 #ifdef DEBUG 2723 pam_trace(PAM_DEBUG_AUTHTOK, 2724 "pam_conv_resp(%p:[%d]=%s, " 2725 "code=%d)", 2726 (void *)pamh, i, r->resp, 2727 r->resp_retcode); 2728 #endif /* DEBUG */ 2729 pam_trace(PAM_DEBUG_CONV, 2730 "pam_conv_resp(%p:[%d] len=%lu, " 2731 "code=%d)", 2732 (void *)pamh, i, 2733 (ulong_t)strlen(r->resp), 2734 r->resp_retcode); 2735 } else { 2736 pam_trace(PAM_DEBUG_CONV, 2737 "pam_conv_resp(%p:[%d]=%s, " 2738 "code=%d)", 2739 (void *)pamh, i, r->resp, 2740 r->resp_retcode); 2741 } 2742 } 2743 } 2744 } 2745 2746 if (msg) 2747 free(msg); 2748 return (retcode); 2749 } 2750 2751 /* 2752 * __pam_display_msg(): 2753 * display message by calling the call back functions 2754 * provided by the application through "pam_conv" structure 2755 */ 2756 2757 int 2758 __pam_display_msg(pam_handle_t *pamh, int msg_style, int num_msg, 2759 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], void *conv_apdp) 2760 { 2761 struct pam_response *ret_respp = NULL; 2762 int ret; 2763 2764 ret = do_conv(pamh, msg_style, num_msg, messages, 2765 conv_apdp, &ret_respp); 2766 2767 if (ret_respp != NULL) 2768 free_resp(num_msg, ret_respp); 2769 2770 return (ret); 2771 } 2772 2773 /* 2774 * __pam_get_authtok() 2775 * retrieves a password of at most PASS_MAX length from the pam 2776 * handle (pam_get_item) or from the input stream (do_conv). 2777 * 2778 * This function allocates memory for the new authtok. 2779 * Applications calling this function are responsible for 2780 * freeing this memory. 2781 * 2782 * If "source" is 2783 * PAM_HANDLE 2784 * and "type" is: 2785 * PAM_AUTHTOK - password is taken from pam handle (PAM_AUTHTOK) 2786 * PAM_OLDAUTHTOK - password is taken from pam handle (PAM_OLDAUTHTOK) 2787 * 2788 * If "source" is 2789 * PAM_PROMPT 2790 * and "type" is: 2791 * 0: Prompt for new passwd, do not even attempt 2792 * to store it in the pam handle. 2793 * PAM_AUTHTOK: Prompt for new passwd, store in pam handle as 2794 * PAM_AUTHTOK item if this value is not already set. 2795 * PAM_OLDAUTHTOK: Prompt for new passwd, store in pam handle as 2796 * PAM_OLDAUTHTOK item if this value is not 2797 * already set. 2798 */ 2799 int 2800 __pam_get_authtok(pam_handle_t *pamh, int source, int type, char *prompt, 2801 char **authtok) 2802 { 2803 int error = PAM_SYSTEM_ERR; 2804 char *new_password = NULL; 2805 struct pam_response *ret_resp = NULL; 2806 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; 2807 2808 if ((*authtok = calloc(PASS_MAX+1, sizeof (char))) == NULL) 2809 return (PAM_BUF_ERR); 2810 2811 if (prompt == NULL) 2812 prompt = dgettext(TEXT_DOMAIN, "password: "); 2813 2814 switch (source) { 2815 case PAM_HANDLE: 2816 2817 /* get password from pam handle item list */ 2818 2819 switch (type) { 2820 case PAM_AUTHTOK: 2821 case PAM_OLDAUTHTOK: 2822 2823 if ((error = pam_get_item(pamh, type, 2824 (void **)&new_password)) != PAM_SUCCESS) 2825 goto err_ret; 2826 2827 if (new_password == NULL || new_password[0] == '\0') { 2828 free(*authtok); 2829 *authtok = NULL; 2830 } else { 2831 (void) strlcpy(*authtok, new_password, 2832 PASS_MAX+1); 2833 } 2834 break; 2835 default: 2836 __pam_log(LOG_AUTH | LOG_ERR, 2837 "__pam_get_authtok() invalid type: %d", type); 2838 error = PAM_SYMBOL_ERR; 2839 goto err_ret; 2840 } 2841 break; 2842 case PAM_PROMPT: 2843 2844 /* 2845 * Prompt for new password and save in pam handle item list 2846 * if the that item is not already set. 2847 */ 2848 2849 (void) strncpy(messages[0], prompt, sizeof (messages[0])); 2850 if ((error = do_conv(pamh, PAM_PROMPT_ECHO_OFF, 1, messages, 2851 NULL, &ret_resp)) != PAM_SUCCESS) 2852 goto err_ret; 2853 2854 if (ret_resp->resp == NULL) { 2855 /* getpass didn't return anything */ 2856 error = PAM_SYSTEM_ERR; 2857 goto err_ret; 2858 } 2859 2860 /* save the new password if this item was NULL */ 2861 if (type) { 2862 if ((error = pam_get_item(pamh, type, 2863 (void **)&new_password)) != PAM_SUCCESS) { 2864 free_resp(1, ret_resp); 2865 goto err_ret; 2866 } 2867 if (new_password == NULL) 2868 (void) pam_set_item(pamh, type, ret_resp->resp); 2869 } 2870 2871 (void) strlcpy(*authtok, ret_resp->resp, PASS_MAX+1); 2872 free_resp(1, ret_resp); 2873 break; 2874 default: 2875 __pam_log(LOG_AUTH | LOG_ERR, 2876 "__pam_get_authtok() invalid source: %d", source); 2877 error = PAM_SYMBOL_ERR; 2878 goto err_ret; 2879 } 2880 2881 return (PAM_SUCCESS); 2882 2883 err_ret: 2884 bzero(*authtok, PASS_MAX+1); 2885 free(*authtok); 2886 *authtok = NULL; 2887 return (error); 2888 } 2889