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