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