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