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