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