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