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