10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52295Sgww  * Common Development and Distribution License (the "License").
62295Sgww  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
223358Sjjj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <syslog.h>
290Sstevel@tonic-gate #include <dlfcn.h>
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <sys/stat.h>
320Sstevel@tonic-gate #include <stdlib.h>
330Sstevel@tonic-gate #include <strings.h>
340Sstevel@tonic-gate #include <malloc.h>
350Sstevel@tonic-gate #include <unistd.h>
360Sstevel@tonic-gate #include <fcntl.h>
370Sstevel@tonic-gate #include <errno.h>
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #include <security/pam_appl.h>
400Sstevel@tonic-gate #include <security/pam_modules.h>
410Sstevel@tonic-gate #include <sys/mman.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include <libintl.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #include "pam_impl.h"
460Sstevel@tonic-gate 
470Sstevel@tonic-gate static char *pam_snames [PAM_NUM_MODULE_TYPES] = {
480Sstevel@tonic-gate 	PAM_ACCOUNT_NAME,
490Sstevel@tonic-gate 	PAM_AUTH_NAME,
500Sstevel@tonic-gate 	PAM_PASSWORD_NAME,
510Sstevel@tonic-gate 	PAM_SESSION_NAME
520Sstevel@tonic-gate };
530Sstevel@tonic-gate 
540Sstevel@tonic-gate static char *pam_inames [PAM_MAX_ITEMS] = {
550Sstevel@tonic-gate /* NONE */		NULL,
560Sstevel@tonic-gate /* PAM_SERVICE */	"service",
570Sstevel@tonic-gate /* PAM_USER */		"user",
580Sstevel@tonic-gate /* PAM_TTY */		"tty",
590Sstevel@tonic-gate /* PAM_RHOST */ 	"rhost",
600Sstevel@tonic-gate /* PAM_CONV */		"conv",
610Sstevel@tonic-gate /* PAM_AUTHTOK */	"authtok",
620Sstevel@tonic-gate /* PAM_OLDAUTHTOK */	"oldauthtok",
630Sstevel@tonic-gate /* PAM_RUSER */ 	"ruser",
640Sstevel@tonic-gate /* PAM_USER_PROMPT */	"user_prompt",
650Sstevel@tonic-gate /* PAM_REPOSITORY */	"repository",
660Sstevel@tonic-gate /* PAM_RESOURCE */	"resource",
672815Sgww /* PAM_AUSER */ 	"auser",
680Sstevel@tonic-gate /* Undefined Items */
690Sstevel@tonic-gate };
700Sstevel@tonic-gate 
710Sstevel@tonic-gate /*
720Sstevel@tonic-gate  * This extra definition is needed in order to build this library
730Sstevel@tonic-gate  * on pre-64-bit-aware systems.
740Sstevel@tonic-gate  */
750Sstevel@tonic-gate #if !defined(_LFS64_LARGEFILE)
760Sstevel@tonic-gate #define	stat64	stat
770Sstevel@tonic-gate #endif	/* !defined(_LFS64_LARGEFILE) */
780Sstevel@tonic-gate 
790Sstevel@tonic-gate /* functions to dynamically load modules */
800Sstevel@tonic-gate static int	load_modules(pam_handle_t *, int, char *, pamtab_t *);
810Sstevel@tonic-gate static void 	*open_module(pam_handle_t *, char *);
820Sstevel@tonic-gate static int	load_function(void *, char *, int (**func)());
830Sstevel@tonic-gate 
840Sstevel@tonic-gate /* functions to read and store the pam.conf configuration file */
850Sstevel@tonic-gate static int	open_pam_conf(struct pam_fh **, pam_handle_t *, char *);
860Sstevel@tonic-gate static void	close_pam_conf(struct pam_fh *);
870Sstevel@tonic-gate static int	read_pam_conf(pam_handle_t *, char *);
880Sstevel@tonic-gate static int 	get_pam_conf_entry(struct pam_fh *, pam_handle_t *,
890Sstevel@tonic-gate     pamtab_t **);
900Sstevel@tonic-gate static char	*read_next_token(char **);
912295Sgww static char	*nextline(struct pam_fh *, pam_handle_t *, int *);
920Sstevel@tonic-gate static int	verify_pam_conf(pamtab_t *, char *);
930Sstevel@tonic-gate 
940Sstevel@tonic-gate /* functions to clean up and free memory */
950Sstevel@tonic-gate static void	clean_up(pam_handle_t *);
960Sstevel@tonic-gate static void	free_pamconf(pamtab_t *);
970Sstevel@tonic-gate static void	free_pam_conf_info(pam_handle_t *);
980Sstevel@tonic-gate static void	free_env(env_list *);
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate /* convenience functions for I18N/L10N communication */
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate static void	free_resp(int, struct pam_response *);
1030Sstevel@tonic-gate static int	do_conv(pam_handle_t *, int, int,
1040Sstevel@tonic-gate     char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], void *,
1050Sstevel@tonic-gate     struct pam_response **);
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate static int	log_priority;	/* pam_trace syslog priority & facility */
1080Sstevel@tonic-gate static int	pam_debug = 0;
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate static char *
1110Sstevel@tonic-gate pam_trace_iname(int item_type, char *iname_buf)
1120Sstevel@tonic-gate {
1130Sstevel@tonic-gate 	char *name;
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	/*
1160Sstevel@tonic-gate 	 * XXX -- Contracted Consolidation Private
1170Sstevel@tonic-gate 	 *	  to be eliminated when dtlogin contract is terminated
1180Sstevel@tonic-gate 	 * Version number requested by PAM's client
1190Sstevel@tonic-gate 	 */
1200Sstevel@tonic-gate 	if (item_type == PAM_MSG_VERSION)
1210Sstevel@tonic-gate 		return ("msg_version");
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	if (item_type <= 0 ||
1240Sstevel@tonic-gate 	    item_type >= PAM_MAX_ITEMS ||
1250Sstevel@tonic-gate 	    (name = pam_inames[item_type]) == NULL) {
1260Sstevel@tonic-gate 		(void) sprintf(iname_buf, "%d", item_type);
1270Sstevel@tonic-gate 		return (iname_buf);
1280Sstevel@tonic-gate 	}
1290Sstevel@tonic-gate 	return (name);
1300Sstevel@tonic-gate }
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate static char *
1330Sstevel@tonic-gate pam_trace_fname(int flag)
1340Sstevel@tonic-gate {
1350Sstevel@tonic-gate 	if (flag & PAM_BINDING)
1360Sstevel@tonic-gate 		return (PAM_BINDING_NAME);
1370Sstevel@tonic-gate 	if (flag & PAM_INCLUDE)
1380Sstevel@tonic-gate 		return (PAM_INCLUDE_NAME);
1390Sstevel@tonic-gate 	if (flag & PAM_OPTIONAL)
1400Sstevel@tonic-gate 		return (PAM_OPTIONAL_NAME);
1410Sstevel@tonic-gate 	if (flag & PAM_REQUIRED)
1420Sstevel@tonic-gate 		return (PAM_REQUIRED_NAME);
1430Sstevel@tonic-gate 	if (flag & PAM_REQUISITE)
1440Sstevel@tonic-gate 		return (PAM_REQUISITE_NAME);
1450Sstevel@tonic-gate 	if (flag & PAM_SUFFICIENT)
1460Sstevel@tonic-gate 		return (PAM_SUFFICIENT_NAME);
1470Sstevel@tonic-gate 	return ("bad flag name");
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate static char *
1510Sstevel@tonic-gate pam_trace_cname(pam_handle_t *pamh)
1520Sstevel@tonic-gate {
1530Sstevel@tonic-gate 	if (pamh->pam_conf_name[pamh->include_depth] == NULL)
1540Sstevel@tonic-gate 		return ("NULL");
1550Sstevel@tonic-gate 	return (pamh->pam_conf_name[pamh->include_depth]);
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate #include <deflt.h>
1590Sstevel@tonic-gate #include <stdarg.h>
1600Sstevel@tonic-gate /*
1610Sstevel@tonic-gate  * pam_settrace - setup configuration for pam tracing
1620Sstevel@tonic-gate  *
1630Sstevel@tonic-gate  * turn on PAM debug if "magic" file exists
1640Sstevel@tonic-gate  * if exists (original), pam_debug = PAM_DEBUG_DEFAULT,
1650Sstevel@tonic-gate  * log_priority = LOG_DEBUG(7) and log_facility = LOG_AUTH(4).
1660Sstevel@tonic-gate  *
1670Sstevel@tonic-gate  * if has contents, keywork=value pairs:
1680Sstevel@tonic-gate  *
1690Sstevel@tonic-gate  *	"log_priority=" 0-7, the pam_trace syslog priority to use
1700Sstevel@tonic-gate  *		(see sys/syslog.h)
1710Sstevel@tonic-gate  *	"log_facility=" 0-23, the pam_trace syslog facility to use
1720Sstevel@tonic-gate  *		(see sys/syslog.h)
1730Sstevel@tonic-gate  *	"debug_flags=" PAM_DEBUG_DEFAULT (0x0001), log traditional
1740Sstevel@tonic-gate  *			(original) debugging.
1750Sstevel@tonic-gate  *		Plus the logical or of:
1760Sstevel@tonic-gate  *		    PAM_DEBUG_ITEM (0x0002), log item values and
1770Sstevel@tonic-gate  *			pam_get_item.
1780Sstevel@tonic-gate  *		    PAM_DEBUG_MODULE (0x0004), log module return status.
1790Sstevel@tonic-gate  *		    PAM_DEBUG_CONF (0x0008), log pam.conf parsing.
1800Sstevel@tonic-gate  *		    PAM_DEBUG_DATA (0x0010), get/set_data.
1810Sstevel@tonic-gate  *		    PAM_DEBUG_CONV (0x0020), conversation/response.
1820Sstevel@tonic-gate  *
1830Sstevel@tonic-gate  *		    If compiled with DEBUG:
1840Sstevel@tonic-gate  *		    PAM_DEBUG_AUTHTOK (0x8000), display AUTHTOK value if
1850Sstevel@tonic-gate  *				PAM_DEBUG_ITEM is set and results from
1860Sstevel@tonic-gate  *				PAM_PROMPT_ECHO_OFF responses.
1870Sstevel@tonic-gate  *		    USE CAREFULLY, THIS EXPOSES THE USER'S PASSWORDS.
1880Sstevel@tonic-gate  *
1890Sstevel@tonic-gate  *		or set to 0 and off even if PAM_DEBUG file exists.
1900Sstevel@tonic-gate  *
1910Sstevel@tonic-gate  * Output has the general form:
1920Sstevel@tonic-gate  * <whatever was set syslog> PAM[<pid>]: <interface>(<handle> and other info)
1930Sstevel@tonic-gate  * <whatever was set syslog> PAM[<pid>]: details requested for <interface> call
1940Sstevel@tonic-gate  *	Where:	<pid> is the process ID of the calling process.
1950Sstevel@tonic-gate  *		<handle> is the Hex value of the pam_handle associated with the
1960Sstevel@tonic-gate  *			call.
1970Sstevel@tonic-gate  */
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate static void
2000Sstevel@tonic-gate pam_settrace()
2010Sstevel@tonic-gate {
2020Sstevel@tonic-gate 	if (defopen(PAM_DEBUG) == 0) {
2030Sstevel@tonic-gate 		char	*arg;
2040Sstevel@tonic-gate 		int	code;
2050Sstevel@tonic-gate 		int	facility = LOG_AUTH;
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 		pam_debug = PAM_DEBUG_DEFAULT;
2080Sstevel@tonic-gate 		log_priority = LOG_DEBUG;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 		(void) defcntl(DC_SETFLAGS, DC_CASE);
2110Sstevel@tonic-gate 		if ((arg = defread(LOG_PRIORITY)) != NULL) {
2120Sstevel@tonic-gate 			code = (int)strtol(arg, NULL, 10);
2130Sstevel@tonic-gate 			if ((code & ~LOG_PRIMASK) == 0) {
2140Sstevel@tonic-gate 				log_priority = code;
2150Sstevel@tonic-gate 			}
2160Sstevel@tonic-gate 		}
2170Sstevel@tonic-gate 		if ((arg = defread(LOG_FACILITY)) != NULL) {
2180Sstevel@tonic-gate 			code = (int)strtol(arg, NULL, 10);
2190Sstevel@tonic-gate 			if (code < LOG_NFACILITIES) {
2200Sstevel@tonic-gate 				facility = code << 3;
2210Sstevel@tonic-gate 			}
2220Sstevel@tonic-gate 		}
2230Sstevel@tonic-gate 		if ((arg = defread(DEBUG_FLAGS)) != NULL) {
2240Sstevel@tonic-gate 			pam_debug = (int)strtol(arg, NULL, 0);
2250Sstevel@tonic-gate 		}
2260Sstevel@tonic-gate 		(void) defopen(NULL);	/* close */
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 		log_priority |= facility;
2290Sstevel@tonic-gate 	}
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate /*
2330Sstevel@tonic-gate  * pam_trace - logs tracing messages
2340Sstevel@tonic-gate  *
2350Sstevel@tonic-gate  *	flag = debug_flags from /etc/pam_debug
2360Sstevel@tonic-gate  *	format and args = message to print (PAM[<pid>]: is prepended).
2370Sstevel@tonic-gate  *
2380Sstevel@tonic-gate  *	global log_priority = pam_trace syslog (log_priority | log_facility)
2390Sstevel@tonic-gate  *		from /etc/pam_debug
2400Sstevel@tonic-gate  */
2410Sstevel@tonic-gate /*PRINTFLIKE2*/
2420Sstevel@tonic-gate static void
2430Sstevel@tonic-gate pam_trace(int flag, char *format, ...)
2440Sstevel@tonic-gate {
2450Sstevel@tonic-gate 	va_list args;
2460Sstevel@tonic-gate 	char message[1024];
2470Sstevel@tonic-gate 	int savemask;
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	if ((pam_debug & flag) == 0)
2500Sstevel@tonic-gate 		return;
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	savemask = setlogmask(LOG_MASK(log_priority & LOG_PRIMASK));
2530Sstevel@tonic-gate 	(void) snprintf(message, sizeof (message), "PAM[%ld]: %s",
2540Sstevel@tonic-gate 	    (long)getpid(), format);
2550Sstevel@tonic-gate 	va_start(args, format);
2560Sstevel@tonic-gate 	(void) vsyslog(log_priority, message, args);
2570Sstevel@tonic-gate 	va_end(args);
2580Sstevel@tonic-gate 	(void) setlogmask(savemask);
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate /*
2620Sstevel@tonic-gate  * __pam_log - logs PAM syslog messages
2630Sstevel@tonic-gate  *
2640Sstevel@tonic-gate  *	priority = message priority
2650Sstevel@tonic-gate  *	format and args = message to log
2660Sstevel@tonic-gate  */
2670Sstevel@tonic-gate /*PRINTFLIKE2*/
2680Sstevel@tonic-gate void
2690Sstevel@tonic-gate __pam_log(int priority, const char *format, ...)
2700Sstevel@tonic-gate {
2710Sstevel@tonic-gate 	va_list args;
2720Sstevel@tonic-gate 	int savemask = setlogmask(LOG_MASK(priority & LOG_PRIMASK));
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	va_start(args, format);
2750Sstevel@tonic-gate 	(void) vsyslog(priority, format, args);
2760Sstevel@tonic-gate 	va_end(args);
2770Sstevel@tonic-gate 	(void) setlogmask(savemask);
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate /*
2820Sstevel@tonic-gate  *			pam_XXXXX routines
2830Sstevel@tonic-gate  *
2840Sstevel@tonic-gate  *	These are the entry points to the authentication switch
2850Sstevel@tonic-gate  */
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate /*
2880Sstevel@tonic-gate  * pam_start		- initiate an authentication transaction and
2890Sstevel@tonic-gate  *			  set parameter values to be used during the
2900Sstevel@tonic-gate  *			  transaction
2910Sstevel@tonic-gate  */
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate int
2940Sstevel@tonic-gate pam_start(const char *service, const char *user,
2950Sstevel@tonic-gate     const struct pam_conv *pam_conv, pam_handle_t **pamh)
2960Sstevel@tonic-gate {
2970Sstevel@tonic-gate 	int	err;
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	*pamh = (struct pam_handle *)calloc(1, sizeof (struct pam_handle));
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	pam_settrace();
3020Sstevel@tonic-gate 	pam_trace(PAM_DEBUG_DEFAULT,
3030Sstevel@tonic-gate 	    "pam_start(%s,%s,%p:%p) - debug = %x",
3040Sstevel@tonic-gate 	    service ? service : "NULL", user ? user : "NULL", (void *)pam_conv,
3050Sstevel@tonic-gate 	    (void *)*pamh, pam_debug);
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	if (*pamh == NULL)
3080Sstevel@tonic-gate 		return (PAM_BUF_ERR);
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	(*pamh)->pam_inmodule = RO_OK;		/* OK to set RO items */
3110Sstevel@tonic-gate 	if ((err = pam_set_item(*pamh, PAM_SERVICE, (void *)service))
3120Sstevel@tonic-gate 	    != PAM_SUCCESS) {
3130Sstevel@tonic-gate 		clean_up(*pamh);
3140Sstevel@tonic-gate 		*pamh = NULL;
3150Sstevel@tonic-gate 		return (err);
3160Sstevel@tonic-gate 	}
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	if ((err = pam_set_item(*pamh, PAM_USER, (void *)user))
3190Sstevel@tonic-gate 	    != PAM_SUCCESS) {
3200Sstevel@tonic-gate 		clean_up(*pamh);
3210Sstevel@tonic-gate 		*pamh = NULL;
3220Sstevel@tonic-gate 		return (err);
3230Sstevel@tonic-gate 	}
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	if ((err = pam_set_item(*pamh, PAM_CONV, (void *)pam_conv))
3260Sstevel@tonic-gate 	    != PAM_SUCCESS) {
3270Sstevel@tonic-gate 		clean_up(*pamh);
3280Sstevel@tonic-gate 		*pamh = NULL;
3290Sstevel@tonic-gate 		return (err);
3300Sstevel@tonic-gate 	}
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	(*pamh)->pam_inmodule = RW_OK;
3330Sstevel@tonic-gate 	return (PAM_SUCCESS);
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate /*
3370Sstevel@tonic-gate  * pam_end - terminate an authentication transaction
3380Sstevel@tonic-gate  */
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate int
3410Sstevel@tonic-gate pam_end(pam_handle_t *pamh, int pam_status)
3420Sstevel@tonic-gate {
3430Sstevel@tonic-gate 	struct pam_module_data *psd, *p;
3440Sstevel@tonic-gate 	fd_list *expired;
3450Sstevel@tonic-gate 	fd_list *traverse;
3460Sstevel@tonic-gate 	env_list *env_expired;
3470Sstevel@tonic-gate 	env_list *env_traverse;
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	pam_trace(PAM_DEBUG_DEFAULT,
3500Sstevel@tonic-gate 	    "pam_end(%p): status = %s", (void *)pamh,
3510Sstevel@tonic-gate 	    pam_strerror(pamh, pam_status));
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	if (pamh == NULL)
3540Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	/* call the cleanup routines for module specific data */
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	psd = pamh->ssd;
3590Sstevel@tonic-gate 	while (psd) {
3600Sstevel@tonic-gate 		if (psd->cleanup) {
3610Sstevel@tonic-gate 			psd->cleanup(pamh, psd->data, pam_status);
3620Sstevel@tonic-gate 		}
3630Sstevel@tonic-gate 		p = psd;
3640Sstevel@tonic-gate 		psd = p->next;
3650Sstevel@tonic-gate 		free(p->module_data_name);
3660Sstevel@tonic-gate 		free(p);
3670Sstevel@tonic-gate 	}
3680Sstevel@tonic-gate 	pamh->ssd = NULL;
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	/* dlclose all module fds */
3710Sstevel@tonic-gate 	traverse = pamh->fd;
3720Sstevel@tonic-gate 	while (traverse) {
3730Sstevel@tonic-gate 		expired = traverse;
3740Sstevel@tonic-gate 		traverse = traverse->next;
3750Sstevel@tonic-gate 		(void) dlclose(expired->mh);
3760Sstevel@tonic-gate 		free(expired);
3770Sstevel@tonic-gate 	}
3780Sstevel@tonic-gate 	pamh->fd = 0;
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	/* remove all environment variables */
3810Sstevel@tonic-gate 	env_traverse = pamh->pam_env;
3820Sstevel@tonic-gate 	while (env_traverse) {
3830Sstevel@tonic-gate 		env_expired = env_traverse;
3840Sstevel@tonic-gate 		env_traverse = env_traverse->next;
3850Sstevel@tonic-gate 		free_env(env_expired);
3860Sstevel@tonic-gate 	}
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	clean_up(pamh);
3890Sstevel@tonic-gate 	return (PAM_SUCCESS);
3900Sstevel@tonic-gate }
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate /*
3930Sstevel@tonic-gate  * pam_set_item		- set the value of a parameter that can be
3940Sstevel@tonic-gate  *			  retrieved via a call to pam_get_item()
3950Sstevel@tonic-gate  */
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate int
3980Sstevel@tonic-gate pam_set_item(pam_handle_t *pamh, int item_type, const void *item)
3990Sstevel@tonic-gate {
4000Sstevel@tonic-gate 	struct pam_item *pip;
4010Sstevel@tonic-gate 	int	size;
4020Sstevel@tonic-gate 	char	iname_buf[PAM_MAX_MSG_SIZE];
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	if (((pam_debug & PAM_DEBUG_ITEM) == 0) || (pamh == NULL)) {
4050Sstevel@tonic-gate 		pam_trace(PAM_DEBUG_DEFAULT,
4060Sstevel@tonic-gate 		    "pam_set_item(%p:%s)", (void *)pamh,
4070Sstevel@tonic-gate 		    pam_trace_iname(item_type, iname_buf));
4080Sstevel@tonic-gate 	}
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	if (pamh == NULL)
4110Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	/* check read only items */
4140Sstevel@tonic-gate 	if ((item_type == PAM_SERVICE) && (pamh->pam_inmodule != RO_OK))
4150Sstevel@tonic-gate 		return (PAM_PERM_DENIED);
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	/*
4180Sstevel@tonic-gate 	 * XXX -- Contracted Consolidation Private
4190Sstevel@tonic-gate 	 *	  to be eliminated when dtlogin contract is terminated
4200Sstevel@tonic-gate 	 * Check if tag is Sun proprietary
4210Sstevel@tonic-gate 	 */
4220Sstevel@tonic-gate 	if (item_type == PAM_MSG_VERSION) {
4230Sstevel@tonic-gate 		if (pamh->pam_client_message_version_number)
4240Sstevel@tonic-gate 			free(pamh->pam_client_message_version_number);
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 		if (item == NULL)
4270Sstevel@tonic-gate 			pamh->pam_client_message_version_number = NULL;
4280Sstevel@tonic-gate 		else
4290Sstevel@tonic-gate 			if ((pamh->pam_client_message_version_number =
4300Sstevel@tonic-gate 			    strdup((char *)item)) == NULL)
4310Sstevel@tonic-gate 				return (PAM_BUF_ERR);
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 		pam_trace(PAM_DEBUG_ITEM,
4340Sstevel@tonic-gate 		    "pam_set_item(%p:%s)=%s", (void *)pamh,
4350Sstevel@tonic-gate 		    pam_trace_iname(item_type, iname_buf),
4360Sstevel@tonic-gate 		    item ? (char *)item : "NULL");
4370Sstevel@tonic-gate 		return (PAM_SUCCESS);
4380Sstevel@tonic-gate 	}
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	/*
4410Sstevel@tonic-gate 	 * Check that item_type is within valid range
4420Sstevel@tonic-gate 	 */
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	if (item_type <= 0 || item_type >= PAM_MAX_ITEMS)
4450Sstevel@tonic-gate 		return (PAM_SYMBOL_ERR);
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	pip = &(pamh->ps_item[item_type]);
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	switch (item_type) {
4500Sstevel@tonic-gate 	case PAM_AUTHTOK:
4510Sstevel@tonic-gate 	case PAM_OLDAUTHTOK:
4520Sstevel@tonic-gate 		if (pip->pi_addr != NULL)
4530Sstevel@tonic-gate 			(void) memset(pip->pi_addr, 0, pip->pi_size);
4540Sstevel@tonic-gate 		/*FALLTHROUGH*/
4550Sstevel@tonic-gate 	case PAM_SERVICE:
4560Sstevel@tonic-gate 	case PAM_USER:
4570Sstevel@tonic-gate 	case PAM_TTY:
4580Sstevel@tonic-gate 	case PAM_RHOST:
4590Sstevel@tonic-gate 	case PAM_RUSER:
4600Sstevel@tonic-gate 	case PAM_USER_PROMPT:
4610Sstevel@tonic-gate 	case PAM_RESOURCE:
4622815Sgww 	case PAM_AUSER:
4630Sstevel@tonic-gate 		if (pip->pi_addr != NULL) {
4640Sstevel@tonic-gate 			free(pip->pi_addr);
4650Sstevel@tonic-gate 		}
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 		if (item == NULL) {
4680Sstevel@tonic-gate 			pip->pi_addr = NULL;
4690Sstevel@tonic-gate 			pip->pi_size = 0;
4700Sstevel@tonic-gate 		} else {
4710Sstevel@tonic-gate 			pip->pi_addr = strdup((char *)item);
4720Sstevel@tonic-gate 			if (pip->pi_addr == NULL) {
4730Sstevel@tonic-gate 				pip->pi_size = 0;
4740Sstevel@tonic-gate 				return (PAM_BUF_ERR);
4750Sstevel@tonic-gate 			}
4760Sstevel@tonic-gate 			pip->pi_size = strlen(pip->pi_addr);
4770Sstevel@tonic-gate 		}
4780Sstevel@tonic-gate 		break;
4790Sstevel@tonic-gate 	case PAM_CONV:
4800Sstevel@tonic-gate 		if (pip->pi_addr != NULL)
4810Sstevel@tonic-gate 			free(pip->pi_addr);
4820Sstevel@tonic-gate 		size = sizeof (struct pam_conv);
4830Sstevel@tonic-gate 		if ((pip->pi_addr = (void *)calloc(1, size)) == NULL)
4840Sstevel@tonic-gate 			return (PAM_BUF_ERR);
4850Sstevel@tonic-gate 		if (item != NULL)
4860Sstevel@tonic-gate 			(void) memcpy(pip->pi_addr, item, (unsigned int) size);
4870Sstevel@tonic-gate 		else
4880Sstevel@tonic-gate 			(void) memset(pip->pi_addr, 0, size);
4890Sstevel@tonic-gate 		pip->pi_size = size;
4900Sstevel@tonic-gate 		break;
4910Sstevel@tonic-gate 	case PAM_REPOSITORY:
4920Sstevel@tonic-gate 		if (pip->pi_addr != NULL) {
4930Sstevel@tonic-gate 			pam_repository_t *auth_rep;
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 			auth_rep = (pam_repository_t *)pip->pi_addr;
4960Sstevel@tonic-gate 			if (auth_rep->type != NULL)
4970Sstevel@tonic-gate 				free(auth_rep->type);
4980Sstevel@tonic-gate 			if (auth_rep->scope != NULL)
4990Sstevel@tonic-gate 				free(auth_rep->scope);
5000Sstevel@tonic-gate 			free(auth_rep);
5010Sstevel@tonic-gate 		}
5020Sstevel@tonic-gate 		if (item != NULL) {
5030Sstevel@tonic-gate 			pam_repository_t *s, *d;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 			size = sizeof (struct pam_repository);
5060Sstevel@tonic-gate 			pip->pi_addr = (void *)calloc(1, size);
5070Sstevel@tonic-gate 			if (pip->pi_addr == NULL)
5080Sstevel@tonic-gate 				return (PAM_BUF_ERR);
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 			s = (struct pam_repository *)item;
5110Sstevel@tonic-gate 			d = (struct pam_repository *)pip->pi_addr;
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 			d->type = strdup(s->type);
5140Sstevel@tonic-gate 			if (d->type == NULL)
5150Sstevel@tonic-gate 				return (PAM_BUF_ERR);
5160Sstevel@tonic-gate 			d->scope = malloc(s->scope_len);
5170Sstevel@tonic-gate 			if (d->scope == NULL)
5180Sstevel@tonic-gate 				return (PAM_BUF_ERR);
5190Sstevel@tonic-gate 			(void) memcpy(d->scope, s->scope, s->scope_len);
5200Sstevel@tonic-gate 			d->scope_len = s->scope_len;
5210Sstevel@tonic-gate 		}
5220Sstevel@tonic-gate 		pip->pi_size = size;
5230Sstevel@tonic-gate 		break;
5240Sstevel@tonic-gate 	default:
5250Sstevel@tonic-gate 		return (PAM_SYMBOL_ERR);
5260Sstevel@tonic-gate 	}
5270Sstevel@tonic-gate 	switch (item_type) {
5280Sstevel@tonic-gate 	case PAM_CONV:
5290Sstevel@tonic-gate 		pam_trace(PAM_DEBUG_ITEM, "pam_set_item(%p:%s)=%p",
5300Sstevel@tonic-gate 		    (void *)pamh,
5310Sstevel@tonic-gate 		    pam_trace_iname(item_type, iname_buf),
5320Sstevel@tonic-gate 		    item ? (void *)((struct pam_conv *)item)->conv :
5330Sstevel@tonic-gate 		    (void *)0);
5340Sstevel@tonic-gate 		break;
5350Sstevel@tonic-gate 	case PAM_REPOSITORY:
5360Sstevel@tonic-gate 		pam_trace(PAM_DEBUG_ITEM, "pam_set_item(%p:%s)=%s",
5370Sstevel@tonic-gate 		    (void *)pamh,
5380Sstevel@tonic-gate 		    pam_trace_iname(item_type, iname_buf),
5390Sstevel@tonic-gate 		    item ? (((struct pam_repository *)item)->type ?
5400Sstevel@tonic-gate 		    ((struct pam_repository *)item)->type : "NULL") :
5410Sstevel@tonic-gate 		    "NULL");
5420Sstevel@tonic-gate 		break;
5430Sstevel@tonic-gate 	case PAM_AUTHTOK:
5440Sstevel@tonic-gate 	case PAM_OLDAUTHTOK:
5450Sstevel@tonic-gate #ifdef	DEBUG
5460Sstevel@tonic-gate 		if (pam_debug & PAM_DEBUG_AUTHTOK)
5470Sstevel@tonic-gate 			pam_trace(PAM_DEBUG_ITEM,
5480Sstevel@tonic-gate 			    "pam_set_item(%p:%s)=%s", (void *)pamh,
5490Sstevel@tonic-gate 			    pam_trace_iname(item_type, iname_buf),
5500Sstevel@tonic-gate 			    item ? (char *)item : "NULL");
5510Sstevel@tonic-gate 		else
5520Sstevel@tonic-gate #endif	/* DEBUG */
5530Sstevel@tonic-gate 			pam_trace(PAM_DEBUG_ITEM,
5540Sstevel@tonic-gate 			    "pam_set_item(%p:%s)=%s", (void *)pamh,
5550Sstevel@tonic-gate 			    pam_trace_iname(item_type, iname_buf),
5560Sstevel@tonic-gate 			    item ? "********" : "NULL");
5570Sstevel@tonic-gate 		break;
5580Sstevel@tonic-gate 	default:
5590Sstevel@tonic-gate 		pam_trace(PAM_DEBUG_ITEM, "pam_set_item(%p:%s)=%s",
5600Sstevel@tonic-gate 		    (void *)pamh,
5610Sstevel@tonic-gate 		    pam_trace_iname(item_type, iname_buf),
5620Sstevel@tonic-gate 		    item ? (char *)item : "NULL");
5630Sstevel@tonic-gate 	}
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	return (PAM_SUCCESS);
5660Sstevel@tonic-gate }
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate /*
5690Sstevel@tonic-gate  * pam_get_item		- read the value of a parameter specified in
5700Sstevel@tonic-gate  *			  the call to pam_set_item()
5710Sstevel@tonic-gate  */
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate int
5740Sstevel@tonic-gate pam_get_item(const pam_handle_t *pamh, int item_type, void **item)
5750Sstevel@tonic-gate {
5760Sstevel@tonic-gate 	struct pam_item *pip;
5770Sstevel@tonic-gate 	char	iname_buf[PAM_MAX_MSG_SIZE];
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	if (((pam_debug & PAM_DEBUG_ITEM) == 0) || (pamh == NULL)) {
5800Sstevel@tonic-gate 		pam_trace(PAM_DEBUG_ITEM, "pam_get_item(%p:%s)",
5810Sstevel@tonic-gate 		    (void *)pamh, pam_trace_iname(item_type, iname_buf));
5820Sstevel@tonic-gate 	}
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	if (pamh == NULL)
5850Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	/*
5880Sstevel@tonic-gate 	 * XXX -- Contracted Consolidation Private
5890Sstevel@tonic-gate 	 *	  to be eliminated when dtlogin contract is terminated
5900Sstevel@tonic-gate 	 * Check if tag is Sun proprietary
5910Sstevel@tonic-gate 	 */
5920Sstevel@tonic-gate 	if (item_type == PAM_MSG_VERSION) {
5930Sstevel@tonic-gate 		*item = pamh->pam_client_message_version_number;
5940Sstevel@tonic-gate 		pam_trace(PAM_DEBUG_ITEM, "pam_get_item(%p:%s)=%s",
5950Sstevel@tonic-gate 		    (void *)pamh, pam_trace_iname(item_type, iname_buf),
5960Sstevel@tonic-gate 		    *item ? (char *)*item : "NULL");
5970Sstevel@tonic-gate 		return (PAM_SUCCESS);
5980Sstevel@tonic-gate 	}
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	if (item_type <= 0 || item_type >= PAM_MAX_ITEMS)
6010Sstevel@tonic-gate 		return (PAM_SYMBOL_ERR);
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	if ((pamh->pam_inmodule != WO_OK) &&
6040Sstevel@tonic-gate 	    ((item_type == PAM_AUTHTOK || item_type == PAM_OLDAUTHTOK))) {
6050Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_NOTICE, "pam_get_item(%s) called from "
6060Sstevel@tonic-gate 		    "a non module context",
6070Sstevel@tonic-gate 		    pam_trace_iname(item_type, iname_buf));
6080Sstevel@tonic-gate 		return (PAM_PERM_DENIED);
6090Sstevel@tonic-gate 	}
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	pip = (struct pam_item *)&(pamh->ps_item[item_type]);
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	*item = pip->pi_addr;
6140Sstevel@tonic-gate 	switch (item_type) {
6150Sstevel@tonic-gate 	case PAM_CONV:
6160Sstevel@tonic-gate 		pam_trace(PAM_DEBUG_ITEM, "pam_get_item(%p:%s)=%p",
6170Sstevel@tonic-gate 		    (void *)pamh,
6180Sstevel@tonic-gate 		    pam_trace_iname(item_type, iname_buf),
6190Sstevel@tonic-gate 		    (void *)((struct pam_conv *)*item)->conv);
6200Sstevel@tonic-gate 		break;
6210Sstevel@tonic-gate 	case PAM_REPOSITORY:
6220Sstevel@tonic-gate 		pam_trace(PAM_DEBUG_ITEM, "pam_get_item(%p:%s)=%s",
6230Sstevel@tonic-gate 		    (void *)pamh,
6240Sstevel@tonic-gate 		    pam_trace_iname(item_type, iname_buf),
6250Sstevel@tonic-gate 		    *item ? (((struct pam_repository *)*item)->type ?
6260Sstevel@tonic-gate 		    ((struct pam_repository *)*item)->type : "NULL") :
6270Sstevel@tonic-gate 		    "NULL");
6280Sstevel@tonic-gate 		break;
6290Sstevel@tonic-gate 	case PAM_AUTHTOK:
6300Sstevel@tonic-gate 	case PAM_OLDAUTHTOK:
6310Sstevel@tonic-gate #ifdef	DEBUG
6320Sstevel@tonic-gate 		if (pam_debug & PAM_DEBUG_AUTHTOK)
6330Sstevel@tonic-gate 			pam_trace(PAM_DEBUG_ITEM,
6340Sstevel@tonic-gate 			    "pam_get_item(%p:%s)=%s", (void *)pamh,
6350Sstevel@tonic-gate 			    pam_trace_iname(item_type, iname_buf),
6360Sstevel@tonic-gate 			    *item ? *(char **)item : "NULL");
6370Sstevel@tonic-gate 		else
6380Sstevel@tonic-gate #endif	/* DEBUG */
6390Sstevel@tonic-gate 			pam_trace(PAM_DEBUG_ITEM,
6400Sstevel@tonic-gate 			    "pam_get_item(%p:%s)=%s", (void *)pamh,
6410Sstevel@tonic-gate 			    pam_trace_iname(item_type, iname_buf),
6420Sstevel@tonic-gate 			    *item ? "********" : "NULL");
6430Sstevel@tonic-gate 		break;
6440Sstevel@tonic-gate 	default:
6450Sstevel@tonic-gate 		pam_trace(PAM_DEBUG_ITEM, "pam_get_item(%p:%s)=%s",
6460Sstevel@tonic-gate 		    (void *)pamh,
6470Sstevel@tonic-gate 		    pam_trace_iname(item_type, iname_buf),
6480Sstevel@tonic-gate 		    *item ? *(char **)item : "NULL");
6490Sstevel@tonic-gate 	}
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	return (PAM_SUCCESS);
6520Sstevel@tonic-gate }
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate /*
6550Sstevel@tonic-gate  * parse_user_name         - process the user response: ignore
6560Sstevel@tonic-gate  *                           '\t' or ' ' before or after a user name.
6570Sstevel@tonic-gate  *                           user_input is a null terminated string.
6580Sstevel@tonic-gate  *                           *ret_username will be the user name.
6590Sstevel@tonic-gate  */
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate static int
6620Sstevel@tonic-gate parse_user_name(char *user_input, char **ret_username)
6630Sstevel@tonic-gate {
6640Sstevel@tonic-gate 	register char *ptr;
6650Sstevel@tonic-gate 	register int index = 0;
6660Sstevel@tonic-gate 	char username[PAM_MAX_RESP_SIZE];
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	/* Set the default value for *ret_username */
6690Sstevel@tonic-gate 	*ret_username = NULL;
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	/*
6720Sstevel@tonic-gate 	 * Set the initial value for username - this is a buffer holds
6730Sstevel@tonic-gate 	 * the user name.
6740Sstevel@tonic-gate 	 */
6750Sstevel@tonic-gate 	bzero((void *)username, PAM_MAX_RESP_SIZE);
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	/*
6780Sstevel@tonic-gate 	 * The user_input is guaranteed to be terminated by a null character.
6790Sstevel@tonic-gate 	 */
6800Sstevel@tonic-gate 	ptr = user_input;
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	/* Skip all the leading whitespaces if there are any. */
6830Sstevel@tonic-gate 	while ((*ptr == ' ') || (*ptr == '\t'))
6840Sstevel@tonic-gate 		ptr++;
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	if (*ptr == '\0') {
6870Sstevel@tonic-gate 		/*
6880Sstevel@tonic-gate 		 * We should never get here since the user_input we got
6890Sstevel@tonic-gate 		 * in pam_get_user() is not all whitespaces nor just "\0".
6900Sstevel@tonic-gate 		 */
6910Sstevel@tonic-gate 		return (PAM_BUF_ERR);
6920Sstevel@tonic-gate 	}
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	/*
6950Sstevel@tonic-gate 	 * username will be the first string we get from user_input
6960Sstevel@tonic-gate 	 * - we skip leading whitespaces and ignore trailing whitespaces
6970Sstevel@tonic-gate 	 */
6980Sstevel@tonic-gate 	while (*ptr != '\0') {
6990Sstevel@tonic-gate 		if ((*ptr == ' ') || (*ptr == '\t'))
7000Sstevel@tonic-gate 			break;
7010Sstevel@tonic-gate 		else {
7020Sstevel@tonic-gate 			username[index] = *ptr;
7030Sstevel@tonic-gate 			index++;
7040Sstevel@tonic-gate 			ptr++;
7050Sstevel@tonic-gate 		}
7060Sstevel@tonic-gate 	}
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	/* ret_username will be freed in pam_get_user(). */
7090Sstevel@tonic-gate 	if ((*ret_username = (char *)malloc((index + 1)*(sizeof (char))))
7100Sstevel@tonic-gate 	    == NULL)
7110Sstevel@tonic-gate 		return (PAM_BUF_ERR);
7120Sstevel@tonic-gate 	(void) strcpy(*ret_username, username);
7130Sstevel@tonic-gate 	return (PAM_SUCCESS);
7140Sstevel@tonic-gate }
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate /*
7170Sstevel@tonic-gate  * Get the value of PAM_USER. If not set, then use the convenience function
7180Sstevel@tonic-gate  * to prompt for the user. Use prompt if specified, else use PAM_USER_PROMPT
7190Sstevel@tonic-gate  * if it is set, else use default.
7200Sstevel@tonic-gate  */
7210Sstevel@tonic-gate #define	WHITESPACE	0
7220Sstevel@tonic-gate #define	USERNAME	1
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate int
7250Sstevel@tonic-gate pam_get_user(pam_handle_t *pamh, char **user, const char *prompt_override)
7260Sstevel@tonic-gate {
7270Sstevel@tonic-gate 	int	status;
7280Sstevel@tonic-gate 	char	*prompt = NULL;
7290Sstevel@tonic-gate 	char    *real_username;
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	struct pam_response *ret_resp = NULL;
7320Sstevel@tonic-gate 	char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	pam_trace(PAM_DEBUG_DEFAULT,
7350Sstevel@tonic-gate 	    "pam_get_user(%p, %p, %s)", (void *)pamh, (void *)*user,
7360Sstevel@tonic-gate 	    prompt_override ? prompt_override : "NULL");
7370Sstevel@tonic-gate 	if (pamh == NULL)
7380Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	if ((status = pam_get_item(pamh, PAM_USER, (void **)user))
7410Sstevel@tonic-gate 	    != PAM_SUCCESS) {
7420Sstevel@tonic-gate 		return (status);
7430Sstevel@tonic-gate 	}
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	/* if the user is set, return it */
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	if (*user != NULL && *user[0] != '\0') {
7480Sstevel@tonic-gate 		return (PAM_SUCCESS);
7490Sstevel@tonic-gate 	}
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	/*
7520Sstevel@tonic-gate 	 * if the module is requesting a special prompt, use it.
7530Sstevel@tonic-gate 	 * else use PAM_USER_PROMPT.
7540Sstevel@tonic-gate 	 */
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	if (prompt_override != NULL) {
7570Sstevel@tonic-gate 		prompt = (char *)prompt_override;
7580Sstevel@tonic-gate 	} else {
7590Sstevel@tonic-gate 		status = pam_get_item(pamh, PAM_USER_PROMPT, (void**)&prompt);
7600Sstevel@tonic-gate 		if (status != PAM_SUCCESS) {
7610Sstevel@tonic-gate 			return (status);
7620Sstevel@tonic-gate 		}
7630Sstevel@tonic-gate 	}
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	/* if the prompt is not set, use default */
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	if (prompt == NULL || prompt[0] == '\0') {
7680Sstevel@tonic-gate 		prompt = dgettext(TEXT_DOMAIN, "Please enter user name: ");
7690Sstevel@tonic-gate 	}
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 	/* prompt for the user */
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 	(void) strncpy(messages[0], prompt, sizeof (messages[0]));
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	for (;;) {
7760Sstevel@tonic-gate 		int state = WHITESPACE;
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 		status = do_conv(pamh, PAM_PROMPT_ECHO_ON, 1, messages,
7790Sstevel@tonic-gate 		    NULL, &ret_resp);
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 		if (status != PAM_SUCCESS) {
7820Sstevel@tonic-gate 			return (status);
7830Sstevel@tonic-gate 		}
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 		if (ret_resp->resp && ret_resp->resp[0] != '\0') {
7860Sstevel@tonic-gate 			int len = strlen(ret_resp->resp);
7870Sstevel@tonic-gate 			int i;
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 			for (i = 0; i < len; i++) {
7900Sstevel@tonic-gate 				if ((ret_resp->resp[i] != ' ') &&
7910Sstevel@tonic-gate 					(ret_resp->resp[i] != '\t')) {
7920Sstevel@tonic-gate 					state = USERNAME;
7930Sstevel@tonic-gate 					break;
7940Sstevel@tonic-gate 				}
7950Sstevel@tonic-gate 			}
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 			if (state == USERNAME)
7980Sstevel@tonic-gate 				break;
7990Sstevel@tonic-gate 		}
8000Sstevel@tonic-gate 	}
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	/* set PAM_USER */
8030Sstevel@tonic-gate 	/* Parse the user input to get the user name. */
8040Sstevel@tonic-gate 	status = parse_user_name(ret_resp->resp, &real_username);
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 	if (status != PAM_SUCCESS) {
8070Sstevel@tonic-gate 		if (real_username != NULL)
8080Sstevel@tonic-gate 			free(real_username);
8090Sstevel@tonic-gate 		free_resp(1, ret_resp);
8100Sstevel@tonic-gate 		return (status);
8110Sstevel@tonic-gate 	}
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 	status = pam_set_item(pamh, PAM_USER, real_username);
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	free(real_username);
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	free_resp(1, ret_resp);
8180Sstevel@tonic-gate 	if (status != PAM_SUCCESS) {
8190Sstevel@tonic-gate 		return (status);
8200Sstevel@tonic-gate 	}
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 	/*
8230Sstevel@tonic-gate 	 * finally, get PAM_USER. We have to call pam_get_item to get
8240Sstevel@tonic-gate 	 * the value of user because pam_set_item mallocs the memory.
8250Sstevel@tonic-gate 	 */
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 	status = pam_get_item(pamh, PAM_USER, (void**)user);
8280Sstevel@tonic-gate 	return (status);
8290Sstevel@tonic-gate }
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate /*
8320Sstevel@tonic-gate  * Set module specific data
8330Sstevel@tonic-gate  */
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate int
8360Sstevel@tonic-gate pam_set_data(pam_handle_t *pamh, const char *module_data_name, void *data,
8370Sstevel@tonic-gate     void (*cleanup)(pam_handle_t *pamh, void *data, int pam_end_status))
8380Sstevel@tonic-gate {
8390Sstevel@tonic-gate 	struct pam_module_data *psd;
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 	pam_trace(PAM_DEBUG_DATA,
8420Sstevel@tonic-gate 	    "pam_set_data(%p:%s:%d)=%p", (void *)pamh,
8430Sstevel@tonic-gate 	    module_data_name ? module_data_name : "NULL", pamh->pam_inmodule,
8440Sstevel@tonic-gate 	    data);
8450Sstevel@tonic-gate 	if (pamh == NULL || (pamh->pam_inmodule != WO_OK) ||
8460Sstevel@tonic-gate 	    module_data_name == NULL) {
8470Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
8480Sstevel@tonic-gate 	}
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	/* check if module data already exists */
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	for (psd = pamh->ssd; psd; psd = psd->next) {
8530Sstevel@tonic-gate 		if (strcmp(psd->module_data_name, module_data_name) == 0) {
8540Sstevel@tonic-gate 			/* clean up original data before setting the new data */
8550Sstevel@tonic-gate 			if (psd->cleanup) {
8560Sstevel@tonic-gate 				psd->cleanup(pamh, psd->data, PAM_SUCCESS);
8570Sstevel@tonic-gate 			}
8580Sstevel@tonic-gate 			psd->data = (void *)data;
8590Sstevel@tonic-gate 			psd->cleanup = cleanup;
8600Sstevel@tonic-gate 			return (PAM_SUCCESS);
8610Sstevel@tonic-gate 		}
8620Sstevel@tonic-gate 	}
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	psd = malloc(sizeof (struct pam_module_data));
8650Sstevel@tonic-gate 	if (psd == NULL)
8660Sstevel@tonic-gate 		return (PAM_BUF_ERR);
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	psd->module_data_name = strdup(module_data_name);
8690Sstevel@tonic-gate 	if (psd->module_data_name == NULL) {
8700Sstevel@tonic-gate 		free(psd);
8710Sstevel@tonic-gate 		return (PAM_BUF_ERR);
8720Sstevel@tonic-gate 	}
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	psd->data = (void *)data;
8750Sstevel@tonic-gate 	psd->cleanup = cleanup;
8760Sstevel@tonic-gate 	psd->next = pamh->ssd;
8770Sstevel@tonic-gate 	pamh->ssd = psd;
8780Sstevel@tonic-gate 	return (PAM_SUCCESS);
8790Sstevel@tonic-gate }
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate /*
8820Sstevel@tonic-gate  * get module specific data
8830Sstevel@tonic-gate  */
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate int
8860Sstevel@tonic-gate pam_get_data(const pam_handle_t *pamh, const char *module_data_name,
8870Sstevel@tonic-gate     const void **data)
8880Sstevel@tonic-gate {
8890Sstevel@tonic-gate 	struct pam_module_data *psd;
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	if (pamh == NULL || (pamh->pam_inmodule != WO_OK) ||
8920Sstevel@tonic-gate 	    module_data_name == NULL) {
8930Sstevel@tonic-gate 		pam_trace(PAM_DEBUG_DATA,
8940Sstevel@tonic-gate 		    "pam_get_data(%p:%s:%d)=%p", (void *)pamh,
8950Sstevel@tonic-gate 		    module_data_name ? module_data_name : "NULL",
8960Sstevel@tonic-gate 		    pamh->pam_inmodule, *data);
8970Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
8980Sstevel@tonic-gate 	}
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	for (psd = pamh->ssd; psd; psd = psd->next) {
9010Sstevel@tonic-gate 		if (strcmp(psd->module_data_name, module_data_name) == 0) {
9020Sstevel@tonic-gate 			*data = psd->data;
9030Sstevel@tonic-gate 			pam_trace(PAM_DEBUG_DATA,
9040Sstevel@tonic-gate 			    "pam_get_data(%p:%s)=%p", (void *)pamh,
9050Sstevel@tonic-gate 			    module_data_name, *data);
9060Sstevel@tonic-gate 			return (PAM_SUCCESS);
9070Sstevel@tonic-gate 		}
9080Sstevel@tonic-gate 	}
9090Sstevel@tonic-gate 	pam_trace(PAM_DEBUG_DATA,
9100Sstevel@tonic-gate 	    "pam_get_data(%p:%s)=%s", (void *)pamh, module_data_name,
9110Sstevel@tonic-gate 	    "PAM_NO_MODULE_DATA");
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	return (PAM_NO_MODULE_DATA);
9140Sstevel@tonic-gate }
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate /*
9170Sstevel@tonic-gate  * PAM equivalent to strerror()
9180Sstevel@tonic-gate  */
9190Sstevel@tonic-gate /* ARGSUSED */
9200Sstevel@tonic-gate const char *
9210Sstevel@tonic-gate pam_strerror(pam_handle_t *pamh, int errnum)
9220Sstevel@tonic-gate {
9230Sstevel@tonic-gate 	switch (errnum) {
9240Sstevel@tonic-gate 	case PAM_SUCCESS:
9250Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Success"));
9260Sstevel@tonic-gate 	case PAM_OPEN_ERR:
9270Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Dlopen failure"));
9280Sstevel@tonic-gate 	case PAM_SYMBOL_ERR:
9290Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Symbol not found"));
9300Sstevel@tonic-gate 	case PAM_SERVICE_ERR:
9310Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
9320Sstevel@tonic-gate 		    "Error in underlying service module"));
9330Sstevel@tonic-gate 	case PAM_SYSTEM_ERR:
9340Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "System error"));
9350Sstevel@tonic-gate 	case PAM_BUF_ERR:
9360Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Memory buffer error"));
9370Sstevel@tonic-gate 	case PAM_CONV_ERR:
9380Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Conversation failure"));
9390Sstevel@tonic-gate 	case PAM_PERM_DENIED:
9400Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Permission denied"));
9410Sstevel@tonic-gate 	case PAM_MAXTRIES:
9420Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
9430Sstevel@tonic-gate 		    "Maximum number of attempts exceeded"));
9440Sstevel@tonic-gate 	case PAM_AUTH_ERR:
9450Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Authentication failed"));
9460Sstevel@tonic-gate 	case PAM_NEW_AUTHTOK_REQD:
9470Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Get new authentication token"));
9480Sstevel@tonic-gate 	case PAM_CRED_INSUFFICIENT:
9490Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Insufficient credentials"));
9500Sstevel@tonic-gate 	case PAM_AUTHINFO_UNAVAIL:
9510Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
9520Sstevel@tonic-gate 		    "Can not retrieve authentication info"));
9530Sstevel@tonic-gate 	case PAM_USER_UNKNOWN:
9540Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "No account present for user"));
9550Sstevel@tonic-gate 	case PAM_CRED_UNAVAIL:
9560Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
9570Sstevel@tonic-gate 		    "Can not retrieve user credentials"));
9580Sstevel@tonic-gate 	case PAM_CRED_EXPIRED:
9590Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
9600Sstevel@tonic-gate 		    "User credentials have expired"));
9610Sstevel@tonic-gate 	case PAM_CRED_ERR:
9620Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
9630Sstevel@tonic-gate 		    "Failure setting user credentials"));
9640Sstevel@tonic-gate 	case PAM_ACCT_EXPIRED:
9650Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "User account has expired"));
9660Sstevel@tonic-gate 	case PAM_AUTHTOK_EXPIRED:
9670Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "User password has expired"));
9680Sstevel@tonic-gate 	case PAM_SESSION_ERR:
9690Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
9700Sstevel@tonic-gate 		    "Can not make/remove entry for session"));
9710Sstevel@tonic-gate 	case PAM_AUTHTOK_ERR:
9720Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
9730Sstevel@tonic-gate 		    "Authentication token manipulation error"));
9740Sstevel@tonic-gate 	case PAM_AUTHTOK_RECOVERY_ERR:
9750Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
9760Sstevel@tonic-gate 		    "Authentication token can not be recovered"));
9770Sstevel@tonic-gate 	case PAM_AUTHTOK_LOCK_BUSY:
9780Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
9790Sstevel@tonic-gate 		    "Authentication token lock busy"));
9800Sstevel@tonic-gate 	case PAM_AUTHTOK_DISABLE_AGING:
9810Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
9820Sstevel@tonic-gate 		    "Authentication token aging disabled"));
9830Sstevel@tonic-gate 	case PAM_NO_MODULE_DATA:
9840Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
9850Sstevel@tonic-gate 		    "Module specific data not found"));
9860Sstevel@tonic-gate 	case PAM_IGNORE:
9870Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Ignore module"));
9880Sstevel@tonic-gate 	case PAM_ABORT:
9890Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "General PAM failure "));
9900Sstevel@tonic-gate 	case PAM_TRY_AGAIN:
9910Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
9920Sstevel@tonic-gate 		    "Unable to complete operation. Try again"));
9930Sstevel@tonic-gate 	default:
9940Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Unknown error"));
9950Sstevel@tonic-gate 	}
9960Sstevel@tonic-gate }
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate static void *
9990Sstevel@tonic-gate sm_name(int ind)
10000Sstevel@tonic-gate {
10010Sstevel@tonic-gate 	switch (ind) {
10020Sstevel@tonic-gate 	case PAM_AUTHENTICATE:
10030Sstevel@tonic-gate 		return (PAM_SM_AUTHENTICATE);
10040Sstevel@tonic-gate 	case PAM_SETCRED:
10050Sstevel@tonic-gate 		return (PAM_SM_SETCRED);
10060Sstevel@tonic-gate 	case PAM_ACCT_MGMT:
10070Sstevel@tonic-gate 		return (PAM_SM_ACCT_MGMT);
10080Sstevel@tonic-gate 	case PAM_OPEN_SESSION:
10090Sstevel@tonic-gate 		return (PAM_SM_OPEN_SESSION);
10100Sstevel@tonic-gate 	case PAM_CLOSE_SESSION:
10110Sstevel@tonic-gate 		return (PAM_SM_CLOSE_SESSION);
10120Sstevel@tonic-gate 	case PAM_CHAUTHTOK:
10130Sstevel@tonic-gate 		return (PAM_SM_CHAUTHTOK);
10140Sstevel@tonic-gate 	}
10150Sstevel@tonic-gate 	return (NULL);
10160Sstevel@tonic-gate }
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate static int
10190Sstevel@tonic-gate (*func(pamtab_t *modulep, int ind))()
10200Sstevel@tonic-gate {
10210Sstevel@tonic-gate 	void	*funcp;
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	if ((funcp = modulep->function_ptr) == NULL)
10240Sstevel@tonic-gate 		return (NULL);
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	switch (ind) {
10270Sstevel@tonic-gate 	case PAM_AUTHENTICATE:
10280Sstevel@tonic-gate 		return (((struct auth_module *)funcp)->pam_sm_authenticate);
10290Sstevel@tonic-gate 	case PAM_SETCRED:
10300Sstevel@tonic-gate 		return (((struct auth_module *)funcp)->pam_sm_setcred);
10310Sstevel@tonic-gate 	case PAM_ACCT_MGMT:
10320Sstevel@tonic-gate 		return (((struct account_module *)funcp)->pam_sm_acct_mgmt);
10330Sstevel@tonic-gate 	case PAM_OPEN_SESSION:
10340Sstevel@tonic-gate 		return (((struct session_module *)funcp)->pam_sm_open_session);
10350Sstevel@tonic-gate 	case PAM_CLOSE_SESSION:
10360Sstevel@tonic-gate 		return (((struct session_module *)funcp)->pam_sm_close_session);
10370Sstevel@tonic-gate 	case PAM_CHAUTHTOK:
10380Sstevel@tonic-gate 		return (((struct password_module *)funcp)->pam_sm_chauthtok);
10390Sstevel@tonic-gate 	}
10400Sstevel@tonic-gate 	return (NULL);
10410Sstevel@tonic-gate }
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate /*
10440Sstevel@tonic-gate  * Run through the PAM service module stack for the given module type.
10450Sstevel@tonic-gate  */
10460Sstevel@tonic-gate static int
10470Sstevel@tonic-gate run_stack(pam_handle_t *pamh, int flags, int type, int def_err, int ind,
10480Sstevel@tonic-gate     char *function_name)
10490Sstevel@tonic-gate {
10500Sstevel@tonic-gate 	int	err = PAM_SYSTEM_ERR;  /* preset */
10510Sstevel@tonic-gate 	int	optional_error = 0;
10520Sstevel@tonic-gate 	int	required_error = 0;
10530Sstevel@tonic-gate 	int	success = 0;
10540Sstevel@tonic-gate 	pamtab_t *modulep;
10550Sstevel@tonic-gate 	int	(*sm_func)();
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	if (pamh == NULL)
10580Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate 	/* read initial entries from pam.conf */
10610Sstevel@tonic-gate 	if ((err = read_pam_conf(pamh, PAM_CONFIG)) != PAM_SUCCESS) {
10620Sstevel@tonic-gate 		return (err);
10630Sstevel@tonic-gate 	}
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 	if ((modulep =
10660Sstevel@tonic-gate 	    pamh->pam_conf_info[pamh->include_depth][type]) == NULL) {
10670Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ERR, "%s no initial module present",
10680Sstevel@tonic-gate 		    pam_trace_cname(pamh));
10690Sstevel@tonic-gate 		goto exit_return;
10700Sstevel@tonic-gate 	}
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	pamh->pam_inmodule = WO_OK;	/* OK to get AUTHTOK */
10730Sstevel@tonic-gate include:
10740Sstevel@tonic-gate 	pam_trace(PAM_DEBUG_MODULE,
10750Sstevel@tonic-gate 	    "[%d:%s]:run_stack:%s(%p, %x): %s", pamh->include_depth,
10760Sstevel@tonic-gate 	    pam_trace_cname(pamh), function_name, (void *)pamh, flags,
10770Sstevel@tonic-gate 	    modulep ? modulep->module_path : "NULL");
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 	while (modulep != NULL) {
10800Sstevel@tonic-gate 		if (modulep->pam_flag & PAM_INCLUDE) {
10810Sstevel@tonic-gate 			/* save the return location */
10820Sstevel@tonic-gate 			pamh->pam_conf_modulep[pamh->include_depth] =
10830Sstevel@tonic-gate 			    modulep->next;
10840Sstevel@tonic-gate 			pam_trace(PAM_DEBUG_MODULE,
10850Sstevel@tonic-gate 			    "setting for include[%d:%p]",
10860Sstevel@tonic-gate 			    pamh->include_depth, (void *)modulep->next);
10870Sstevel@tonic-gate 			if (pamh->include_depth++ >= PAM_MAX_INCLUDE) {
10880Sstevel@tonic-gate 				__pam_log(LOG_AUTH | LOG_ERR,
10890Sstevel@tonic-gate 				    "run_stack: includes too deep %d "
10900Sstevel@tonic-gate 				    "found trying to include %s from %s, %d "
10910Sstevel@tonic-gate 				    "allowed", pamh->include_depth,
10920Sstevel@tonic-gate 				    modulep->module_path, pamh->pam_conf_name
10930Sstevel@tonic-gate 				    [PAM_MAX_INCLUDE] == NULL ? "NULL" :
10940Sstevel@tonic-gate 				    pamh->pam_conf_name[PAM_MAX_INCLUDE],
10950Sstevel@tonic-gate 				    PAM_MAX_INCLUDE);
10960Sstevel@tonic-gate 				goto exit_return;
10970Sstevel@tonic-gate 			}
10980Sstevel@tonic-gate 			if ((err = read_pam_conf(pamh,
10990Sstevel@tonic-gate 			    modulep->module_path)) != PAM_SUCCESS) {
11000Sstevel@tonic-gate 				__pam_log(LOG_AUTH | LOG_ERR,
11010Sstevel@tonic-gate 				    "run_stack[%d:%s]: can't read included "
11020Sstevel@tonic-gate 				    "conf %s", pamh->include_depth,
11030Sstevel@tonic-gate 				    pam_trace_cname(pamh),
11040Sstevel@tonic-gate 				    modulep->module_path);
11050Sstevel@tonic-gate 				goto exit_return;
11060Sstevel@tonic-gate 			}
11070Sstevel@tonic-gate 			if ((modulep = pamh->pam_conf_info
11080Sstevel@tonic-gate 			    [pamh->include_depth][type]) == NULL) {
11090Sstevel@tonic-gate 				__pam_log(LOG_AUTH | LOG_ERR,
11100Sstevel@tonic-gate 				    "run_stack[%d:%s]: no include module "
11110Sstevel@tonic-gate 				    "present %s", pamh->include_depth,
11120Sstevel@tonic-gate 				    pam_trace_cname(pamh), function_name);
11130Sstevel@tonic-gate 				goto exit_return;
11140Sstevel@tonic-gate 			}
11150Sstevel@tonic-gate 			if (modulep->pam_flag & PAM_INCLUDE) {
11160Sstevel@tonic-gate 				/* first line another include */
11170Sstevel@tonic-gate 				goto include;
11180Sstevel@tonic-gate 			}
11190Sstevel@tonic-gate 			pam_trace(PAM_DEBUG_DEFAULT, "include[%d:%s]"
11200Sstevel@tonic-gate 			    "(%p, %s)=%s", pamh->include_depth,
11210Sstevel@tonic-gate 			    pam_trace_cname(pamh), (void *)pamh,
11220Sstevel@tonic-gate 			    function_name, modulep->module_path);
11230Sstevel@tonic-gate 			if ((err = load_modules(pamh, type, sm_name(ind),
11240Sstevel@tonic-gate 			    pamh->pam_conf_info
11250Sstevel@tonic-gate 			    [pamh->include_depth][type])) != PAM_SUCCESS) {
11260Sstevel@tonic-gate 				pam_trace(PAM_DEBUG_DEFAULT,
11270Sstevel@tonic-gate 				    "[%d:%s]:%s(%p, %x): load_modules failed",
11280Sstevel@tonic-gate 				    pamh->include_depth, pam_trace_cname(pamh),
11290Sstevel@tonic-gate 				    function_name, (void *)pamh, flags);
11300Sstevel@tonic-gate 				goto exit_return;
11310Sstevel@tonic-gate 			}
11320Sstevel@tonic-gate 			if ((modulep = pamh->pam_conf_info
11330Sstevel@tonic-gate 			    [pamh->include_depth][type]) == NULL) {
11340Sstevel@tonic-gate 				__pam_log(LOG_AUTH | LOG_ERR,
11350Sstevel@tonic-gate 				    "%s no initial module present",
11360Sstevel@tonic-gate 				    pam_trace_cname(pamh));
11370Sstevel@tonic-gate 				goto exit_return;
11380Sstevel@tonic-gate 			}
11390Sstevel@tonic-gate 		} else if ((err = load_modules(pamh, type, sm_name(ind),
11400Sstevel@tonic-gate 		    modulep)) != PAM_SUCCESS) {
11410Sstevel@tonic-gate 			pam_trace(PAM_DEBUG_DEFAULT,
11420Sstevel@tonic-gate 			    "[%d:%s]:%s(%p, %x): load_modules failed",
11430Sstevel@tonic-gate 			    pamh->include_depth, pam_trace_cname(pamh),
11440Sstevel@tonic-gate 			    function_name, (void *)pamh, flags);
11450Sstevel@tonic-gate 			goto exit_return;
11460Sstevel@tonic-gate 		}  /* PAM_INCLUDE */
11470Sstevel@tonic-gate 		sm_func = func(modulep, ind);
11480Sstevel@tonic-gate 		if (sm_func) {
11490Sstevel@tonic-gate 			err = sm_func(pamh, flags, modulep->module_argc,
11500Sstevel@tonic-gate 			    (const char **)modulep->module_argv);
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 			pam_trace(PAM_DEBUG_MODULE,
11530Sstevel@tonic-gate 			    "[%d:%s]:%s(%p, %x): %s returned %s",
11540Sstevel@tonic-gate 			    pamh->include_depth, pam_trace_cname(pamh),
11550Sstevel@tonic-gate 			    function_name, (void *)pamh, flags,
11560Sstevel@tonic-gate 			    modulep->module_path, pam_strerror(pamh, err));
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 			switch (err) {
11590Sstevel@tonic-gate 			case PAM_IGNORE:
11600Sstevel@tonic-gate 				/* do nothing */
11610Sstevel@tonic-gate 				break;
11620Sstevel@tonic-gate 			case PAM_SUCCESS:
11630Sstevel@tonic-gate 				if ((modulep->pam_flag & PAM_SUFFI_BIND) &&
11640Sstevel@tonic-gate 				    !required_error) {
11650Sstevel@tonic-gate 					pamh->pam_inmodule = RW_OK;
11660Sstevel@tonic-gate 					pam_trace(PAM_DEBUG_MODULE,
11670Sstevel@tonic-gate 					    "[%d:%s]:%s(%p, %x): %s: success",
11680Sstevel@tonic-gate 					    pamh->include_depth,
11690Sstevel@tonic-gate 					    pam_trace_cname(pamh),
11700Sstevel@tonic-gate 					    function_name, (void *)pamh, flags,
11710Sstevel@tonic-gate 					    (modulep->pam_flag & PAM_BINDING) ?
11720Sstevel@tonic-gate 					    PAM_BINDING_NAME :
11730Sstevel@tonic-gate 					    PAM_SUFFICIENT_NAME);
11740Sstevel@tonic-gate 					goto exit_return;
11750Sstevel@tonic-gate 				}
11760Sstevel@tonic-gate 				success = 1;
11770Sstevel@tonic-gate 				break;
11780Sstevel@tonic-gate 			case PAM_TRY_AGAIN:
11790Sstevel@tonic-gate 				/*
11800Sstevel@tonic-gate 				 * We need to return immediately, and
11810Sstevel@tonic-gate 				 * we shouldn't reset the AUTHTOK item
11820Sstevel@tonic-gate 				 * since it is not an error per-se.
11830Sstevel@tonic-gate 				 */
11840Sstevel@tonic-gate 				pamh->pam_inmodule = RW_OK;
11850Sstevel@tonic-gate 				pam_trace(PAM_DEBUG_MODULE,
11860Sstevel@tonic-gate 				    "[%d:%s]:%s(%p, %x): TRY_AGAIN: %s",
11870Sstevel@tonic-gate 				    pamh->include_depth, pam_trace_cname(pamh),
11880Sstevel@tonic-gate 				    function_name, (void *)pamh, flags,
11890Sstevel@tonic-gate 				    pam_strerror(pamh, required_error ?
11900Sstevel@tonic-gate 				    required_error : err));
11910Sstevel@tonic-gate 				err = required_error ? required_error : err;
11920Sstevel@tonic-gate 				goto exit_return;
11930Sstevel@tonic-gate 			default:
11940Sstevel@tonic-gate 				if (modulep->pam_flag & PAM_REQUISITE) {
11950Sstevel@tonic-gate 					pamh->pam_inmodule = RW_OK;
11960Sstevel@tonic-gate 					pam_trace(PAM_DEBUG_MODULE,
11970Sstevel@tonic-gate 					    "[%d:%s]:%s(%p, %x): requisite: %s",
11980Sstevel@tonic-gate 					    pamh->include_depth,
11990Sstevel@tonic-gate 					    pam_trace_cname(pamh),
12000Sstevel@tonic-gate 					    function_name, (void *)pamh, flags,
12010Sstevel@tonic-gate 					    pam_strerror(pamh,
12020Sstevel@tonic-gate 					    required_error ? required_error :
12030Sstevel@tonic-gate 					    err));
12040Sstevel@tonic-gate 					err = required_error ?
12050Sstevel@tonic-gate 					    required_error : err;
12060Sstevel@tonic-gate 					goto exit_return;
12070Sstevel@tonic-gate 				} else if (modulep->pam_flag & PAM_REQRD_BIND) {
12080Sstevel@tonic-gate 					if (!required_error)
12090Sstevel@tonic-gate 						required_error = err;
12100Sstevel@tonic-gate 				} else {
12110Sstevel@tonic-gate 					if (!optional_error)
12120Sstevel@tonic-gate 						optional_error = err;
12130Sstevel@tonic-gate 				}
12140Sstevel@tonic-gate 				pam_trace(PAM_DEBUG_DEFAULT,
12150Sstevel@tonic-gate 				    "[%d:%s]:%s(%p, %x): error %s",
12160Sstevel@tonic-gate 				    pamh->include_depth, pam_trace_cname(pamh),
12170Sstevel@tonic-gate 				    function_name, (void *)pamh, flags,
12180Sstevel@tonic-gate 				    pam_strerror(pamh, err));
12190Sstevel@tonic-gate 				break;
12200Sstevel@tonic-gate 			}
12210Sstevel@tonic-gate 		}
12220Sstevel@tonic-gate 		modulep = modulep->next;
12230Sstevel@tonic-gate 	}
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 	pam_trace(PAM_DEBUG_MODULE, "[%d:%s]:stack_end:%s(%p, %x): %s %s: %s",
12260Sstevel@tonic-gate 	    pamh->include_depth, pam_trace_cname(pamh), function_name,
12270Sstevel@tonic-gate 	    (void *)pamh, flags, pamh->include_depth ? "included" : "final",
12280Sstevel@tonic-gate 	    required_error ? "required" : success ? "success" :
12290Sstevel@tonic-gate 	    optional_error ? "optional" : "default",
12300Sstevel@tonic-gate 	    pam_strerror(pamh, required_error ? required_error :
12310Sstevel@tonic-gate 	    success ? PAM_SUCCESS : optional_error ? optional_error : def_err));
12320Sstevel@tonic-gate 	if (pamh->include_depth > 0) {
12330Sstevel@tonic-gate 		free_pam_conf_info(pamh);
12340Sstevel@tonic-gate 		pamh->include_depth--;
12350Sstevel@tonic-gate 		/* continue at next entry */
12360Sstevel@tonic-gate 		modulep = pamh->pam_conf_modulep[pamh->include_depth];
12370Sstevel@tonic-gate 		pam_trace(PAM_DEBUG_MODULE, "looping for include[%d:%p]",
12380Sstevel@tonic-gate 		    pamh->include_depth, (void *)modulep);
12390Sstevel@tonic-gate 		goto include;
12400Sstevel@tonic-gate 	}
12410Sstevel@tonic-gate 	free_pam_conf_info(pamh);
12420Sstevel@tonic-gate 	pamh->pam_inmodule = RW_OK;
12430Sstevel@tonic-gate 	if (required_error != 0)
12440Sstevel@tonic-gate 		return (required_error);
12450Sstevel@tonic-gate 	else if (success != 0)
12460Sstevel@tonic-gate 		return (PAM_SUCCESS);
12470Sstevel@tonic-gate 	else if (optional_error != 0)
12480Sstevel@tonic-gate 		return (optional_error);
12490Sstevel@tonic-gate 	else
12500Sstevel@tonic-gate 		return (def_err);
12510Sstevel@tonic-gate 
12520Sstevel@tonic-gate exit_return:
12530Sstevel@tonic-gate 	/*
12540Sstevel@tonic-gate 	 * All done at whatever depth we're at.
12550Sstevel@tonic-gate 	 * Go back to not having read /etc/pam.conf
12560Sstevel@tonic-gate 	 */
12570Sstevel@tonic-gate 	while (pamh->include_depth > 0) {
12580Sstevel@tonic-gate 		free_pam_conf_info(pamh);
12590Sstevel@tonic-gate 		pamh->include_depth--;
12600Sstevel@tonic-gate 	}
12610Sstevel@tonic-gate 	free_pam_conf_info(pamh);
12620Sstevel@tonic-gate 	pamh->pam_inmodule = RW_OK;
12630Sstevel@tonic-gate 	return (err);
12640Sstevel@tonic-gate }
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate /*
12670Sstevel@tonic-gate  * pam_authenticate - authenticate a user
12680Sstevel@tonic-gate  */
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate int
12710Sstevel@tonic-gate pam_authenticate(pam_handle_t *pamh, int flags)
12720Sstevel@tonic-gate {
12730Sstevel@tonic-gate 	int	retval;
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 	retval = run_stack(pamh, flags, PAM_AUTH_MODULE, PAM_AUTH_ERR,
12760Sstevel@tonic-gate 	    PAM_AUTHENTICATE, "pam_authenticate");
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate 	if (retval != PAM_SUCCESS)
12790Sstevel@tonic-gate 		(void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
12800Sstevel@tonic-gate 	return (retval);
12810Sstevel@tonic-gate }
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate /*
12840Sstevel@tonic-gate  * pam_setcred - modify or retrieve user credentials
12850Sstevel@tonic-gate  */
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate int
12880Sstevel@tonic-gate pam_setcred(pam_handle_t *pamh, int flags)
12890Sstevel@tonic-gate {
12900Sstevel@tonic-gate 	int	retval;
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 	retval = run_stack(pamh, flags, PAM_AUTH_MODULE, PAM_CRED_ERR,
12930Sstevel@tonic-gate 	    PAM_SETCRED, "pam_setcred");
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate 	if (retval != PAM_SUCCESS)
12960Sstevel@tonic-gate 		(void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
12970Sstevel@tonic-gate 	return (retval);
12980Sstevel@tonic-gate }
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate /*
13010Sstevel@tonic-gate  * pam_acct_mgmt - check password aging, account expiration
13020Sstevel@tonic-gate  */
13030Sstevel@tonic-gate 
13040Sstevel@tonic-gate int
13050Sstevel@tonic-gate pam_acct_mgmt(pam_handle_t *pamh, int flags)
13060Sstevel@tonic-gate {
13070Sstevel@tonic-gate 	int	retval;
13080Sstevel@tonic-gate 
13090Sstevel@tonic-gate 	retval = run_stack(pamh, flags, PAM_ACCOUNT_MODULE, PAM_ACCT_EXPIRED,
13100Sstevel@tonic-gate 	    PAM_ACCT_MGMT, "pam_acct_mgmt");
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate 	if (retval != PAM_SUCCESS &&
13130Sstevel@tonic-gate 	    retval != PAM_NEW_AUTHTOK_REQD) {
13140Sstevel@tonic-gate 		(void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
13150Sstevel@tonic-gate 	}
13160Sstevel@tonic-gate 	return (retval);
13170Sstevel@tonic-gate }
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate /*
13200Sstevel@tonic-gate  * pam_open_session - begin session management
13210Sstevel@tonic-gate  */
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate int
13240Sstevel@tonic-gate pam_open_session(pam_handle_t *pamh, int flags)
13250Sstevel@tonic-gate {
13260Sstevel@tonic-gate 	int	retval;
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate 	retval = run_stack(pamh, flags, PAM_SESSION_MODULE, PAM_SESSION_ERR,
13290Sstevel@tonic-gate 	    PAM_OPEN_SESSION, "pam_open_session");
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 	if (retval != PAM_SUCCESS)
13320Sstevel@tonic-gate 		(void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
13330Sstevel@tonic-gate 	return (retval);
13340Sstevel@tonic-gate }
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate /*
13370Sstevel@tonic-gate  * pam_close_session - terminate session management
13380Sstevel@tonic-gate  */
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate int
13410Sstevel@tonic-gate pam_close_session(pam_handle_t *pamh, int flags)
13420Sstevel@tonic-gate {
13430Sstevel@tonic-gate 	int	retval;
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 	retval = run_stack(pamh, flags, PAM_SESSION_MODULE, PAM_SESSION_ERR,
13460Sstevel@tonic-gate 	    PAM_CLOSE_SESSION, "pam_close_session");
13470Sstevel@tonic-gate 
13480Sstevel@tonic-gate 	if (retval != PAM_SUCCESS)
13490Sstevel@tonic-gate 		(void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
13500Sstevel@tonic-gate 	return (retval);
13510Sstevel@tonic-gate }
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate /*
13540Sstevel@tonic-gate  * pam_chauthtok - change user authentication token
13550Sstevel@tonic-gate  */
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate int
13580Sstevel@tonic-gate pam_chauthtok(pam_handle_t *pamh, int flags)
13590Sstevel@tonic-gate {
13600Sstevel@tonic-gate 	int	retval;
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	/* do not let apps use PAM_PRELIM_CHECK or PAM_UPDATE_AUTHTOK */
13630Sstevel@tonic-gate 	if (flags & (PAM_PRELIM_CHECK | PAM_UPDATE_AUTHTOK)) {
13640Sstevel@tonic-gate 		pam_trace(PAM_DEBUG_DEFAULT,
13650Sstevel@tonic-gate 		    "pam_chauthtok(%p, %x): %s", (void *)pamh, flags,
13660Sstevel@tonic-gate 		    pam_strerror(pamh, PAM_SYMBOL_ERR));
13670Sstevel@tonic-gate 		return (PAM_SYMBOL_ERR);
13680Sstevel@tonic-gate 	}
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate 	/* 1st pass: PRELIM CHECK */
13710Sstevel@tonic-gate 	retval = run_stack(pamh, flags | PAM_PRELIM_CHECK, PAM_PASSWORD_MODULE,
13720Sstevel@tonic-gate 	    PAM_AUTHTOK_ERR, PAM_CHAUTHTOK, "pam_chauthtok-prelim");
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate 	if (retval == PAM_TRY_AGAIN)
13750Sstevel@tonic-gate 		return (retval);
13760Sstevel@tonic-gate 
13770Sstevel@tonic-gate 	if (retval != PAM_SUCCESS) {
13780Sstevel@tonic-gate 		(void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
13790Sstevel@tonic-gate 		return (retval);
13800Sstevel@tonic-gate 	}
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 	/* 2nd pass: UPDATE AUTHTOK */
13830Sstevel@tonic-gate 	retval = run_stack(pamh, flags | PAM_UPDATE_AUTHTOK,
13840Sstevel@tonic-gate 	    PAM_PASSWORD_MODULE, PAM_AUTHTOK_ERR, PAM_CHAUTHTOK,
13850Sstevel@tonic-gate 	    "pam_chauthtok-update");
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 	if (retval != PAM_SUCCESS)
13880Sstevel@tonic-gate 		(void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate 	return (retval);
13910Sstevel@tonic-gate }
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate /*
13940Sstevel@tonic-gate  * pam_putenv - add an environment variable to the PAM handle
13950Sstevel@tonic-gate  *	if name_value == 'NAME=VALUE'	then set variable to the value
13960Sstevel@tonic-gate  *	if name_value == 'NAME='	then set variable to an empty value
13970Sstevel@tonic-gate  *	if name_value == 'NAME'		then delete the variable
13980Sstevel@tonic-gate  */
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate int
14010Sstevel@tonic-gate pam_putenv(pam_handle_t *pamh, const char *name_value)
14020Sstevel@tonic-gate {
14030Sstevel@tonic-gate 	int		error = PAM_SYSTEM_ERR;
14040Sstevel@tonic-gate 	char		*equal_sign = 0;
14050Sstevel@tonic-gate 	char		*name = NULL, *value = NULL, *tmp_value = NULL;
14060Sstevel@tonic-gate 	env_list	*traverse, *trail;
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 	pam_trace(PAM_DEBUG_DEFAULT,
14090Sstevel@tonic-gate 	    "pam_putenv(%p, %s)", (void *)pamh,
14100Sstevel@tonic-gate 	    name_value ? name_value : "NULL");
14110Sstevel@tonic-gate 
14120Sstevel@tonic-gate 	if (pamh == NULL || name_value == NULL)
14130Sstevel@tonic-gate 		goto out;
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate 	/* see if we were passed 'NAME=VALUE', 'NAME=', or 'NAME' */
14160Sstevel@tonic-gate 	if ((equal_sign = strchr(name_value, '=')) != 0) {
14170Sstevel@tonic-gate 		if ((name = (char *)calloc(equal_sign - name_value + 1,
14180Sstevel@tonic-gate 		    sizeof (char))) == 0) {
14190Sstevel@tonic-gate 			error = PAM_BUF_ERR;
14200Sstevel@tonic-gate 			goto out;
14210Sstevel@tonic-gate 		}
14220Sstevel@tonic-gate 		(void) strncpy(name, name_value, equal_sign - name_value);
14230Sstevel@tonic-gate 		if ((value = strdup(++equal_sign)) == 0) {
14240Sstevel@tonic-gate 			error = PAM_BUF_ERR;
14250Sstevel@tonic-gate 			goto out;
14260Sstevel@tonic-gate 		}
14270Sstevel@tonic-gate 	} else {
14280Sstevel@tonic-gate 		if ((name = strdup(name_value)) == 0) {
14290Sstevel@tonic-gate 			error = PAM_BUF_ERR;
14300Sstevel@tonic-gate 			goto out;
14310Sstevel@tonic-gate 		}
14320Sstevel@tonic-gate 	}
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate 	/* check to see if we already have this variable in the PAM handle */
14350Sstevel@tonic-gate 	traverse = pamh->pam_env;
14360Sstevel@tonic-gate 	trail = traverse;
14370Sstevel@tonic-gate 	while (traverse && strncmp(traverse->name, name, strlen(name))) {
14380Sstevel@tonic-gate 		trail = traverse;
14390Sstevel@tonic-gate 		traverse = traverse->next;
14400Sstevel@tonic-gate 	}
14410Sstevel@tonic-gate 
14420Sstevel@tonic-gate 	if (traverse) {
14430Sstevel@tonic-gate 		/* found a match */
14440Sstevel@tonic-gate 		if (value == 0) {
14450Sstevel@tonic-gate 			/* remove the env variable */
14460Sstevel@tonic-gate 			if (pamh->pam_env == traverse)
14470Sstevel@tonic-gate 				pamh->pam_env = traverse->next;
14480Sstevel@tonic-gate 			else
14490Sstevel@tonic-gate 				trail->next = traverse->next;
14500Sstevel@tonic-gate 			free_env(traverse);
14510Sstevel@tonic-gate 		} else if (strlen(value) == 0) {
14520Sstevel@tonic-gate 			/* set env variable to empty value */
14530Sstevel@tonic-gate 			if ((tmp_value = strdup("")) == 0) {
14540Sstevel@tonic-gate 				error = PAM_SYSTEM_ERR;
14550Sstevel@tonic-gate 				goto out;
14560Sstevel@tonic-gate 			}
14570Sstevel@tonic-gate 			free(traverse->value);
14580Sstevel@tonic-gate 			traverse->value = tmp_value;
14590Sstevel@tonic-gate 		} else {
14600Sstevel@tonic-gate 			/* set the new value */
14610Sstevel@tonic-gate 			if ((tmp_value = strdup(value)) == 0) {
14620Sstevel@tonic-gate 				error = PAM_SYSTEM_ERR;
14630Sstevel@tonic-gate 				goto out;
14640Sstevel@tonic-gate 			}
14650Sstevel@tonic-gate 			free(traverse->value);
14660Sstevel@tonic-gate 			traverse->value = tmp_value;
14670Sstevel@tonic-gate 		}
14680Sstevel@tonic-gate 
14690Sstevel@tonic-gate 	} else if (traverse == 0 && value) {
14700Sstevel@tonic-gate 		/*
14710Sstevel@tonic-gate 		 * could not find a match in the PAM handle.
14720Sstevel@tonic-gate 		 * add the new value if there is one
14730Sstevel@tonic-gate 		 */
14740Sstevel@tonic-gate 		if ((traverse = (env_list *)calloc
14750Sstevel@tonic-gate 					(1,
14760Sstevel@tonic-gate 					sizeof (env_list))) == 0) {
14770Sstevel@tonic-gate 			error = PAM_BUF_ERR;
14780Sstevel@tonic-gate 			goto out;
14790Sstevel@tonic-gate 		}
14800Sstevel@tonic-gate 		if ((traverse->name = strdup(name)) == 0) {
14810Sstevel@tonic-gate 			free_env(traverse);
14820Sstevel@tonic-gate 			error = PAM_BUF_ERR;
14830Sstevel@tonic-gate 			goto out;
14840Sstevel@tonic-gate 		}
14850Sstevel@tonic-gate 		if ((traverse->value = strdup(value)) == 0) {
14860Sstevel@tonic-gate 			free_env(traverse);
14870Sstevel@tonic-gate 			error = PAM_BUF_ERR;
14880Sstevel@tonic-gate 			goto out;
14890Sstevel@tonic-gate 		}
14900Sstevel@tonic-gate 		if (trail == 0) {
14910Sstevel@tonic-gate 			/* new head of list */
14920Sstevel@tonic-gate 			pamh->pam_env = traverse;
14930Sstevel@tonic-gate 		} else {
14940Sstevel@tonic-gate 			/* adding to end of list */
14950Sstevel@tonic-gate 			trail->next = traverse;
14960Sstevel@tonic-gate 		}
14970Sstevel@tonic-gate 	}
14980Sstevel@tonic-gate 
14990Sstevel@tonic-gate 	error = PAM_SUCCESS;
15000Sstevel@tonic-gate out:
15010Sstevel@tonic-gate 	if (error != PAM_SUCCESS) {
15020Sstevel@tonic-gate 		if (traverse) {
15030Sstevel@tonic-gate 			if (traverse->name)
15040Sstevel@tonic-gate 				free(traverse->name);
15050Sstevel@tonic-gate 			if (traverse->value)
15060Sstevel@tonic-gate 				free(traverse->value);
15070Sstevel@tonic-gate 			free(traverse);
15080Sstevel@tonic-gate 		}
15090Sstevel@tonic-gate 	}
15100Sstevel@tonic-gate 	if (name)
15110Sstevel@tonic-gate 		free(name);
15120Sstevel@tonic-gate 	if (value)
15130Sstevel@tonic-gate 		free(value);
15140Sstevel@tonic-gate 	return (error);
15150Sstevel@tonic-gate }
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate /*
15180Sstevel@tonic-gate  * pam_getenv - retrieve an environment variable from the PAM handle
15190Sstevel@tonic-gate  */
15200Sstevel@tonic-gate char *
15210Sstevel@tonic-gate pam_getenv(pam_handle_t *pamh, const char *name)
15220Sstevel@tonic-gate {
15230Sstevel@tonic-gate 	int		error = PAM_SYSTEM_ERR;
15240Sstevel@tonic-gate 	env_list	*traverse;
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 	pam_trace(PAM_DEBUG_DEFAULT,
15270Sstevel@tonic-gate 	    "pam_getenv(%p, %p)", (void *)pamh, (void *)name);
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate 	if (pamh == NULL || name == NULL)
15300Sstevel@tonic-gate 		goto out;
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate 	/* check to see if we already have this variable in the PAM handle */
15330Sstevel@tonic-gate 	traverse = pamh->pam_env;
15340Sstevel@tonic-gate 	while (traverse && strncmp(traverse->name, name, strlen(name))) {
15350Sstevel@tonic-gate 		traverse = traverse->next;
15360Sstevel@tonic-gate 	}
15370Sstevel@tonic-gate 	error = (traverse ? PAM_SUCCESS : PAM_SYSTEM_ERR);
15380Sstevel@tonic-gate 	pam_trace(PAM_DEBUG_DEFAULT,
15390Sstevel@tonic-gate 	    "pam_getenv(%p, %s)=%s", (void *)pamh, name,
15400Sstevel@tonic-gate 	    traverse ? traverse->value : "NULL");
15410Sstevel@tonic-gate out:
15420Sstevel@tonic-gate 	return (error ? NULL : strdup(traverse->value));
15430Sstevel@tonic-gate }
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate /*
15460Sstevel@tonic-gate  * pam_getenvlist - retrieve all environment variables from the PAM handle
15473358Sjjj  *                  in a NULL terminated array. On error, return NULL.
15480Sstevel@tonic-gate  */
15490Sstevel@tonic-gate char **
15500Sstevel@tonic-gate pam_getenvlist(pam_handle_t *pamh)
15510Sstevel@tonic-gate {
15520Sstevel@tonic-gate 	int		error = PAM_SYSTEM_ERR;
15530Sstevel@tonic-gate 	char		**list = 0;
15540Sstevel@tonic-gate 	int		length = 0;
15550Sstevel@tonic-gate 	env_list	*traverse;
15563358Sjjj 	char		*tenv;
15573358Sjjj 	size_t		tenv_size;
15580Sstevel@tonic-gate 
15590Sstevel@tonic-gate 	pam_trace(PAM_DEBUG_DEFAULT,
15600Sstevel@tonic-gate 	    "pam_getenvlist(%p)", (void *)pamh);
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 	if (pamh == NULL)
15630Sstevel@tonic-gate 		goto out;
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate 	/* find out how many environment variables we have */
15660Sstevel@tonic-gate 	traverse = pamh->pam_env;
15670Sstevel@tonic-gate 	while (traverse) {
15680Sstevel@tonic-gate 		length++;
15690Sstevel@tonic-gate 		traverse = traverse->next;
15700Sstevel@tonic-gate 	}
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate 	/* allocate the array we will return to the caller */
15733358Sjjj 	if ((list = (char **)calloc(length + 1, sizeof (char *))) == NULL) {
15740Sstevel@tonic-gate 		error = PAM_BUF_ERR;
15750Sstevel@tonic-gate 		goto out;
15760Sstevel@tonic-gate 	}
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 	/* add the variables one by one */
15790Sstevel@tonic-gate 	length = 0;
15800Sstevel@tonic-gate 	traverse = pamh->pam_env;
15813358Sjjj 	while (traverse != NULL) {
15823358Sjjj 		tenv_size = strlen(traverse->name) +
15833358Sjjj 		    strlen(traverse->value) + 2; /* name=val\0 */
15843358Sjjj 		if ((tenv = malloc(tenv_size)) == NULL) {
15850Sstevel@tonic-gate 			error = PAM_BUF_ERR;
15860Sstevel@tonic-gate 			goto out;
15870Sstevel@tonic-gate 		}
15883358Sjjj 		/*LINTED*/
15893358Sjjj 		(void) sprintf(tenv, "%s=%s", traverse->name, traverse->value);
15903358Sjjj 		list[length++] = tenv;
15910Sstevel@tonic-gate 		traverse = traverse->next;
15920Sstevel@tonic-gate 	}
15933358Sjjj 	list[length] = NULL;
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate 	error = PAM_SUCCESS;
15960Sstevel@tonic-gate out:
15970Sstevel@tonic-gate 	if (error != PAM_SUCCESS) {
15980Sstevel@tonic-gate 		/* free the partially constructed list */
15990Sstevel@tonic-gate 		if (list) {
16000Sstevel@tonic-gate 			length = 0;
16010Sstevel@tonic-gate 			while (list[length] != NULL) {
16020Sstevel@tonic-gate 				free(list[length]);
16030Sstevel@tonic-gate 				length++;
16040Sstevel@tonic-gate 			}
16050Sstevel@tonic-gate 			free(list);
16060Sstevel@tonic-gate 		}
16070Sstevel@tonic-gate 	}
16080Sstevel@tonic-gate 	return (error ? NULL : list);
16090Sstevel@tonic-gate }
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate /*
16120Sstevel@tonic-gate  * Routines to load a requested module on demand
16130Sstevel@tonic-gate  */
16140Sstevel@tonic-gate 
16150Sstevel@tonic-gate /*
16160Sstevel@tonic-gate  * load_modules - load the requested module.
16170Sstevel@tonic-gate  *		  if the dlopen or dlsym fail, then
16180Sstevel@tonic-gate  *		  the module is ignored.
16190Sstevel@tonic-gate  */
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate static int
16220Sstevel@tonic-gate load_modules(pam_handle_t *pamh, int type, char *function_name,
16230Sstevel@tonic-gate     pamtab_t *pam_entry)
16240Sstevel@tonic-gate {
16250Sstevel@tonic-gate 	void	*mh;
16260Sstevel@tonic-gate 	struct	auth_module *authp;
16270Sstevel@tonic-gate 	struct	account_module *accountp;
16280Sstevel@tonic-gate 	struct	session_module *sessionp;
16290Sstevel@tonic-gate 	struct	password_module *passwdp;
16300Sstevel@tonic-gate 	int	loading_functions = 0; /* are we currently loading functions? */
16310Sstevel@tonic-gate 
16320Sstevel@tonic-gate 	pam_trace(PAM_DEBUG_MODULE, "load_modules[%d:%s](%p, %s)=%s:%s",
16330Sstevel@tonic-gate 		pamh->include_depth, pam_trace_cname(pamh), (void *)pamh,
16340Sstevel@tonic-gate 		function_name, pam_trace_fname(pam_entry->pam_flag),
16350Sstevel@tonic-gate 		pam_entry->module_path);
16360Sstevel@tonic-gate 
16370Sstevel@tonic-gate 	while (pam_entry != NULL) {
16380Sstevel@tonic-gate 		pam_trace(PAM_DEBUG_DEFAULT,
16390Sstevel@tonic-gate 		    "while load_modules[%d:%s](%p, %s)=%s",
16400Sstevel@tonic-gate 		    pamh->include_depth, pam_trace_cname(pamh), (void *)pamh,
16410Sstevel@tonic-gate 		    function_name, pam_entry->module_path);
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate 		if (pam_entry->pam_flag & PAM_INCLUDE) {
16440Sstevel@tonic-gate 			pam_trace(PAM_DEBUG_DEFAULT,
16450Sstevel@tonic-gate 			    "done load_modules[%d:%s](%p, %s)=%s",
16460Sstevel@tonic-gate 			    pamh->include_depth, pam_trace_cname(pamh),
16470Sstevel@tonic-gate 			    (void *)pamh, function_name,
16480Sstevel@tonic-gate 			    pam_entry->module_path);
16490Sstevel@tonic-gate 			return (PAM_SUCCESS);
16500Sstevel@tonic-gate 		}
16510Sstevel@tonic-gate 		switch (type) {
16520Sstevel@tonic-gate 		case PAM_AUTH_MODULE:
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 			/* if the function has already been loaded, return */
16550Sstevel@tonic-gate 			authp = pam_entry->function_ptr;
16560Sstevel@tonic-gate 			if (!loading_functions &&
16570Sstevel@tonic-gate 				(((strcmp(function_name, PAM_SM_AUTHENTICATE)
16580Sstevel@tonic-gate 				== 0) &&
16590Sstevel@tonic-gate 				authp && authp->pam_sm_authenticate) ||
16600Sstevel@tonic-gate 				((strcmp(function_name, PAM_SM_SETCRED) == 0) &&
16610Sstevel@tonic-gate 				authp && authp->pam_sm_setcred))) {
16620Sstevel@tonic-gate 				return (PAM_SUCCESS);
16630Sstevel@tonic-gate 			}
16640Sstevel@tonic-gate 
16650Sstevel@tonic-gate 			/* function has not been loaded yet */
16660Sstevel@tonic-gate 			loading_functions = 1;
16670Sstevel@tonic-gate 			if (authp == NULL) {
16680Sstevel@tonic-gate 				authp = (struct auth_module *)calloc(1,
16690Sstevel@tonic-gate 				    sizeof (struct auth_module));
16700Sstevel@tonic-gate 				if (authp == NULL)
16710Sstevel@tonic-gate 					return (PAM_BUF_ERR);
16720Sstevel@tonic-gate 			}
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate 			/* if open_module fails, return error */
16750Sstevel@tonic-gate 			if ((mh = open_module(pamh,
16760Sstevel@tonic-gate 			    pam_entry->module_path)) == NULL) {
16770Sstevel@tonic-gate 				__pam_log(LOG_AUTH | LOG_ERR,
16780Sstevel@tonic-gate 				    "load_modules[%d:%s]: can not open module "
16790Sstevel@tonic-gate 				    "%s", pamh->include_depth,
16800Sstevel@tonic-gate 				    pam_trace_cname(pamh),
16810Sstevel@tonic-gate 				    pam_entry->module_path);
16820Sstevel@tonic-gate 				free(authp);
16830Sstevel@tonic-gate 				return (PAM_OPEN_ERR);
16840Sstevel@tonic-gate 			}
16850Sstevel@tonic-gate 
16860Sstevel@tonic-gate 			/* load the authentication function */
16870Sstevel@tonic-gate 			if (strcmp(function_name, PAM_SM_AUTHENTICATE) == 0) {
16880Sstevel@tonic-gate 				if (load_function(mh, PAM_SM_AUTHENTICATE,
16890Sstevel@tonic-gate 				    &authp->pam_sm_authenticate)
16900Sstevel@tonic-gate 				    != PAM_SUCCESS) {
16910Sstevel@tonic-gate 					/* return error if dlsym fails */
16920Sstevel@tonic-gate 					free(authp);
16930Sstevel@tonic-gate 					return (PAM_SYMBOL_ERR);
16940Sstevel@tonic-gate 				}
16950Sstevel@tonic-gate 
16960Sstevel@tonic-gate 			/* load the setcred function */
16970Sstevel@tonic-gate 			} else if (strcmp(function_name, PAM_SM_SETCRED) == 0) {
16980Sstevel@tonic-gate 				if (load_function(mh, PAM_SM_SETCRED,
16990Sstevel@tonic-gate 				    &authp->pam_sm_setcred) != PAM_SUCCESS) {
17000Sstevel@tonic-gate 					/* return error if dlsym fails */
17010Sstevel@tonic-gate 					free(authp);
17020Sstevel@tonic-gate 					return (PAM_SYMBOL_ERR);
17030Sstevel@tonic-gate 				}
17040Sstevel@tonic-gate 			}
17050Sstevel@tonic-gate 			pam_entry->function_ptr = authp;
17060Sstevel@tonic-gate 			break;
17070Sstevel@tonic-gate 		case PAM_ACCOUNT_MODULE:
17080Sstevel@tonic-gate 			accountp = pam_entry->function_ptr;
17090Sstevel@tonic-gate 			if (!loading_functions &&
17100Sstevel@tonic-gate 			    (strcmp(function_name, PAM_SM_ACCT_MGMT) == 0) &&
17110Sstevel@tonic-gate 			    accountp && accountp->pam_sm_acct_mgmt) {
17120Sstevel@tonic-gate 				return (PAM_SUCCESS);
17130Sstevel@tonic-gate 			}
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate 			/*
17160Sstevel@tonic-gate 			 * If functions are added to the account module,
17170Sstevel@tonic-gate 			 * verify that one of the other functions hasn't
17180Sstevel@tonic-gate 			 * already loaded it.  See PAM_AUTH_MODULE code.
17190Sstevel@tonic-gate 			 */
17200Sstevel@tonic-gate 			loading_functions = 1;
17210Sstevel@tonic-gate 			accountp = (struct account_module *)calloc(1,
17220Sstevel@tonic-gate 			    sizeof (struct account_module));
17230Sstevel@tonic-gate 			if (accountp == NULL)
17240Sstevel@tonic-gate 				return (PAM_BUF_ERR);
17250Sstevel@tonic-gate 
17260Sstevel@tonic-gate 			/* if open_module fails, return error */
17270Sstevel@tonic-gate 			if ((mh = open_module(pamh,
17280Sstevel@tonic-gate 			    pam_entry->module_path)) == NULL) {
17290Sstevel@tonic-gate 				__pam_log(LOG_AUTH | LOG_ERR,
17300Sstevel@tonic-gate 				    "load_modules[%d:%s]: can not open module "
17310Sstevel@tonic-gate 				    "%s", pamh->include_depth,
17320Sstevel@tonic-gate 				    pam_trace_cname(pamh),
17330Sstevel@tonic-gate 				    pam_entry->module_path);
17340Sstevel@tonic-gate 				free(accountp);
17350Sstevel@tonic-gate 				return (PAM_OPEN_ERR);
17360Sstevel@tonic-gate 			}
17370Sstevel@tonic-gate 
17380Sstevel@tonic-gate 			if (load_function(mh, PAM_SM_ACCT_MGMT,
17390Sstevel@tonic-gate 			    &accountp->pam_sm_acct_mgmt) != PAM_SUCCESS) {
17400Sstevel@tonic-gate 				__pam_log(LOG_AUTH | LOG_ERR,
17410Sstevel@tonic-gate 				    "load_modules[%d:%s]: pam_sm_acct_mgmt() "
17420Sstevel@tonic-gate 				    "missing", pamh->include_depth,
17430Sstevel@tonic-gate 				    pam_trace_cname(pamh));
17440Sstevel@tonic-gate 				free(accountp);
17450Sstevel@tonic-gate 				return (PAM_SYMBOL_ERR);
17460Sstevel@tonic-gate 			}
17470Sstevel@tonic-gate 			pam_entry->function_ptr = accountp;
17480Sstevel@tonic-gate 			break;
17490Sstevel@tonic-gate 		case PAM_SESSION_MODULE:
17500Sstevel@tonic-gate 			sessionp = pam_entry->function_ptr;
17510Sstevel@tonic-gate 			if (!loading_functions &&
17520Sstevel@tonic-gate 			    (((strcmp(function_name,
17530Sstevel@tonic-gate 			    PAM_SM_OPEN_SESSION) == 0) &&
17540Sstevel@tonic-gate 			    sessionp && sessionp->pam_sm_open_session) ||
17550Sstevel@tonic-gate 			    ((strcmp(function_name,
17560Sstevel@tonic-gate 			    PAM_SM_CLOSE_SESSION) == 0) &&
17570Sstevel@tonic-gate 			    sessionp && sessionp->pam_sm_close_session))) {
17580Sstevel@tonic-gate 				return (PAM_SUCCESS);
17590Sstevel@tonic-gate 			}
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate 			loading_functions = 1;
17620Sstevel@tonic-gate 			if (sessionp == NULL) {
17630Sstevel@tonic-gate 				sessionp = (struct session_module *)
17640Sstevel@tonic-gate 				    calloc(1, sizeof (struct session_module));
17650Sstevel@tonic-gate 				if (sessionp == NULL)
17660Sstevel@tonic-gate 					return (PAM_BUF_ERR);
17670Sstevel@tonic-gate 			}
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate 			/* if open_module fails, return error */
17700Sstevel@tonic-gate 			if ((mh = open_module(pamh,
17710Sstevel@tonic-gate 			    pam_entry->module_path)) == NULL) {
17720Sstevel@tonic-gate 				__pam_log(LOG_AUTH | LOG_ERR,
17730Sstevel@tonic-gate 				    "load_modules[%d:%s]: can not open module "
17740Sstevel@tonic-gate 				    "%s", pamh->include_depth,
17750Sstevel@tonic-gate 				    pam_trace_cname(pamh),
17760Sstevel@tonic-gate 				    pam_entry->module_path);
17770Sstevel@tonic-gate 				free(sessionp);
17780Sstevel@tonic-gate 				return (PAM_OPEN_ERR);
17790Sstevel@tonic-gate 			}
17800Sstevel@tonic-gate 
17810Sstevel@tonic-gate 			if ((strcmp(function_name, PAM_SM_OPEN_SESSION) == 0) &&
17820Sstevel@tonic-gate 			    load_function(mh, PAM_SM_OPEN_SESSION,
17830Sstevel@tonic-gate 				&sessionp->pam_sm_open_session)
17840Sstevel@tonic-gate 				!= PAM_SUCCESS) {
17850Sstevel@tonic-gate 				free(sessionp);
17860Sstevel@tonic-gate 				return (PAM_SYMBOL_ERR);
17870Sstevel@tonic-gate 			} else if ((strcmp(function_name,
17880Sstevel@tonic-gate 					PAM_SM_CLOSE_SESSION) == 0) &&
17890Sstevel@tonic-gate 				    load_function(mh, PAM_SM_CLOSE_SESSION,
17900Sstevel@tonic-gate 					&sessionp->pam_sm_close_session)
17910Sstevel@tonic-gate 					!= PAM_SUCCESS) {
17920Sstevel@tonic-gate 				free(sessionp);
17930Sstevel@tonic-gate 				return (PAM_SYMBOL_ERR);
17940Sstevel@tonic-gate 			}
17950Sstevel@tonic-gate 			pam_entry->function_ptr = sessionp;
17960Sstevel@tonic-gate 			break;
17970Sstevel@tonic-gate 		case PAM_PASSWORD_MODULE:
17980Sstevel@tonic-gate 			passwdp = pam_entry->function_ptr;
17990Sstevel@tonic-gate 			if (!loading_functions &&
18000Sstevel@tonic-gate 			    (strcmp(function_name, PAM_SM_CHAUTHTOK) == 0) &&
18010Sstevel@tonic-gate 			    passwdp && passwdp->pam_sm_chauthtok) {
18020Sstevel@tonic-gate 				return (PAM_SUCCESS);
18030Sstevel@tonic-gate 			}
18040Sstevel@tonic-gate 
18050Sstevel@tonic-gate 			/*
18060Sstevel@tonic-gate 			 * If functions are added to the password module,
18070Sstevel@tonic-gate 			 * verify that one of the other functions hasn't
18080Sstevel@tonic-gate 			 * already loaded it.  See PAM_AUTH_MODULE code.
18090Sstevel@tonic-gate 			 */
18100Sstevel@tonic-gate 			loading_functions = 1;
18110Sstevel@tonic-gate 			passwdp = (struct password_module *)
18120Sstevel@tonic-gate 				calloc(1, sizeof (struct password_module));
18130Sstevel@tonic-gate 			if (passwdp == NULL)
18140Sstevel@tonic-gate 				return (PAM_BUF_ERR);
18150Sstevel@tonic-gate 
18160Sstevel@tonic-gate 			/* if open_module fails, continue */
18170Sstevel@tonic-gate 			if ((mh = open_module(pamh,
18180Sstevel@tonic-gate 			    pam_entry->module_path)) == NULL) {
18190Sstevel@tonic-gate 				__pam_log(LOG_AUTH | LOG_ERR,
18200Sstevel@tonic-gate 				    "load_modules[%d:%s]: can not open module "
18210Sstevel@tonic-gate 				    "%s", pamh->include_depth,
18220Sstevel@tonic-gate 				    pam_trace_cname(pamh),
18230Sstevel@tonic-gate 				    pam_entry->module_path);
18240Sstevel@tonic-gate 				free(passwdp);
18250Sstevel@tonic-gate 				return (PAM_OPEN_ERR);
18260Sstevel@tonic-gate 			}
18270Sstevel@tonic-gate 
18280Sstevel@tonic-gate 			if (load_function(mh, PAM_SM_CHAUTHTOK,
18290Sstevel@tonic-gate 			    &passwdp->pam_sm_chauthtok) != PAM_SUCCESS) {
18300Sstevel@tonic-gate 				free(passwdp);
18310Sstevel@tonic-gate 				return (PAM_SYMBOL_ERR);
18320Sstevel@tonic-gate 			}
18330Sstevel@tonic-gate 			pam_entry->function_ptr = passwdp;
18340Sstevel@tonic-gate 			break;
18350Sstevel@tonic-gate 		default:
18360Sstevel@tonic-gate 			pam_trace(PAM_DEBUG_DEFAULT,
18370Sstevel@tonic-gate 			    "load_modules[%d:%s](%p, %s): unsupported type %d",
18380Sstevel@tonic-gate 			    pamh->include_depth, pam_trace_cname(pamh),
18390Sstevel@tonic-gate 			    (void *)pamh, function_name, type);
18400Sstevel@tonic-gate 			break;
18410Sstevel@tonic-gate 		}
18420Sstevel@tonic-gate 
18430Sstevel@tonic-gate 		pam_entry = pam_entry->next;
18440Sstevel@tonic-gate 	} /* while */
18450Sstevel@tonic-gate 
18460Sstevel@tonic-gate 	pam_trace(PAM_DEBUG_MODULE, "load_modules[%d:%s](%p, %s)=done",
18470Sstevel@tonic-gate 	    pamh->include_depth, pam_trace_cname(pamh), (void *)pamh,
18480Sstevel@tonic-gate 	    function_name);
18490Sstevel@tonic-gate 
18500Sstevel@tonic-gate 	return (PAM_SUCCESS);
18510Sstevel@tonic-gate }
18520Sstevel@tonic-gate 
18530Sstevel@tonic-gate /*
18540Sstevel@tonic-gate  * open_module		- Open the module first checking for
18550Sstevel@tonic-gate  *			  propers modes and ownerships on the file.
18560Sstevel@tonic-gate  */
18570Sstevel@tonic-gate 
18580Sstevel@tonic-gate static void *
18590Sstevel@tonic-gate open_module(pam_handle_t *pamh, char *module_so)
18600Sstevel@tonic-gate {
18610Sstevel@tonic-gate 	struct stat64	stb;
18620Sstevel@tonic-gate 	char		*errmsg;
18630Sstevel@tonic-gate 	void		*lfd;
18640Sstevel@tonic-gate 	fd_list		*module_fds = 0;
18650Sstevel@tonic-gate 	fd_list		*trail = 0;
18660Sstevel@tonic-gate 	fd_list		*traverse = 0;
18670Sstevel@tonic-gate 
18680Sstevel@tonic-gate 	/* Check the ownership and file modes */
18690Sstevel@tonic-gate 	if (stat64(module_so, &stb) < 0) {
18700Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ERR,
18710Sstevel@tonic-gate 		    "open_module[%d:%s]: stat(%s) failed: %s",
18720Sstevel@tonic-gate 		    pamh->include_depth, pam_trace_cname(pamh), module_so,
18730Sstevel@tonic-gate 		    strerror(errno));
18740Sstevel@tonic-gate 		return (NULL);
18750Sstevel@tonic-gate 	}
18760Sstevel@tonic-gate 	if (stb.st_uid != (uid_t)0) {
18770Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ALERT,
18780Sstevel@tonic-gate 		    "open_module[%d:%s]: Owner of the module %s is not root",
18790Sstevel@tonic-gate 		    pamh->include_depth, pam_trace_cname(pamh), module_so);
18800Sstevel@tonic-gate 		return (NULL);
18810Sstevel@tonic-gate 	}
18820Sstevel@tonic-gate 	if (stb.st_mode & S_IWGRP) {
18830Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ALERT,
18840Sstevel@tonic-gate 		    "open_module[%d:%s]: module %s writable by group",
18850Sstevel@tonic-gate 		    pamh->include_depth, pam_trace_cname(pamh), module_so);
18860Sstevel@tonic-gate 		return (NULL);
18870Sstevel@tonic-gate 	}
18880Sstevel@tonic-gate 	if (stb.st_mode & S_IWOTH) {
18890Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ALERT,
18900Sstevel@tonic-gate 		    "open_module[%d:%s]: module %s writable by world",
18910Sstevel@tonic-gate 		    pamh->include_depth, pam_trace_cname(pamh), module_so);
18920Sstevel@tonic-gate 		return (NULL);
18930Sstevel@tonic-gate 	}
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 	/*
18960Sstevel@tonic-gate 	 * Perform the dlopen()
18970Sstevel@tonic-gate 	 */
18980Sstevel@tonic-gate 	lfd = (void *)dlopen(module_so, RTLD_LAZY);
18990Sstevel@tonic-gate 
19000Sstevel@tonic-gate 	if (lfd == NULL) {
19010Sstevel@tonic-gate 		errmsg = dlerror();
19020Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ERR, "open_module[%d:%s]: %s "
19030Sstevel@tonic-gate 		    "failed: %s", pamh->include_depth, pam_trace_cname(pamh),
19040Sstevel@tonic-gate 		    module_so, errmsg != NULL ? errmsg : "Unknown error");
19050Sstevel@tonic-gate 		return (NULL);
19060Sstevel@tonic-gate 	} else {
19070Sstevel@tonic-gate 		/* add this fd to the pam handle */
19080Sstevel@tonic-gate 		if ((module_fds = (fd_list *)calloc(1, sizeof (fd_list)))
19090Sstevel@tonic-gate 		    == 0) {
19100Sstevel@tonic-gate 			(void) dlclose(lfd);
19110Sstevel@tonic-gate 			lfd = 0;
19120Sstevel@tonic-gate 			return (NULL);
19130Sstevel@tonic-gate 		}
19140Sstevel@tonic-gate 		module_fds->mh = lfd;
19150Sstevel@tonic-gate 
19160Sstevel@tonic-gate 		if (pamh->fd == 0) {
19170Sstevel@tonic-gate 			/* adding new head of list */
19180Sstevel@tonic-gate 			pamh->fd = module_fds;
19190Sstevel@tonic-gate 		} else {
19200Sstevel@tonic-gate 			/* appending to end of list */
19210Sstevel@tonic-gate 			traverse = pamh->fd;
19220Sstevel@tonic-gate 			while (traverse) {
19230Sstevel@tonic-gate 				trail = traverse;
19240Sstevel@tonic-gate 				traverse = traverse->next;
19250Sstevel@tonic-gate 			}
19260Sstevel@tonic-gate 			trail->next = module_fds;
19270Sstevel@tonic-gate 		}
19280Sstevel@tonic-gate 	}
19290Sstevel@tonic-gate 
19300Sstevel@tonic-gate 	return (lfd);
19310Sstevel@tonic-gate }
19320Sstevel@tonic-gate 
19330Sstevel@tonic-gate /*
19340Sstevel@tonic-gate  * load_function - call dlsym() to resolve the function address
19350Sstevel@tonic-gate  */
19360Sstevel@tonic-gate static int
19370Sstevel@tonic-gate load_function(void *lfd, char *name, int (**func)())
19380Sstevel@tonic-gate {
19390Sstevel@tonic-gate 	char *errmsg = NULL;
19400Sstevel@tonic-gate 
19410Sstevel@tonic-gate 	if (lfd == NULL)
19420Sstevel@tonic-gate 		return (PAM_SYMBOL_ERR);
19430Sstevel@tonic-gate 
19440Sstevel@tonic-gate 	*func = (int (*)())dlsym(lfd, name);
19450Sstevel@tonic-gate 	if (*func == NULL) {
19460Sstevel@tonic-gate 		errmsg = dlerror();
19470Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ERR, "dlsym failed %s: error %s",
19480Sstevel@tonic-gate 		    name, errmsg != NULL ? errmsg : "Unknown error");
19490Sstevel@tonic-gate 		return (PAM_SYMBOL_ERR);
19500Sstevel@tonic-gate 	}
19510Sstevel@tonic-gate 
19520Sstevel@tonic-gate 	pam_trace(PAM_DEBUG_DEFAULT,
19530Sstevel@tonic-gate 	    "load_function: successful load of %s", name);
19540Sstevel@tonic-gate 	return (PAM_SUCCESS);
19550Sstevel@tonic-gate }
19560Sstevel@tonic-gate 
19570Sstevel@tonic-gate /*
19580Sstevel@tonic-gate  * Routines to read the pam.conf configuration file
19590Sstevel@tonic-gate  */
19600Sstevel@tonic-gate 
19610Sstevel@tonic-gate /*
19620Sstevel@tonic-gate  * open_pam_conf - open the pam.conf config file
19630Sstevel@tonic-gate  */
19640Sstevel@tonic-gate 
19650Sstevel@tonic-gate static int
19660Sstevel@tonic-gate open_pam_conf(struct pam_fh **pam_fh, pam_handle_t *pamh, char *config)
19670Sstevel@tonic-gate {
19680Sstevel@tonic-gate 	struct stat64	stb;
19690Sstevel@tonic-gate 	int		fd;
19700Sstevel@tonic-gate 
19710Sstevel@tonic-gate 	if ((fd = open(config, O_RDONLY)) == -1) {
19720Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ALERT,
19730Sstevel@tonic-gate 		    "open_pam_conf[%d:%s]: open(%s) failed: %s",
19740Sstevel@tonic-gate 		    pamh->include_depth, pam_trace_cname(pamh), config,
19750Sstevel@tonic-gate 		    strerror(errno));
19760Sstevel@tonic-gate 		return (0);
19770Sstevel@tonic-gate 	}
19780Sstevel@tonic-gate 	/* Check the ownership and file modes */
19790Sstevel@tonic-gate 	if (fstat64(fd, &stb) < 0) {
19800Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ALERT,
19810Sstevel@tonic-gate 		    "open_pam_conf[%d:%s]: stat(%s) failed: %s",
19820Sstevel@tonic-gate 		    pamh->include_depth, pam_trace_cname(pamh), config,
19830Sstevel@tonic-gate 		    strerror(errno));
19840Sstevel@tonic-gate 		(void) close(fd);
19850Sstevel@tonic-gate 		return (0);
19860Sstevel@tonic-gate 	}
19870Sstevel@tonic-gate 	if (stb.st_uid != (uid_t)0) {
19880Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ALERT,
19890Sstevel@tonic-gate 		    "open_pam_conf[%d:%s]: Owner of %s is not root",
19900Sstevel@tonic-gate 		    pamh->include_depth, pam_trace_cname(pamh), config);
19910Sstevel@tonic-gate 		(void) close(fd);
19920Sstevel@tonic-gate 		return (0);
19930Sstevel@tonic-gate 	}
19940Sstevel@tonic-gate 	if (stb.st_mode & S_IWGRP) {
19950Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ALERT,
19960Sstevel@tonic-gate 		    "open_pam_conf[%d:%s]: %s writable by group",
19970Sstevel@tonic-gate 		    pamh->include_depth, pam_trace_cname(pamh), config);
19980Sstevel@tonic-gate 		(void) close(fd);
19990Sstevel@tonic-gate 		return (0);
20000Sstevel@tonic-gate 	}
20010Sstevel@tonic-gate 	if (stb.st_mode & S_IWOTH) {
20020Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ALERT,
20030Sstevel@tonic-gate 		    "open_pam_conf[%d:%s]: %s writable by world",
20040Sstevel@tonic-gate 		    pamh->include_depth, pam_trace_cname(pamh), config);
20050Sstevel@tonic-gate 		(void) close(fd);
20060Sstevel@tonic-gate 		return (0);
20070Sstevel@tonic-gate 	}
20080Sstevel@tonic-gate 	if ((*pam_fh = calloc(1, sizeof (struct pam_fh))) == NULL) {
20090Sstevel@tonic-gate 		(void) close(fd);
20100Sstevel@tonic-gate 		return (0);
20110Sstevel@tonic-gate 	}
20120Sstevel@tonic-gate 	(*pam_fh)->fconfig = fd;
20130Sstevel@tonic-gate 	(*pam_fh)->bufsize = (size_t)stb.st_size;
20140Sstevel@tonic-gate 	if (((*pam_fh)->data = mmap(0, (*pam_fh)->bufsize, PROT_READ,
20150Sstevel@tonic-gate 	    MAP_PRIVATE, (*pam_fh)->fconfig, 0)) == MAP_FAILED) {
20160Sstevel@tonic-gate 		(void) close(fd);
20170Sstevel@tonic-gate 		free (*pam_fh);
20180Sstevel@tonic-gate 		return (0);
20190Sstevel@tonic-gate 	}
20200Sstevel@tonic-gate 	(*pam_fh)->bufferp = (*pam_fh)->data;
20210Sstevel@tonic-gate 
20220Sstevel@tonic-gate 	return (1);
20230Sstevel@tonic-gate }
20240Sstevel@tonic-gate 
20250Sstevel@tonic-gate /*
20260Sstevel@tonic-gate  * close_pam_conf - close pam.conf
20270Sstevel@tonic-gate  */
20280Sstevel@tonic-gate 
20290Sstevel@tonic-gate static void
20300Sstevel@tonic-gate close_pam_conf(struct pam_fh *pam_fh)
20310Sstevel@tonic-gate {
20320Sstevel@tonic-gate 	(void) munmap(pam_fh->data, pam_fh->bufsize);
20330Sstevel@tonic-gate 	(void) close(pam_fh->fconfig);
20340Sstevel@tonic-gate 	free(pam_fh);
20350Sstevel@tonic-gate }
20360Sstevel@tonic-gate 
20370Sstevel@tonic-gate /*
20380Sstevel@tonic-gate  * read_pam_conf - read in each entry in pam.conf and store info
20390Sstevel@tonic-gate  *		   under the pam handle.
20400Sstevel@tonic-gate  */
20410Sstevel@tonic-gate 
20420Sstevel@tonic-gate static int
20430Sstevel@tonic-gate read_pam_conf(pam_handle_t *pamh, char *config)
20440Sstevel@tonic-gate {
20450Sstevel@tonic-gate 	struct pam_fh	*pam_fh;
20460Sstevel@tonic-gate 	pamtab_t	*pamentp;
20470Sstevel@tonic-gate 	pamtab_t	*tpament;
20480Sstevel@tonic-gate 	char		*service;
20490Sstevel@tonic-gate 	int		error;
20500Sstevel@tonic-gate 	int		i = pamh->include_depth;	/* include depth */
20510Sstevel@tonic-gate 	/*
20520Sstevel@tonic-gate 	 * service types:
20530Sstevel@tonic-gate 	 * error (-1), "auth" (0), "account" (1), "session" (2), "password" (3)
20540Sstevel@tonic-gate 	 */
20550Sstevel@tonic-gate 	int service_found[PAM_NUM_MODULE_TYPES+1] = {0, 0, 0, 0, 0};
20560Sstevel@tonic-gate 
20570Sstevel@tonic-gate 	(void) pam_get_item(pamh, PAM_SERVICE, (void **)&service);
20580Sstevel@tonic-gate 	if (service == NULL || *service == '\0') {
20590Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ERR, "No service name");
20600Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
20610Sstevel@tonic-gate 	}
20620Sstevel@tonic-gate 
20630Sstevel@tonic-gate 	pamh->pam_conf_name[i] = strdup(config);
20640Sstevel@tonic-gate 	pam_trace(PAM_DEBUG_CONF, "read_pam_conf[%d:%s](%p) open(%s)",
20650Sstevel@tonic-gate 	    i, pam_trace_cname(pamh), (void *)pamh, config);
20662295Sgww 	if (open_pam_conf(&pam_fh, pamh, config) == 0) {
20670Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
20682295Sgww 	}
20690Sstevel@tonic-gate 
20700Sstevel@tonic-gate 	while ((error =
20710Sstevel@tonic-gate 	    get_pam_conf_entry(pam_fh, pamh, &pamentp)) == PAM_SUCCESS &&
20720Sstevel@tonic-gate 	    pamentp) {
20730Sstevel@tonic-gate 
20740Sstevel@tonic-gate 		/* See if entry is this service and valid */
20750Sstevel@tonic-gate 		if (verify_pam_conf(pamentp, service)) {
20760Sstevel@tonic-gate 			pam_trace(PAM_DEBUG_CONF,
20770Sstevel@tonic-gate 			    "read_pam_conf[%d:%s](%p): bad entry error %s",
20780Sstevel@tonic-gate 			    i, pam_trace_cname(pamh), (void *)pamh, service);
20790Sstevel@tonic-gate 
20800Sstevel@tonic-gate 			error = PAM_SYSTEM_ERR;
20810Sstevel@tonic-gate 			free_pamconf(pamentp);
20820Sstevel@tonic-gate 			goto out;
20830Sstevel@tonic-gate 		}
20840Sstevel@tonic-gate 		if (strcasecmp(pamentp->pam_service, service) == 0) {
20850Sstevel@tonic-gate 			pam_trace(PAM_DEBUG_CONF,
20860Sstevel@tonic-gate 			    "read_pam_conf[%d:%s](%p): processing %s",
20870Sstevel@tonic-gate 			    i, pam_trace_cname(pamh), (void *)pamh, service);
20880Sstevel@tonic-gate 			/* process first service entry */
20890Sstevel@tonic-gate 			if (service_found[pamentp->pam_type + 1] == 0) {
20900Sstevel@tonic-gate 				/* purge "other" entries */
20910Sstevel@tonic-gate 				while ((tpament = pamh->pam_conf_info[i]
20920Sstevel@tonic-gate 				    [pamentp->pam_type]) != NULL) {
20930Sstevel@tonic-gate 					pam_trace(PAM_DEBUG_CONF,
20940Sstevel@tonic-gate 					    "read_pam_conf(%p): purging "
20950Sstevel@tonic-gate 					    "\"other\"[%d:%s][%s]",
20960Sstevel@tonic-gate 					    (void *)pamh, i,
20970Sstevel@tonic-gate 					    pam_trace_cname(pamh),
20980Sstevel@tonic-gate 					    pam_snames[pamentp->pam_type]);
20990Sstevel@tonic-gate 					pamh->pam_conf_info[i]
21000Sstevel@tonic-gate 					    [pamentp->pam_type] = tpament->next;
21010Sstevel@tonic-gate 					free_pamconf(tpament);
21020Sstevel@tonic-gate 				}
21030Sstevel@tonic-gate 				/* add first service entry */
21040Sstevel@tonic-gate 				pam_trace(PAM_DEBUG_CONF,
21050Sstevel@tonic-gate 				    "read_pam_conf(%p): adding 1st "
21060Sstevel@tonic-gate 				    "%s[%d:%s][%s]",
21070Sstevel@tonic-gate 				    (void *)pamh, service, i,
21080Sstevel@tonic-gate 				    pam_trace_cname(pamh),
21090Sstevel@tonic-gate 				    pam_snames[pamentp->pam_type]);
21100Sstevel@tonic-gate 				pamh->pam_conf_info[i][pamentp->pam_type] =
21110Sstevel@tonic-gate 				    pamentp;
21120Sstevel@tonic-gate 				service_found[pamentp->pam_type + 1] = 1;
21130Sstevel@tonic-gate 			} else {
21140Sstevel@tonic-gate 				/* append more service entries */
21150Sstevel@tonic-gate 				pam_trace(PAM_DEBUG_CONF,
21160Sstevel@tonic-gate 				    "read_pam_conf(%p): adding more "
21170Sstevel@tonic-gate 				    "%s[%d:%s][%s]",
21180Sstevel@tonic-gate 				    (void *)pamh, service, i,
21190Sstevel@tonic-gate 				    pam_trace_cname(pamh),
21200Sstevel@tonic-gate 				    pam_snames[pamentp->pam_type]);
21210Sstevel@tonic-gate 				tpament =
21220Sstevel@tonic-gate 				    pamh->pam_conf_info[i][pamentp->pam_type];
21230Sstevel@tonic-gate 				while (tpament->next != NULL) {
21240Sstevel@tonic-gate 					tpament = tpament->next;
21250Sstevel@tonic-gate 				}
21260Sstevel@tonic-gate 				tpament->next = pamentp;
21270Sstevel@tonic-gate 			}
21280Sstevel@tonic-gate 		} else if (service_found[pamentp->pam_type + 1] == 0) {
21290Sstevel@tonic-gate 			/* See if "other" entry available and valid */
21300Sstevel@tonic-gate 			if (verify_pam_conf(pamentp, "other")) {
21310Sstevel@tonic-gate 				pam_trace(PAM_DEBUG_CONF,
21320Sstevel@tonic-gate 				    "read_pam_conf(%p): bad entry error %s "
21330Sstevel@tonic-gate 				    "\"other\"[%d:%s]",
21340Sstevel@tonic-gate 				    (void *)pamh, service, i,
21350Sstevel@tonic-gate 				    pam_trace_cname(pamh));
21360Sstevel@tonic-gate 				error = PAM_SYSTEM_ERR;
21370Sstevel@tonic-gate 				free_pamconf(pamentp);
21380Sstevel@tonic-gate 				goto out;
21390Sstevel@tonic-gate 			}
21400Sstevel@tonic-gate 			if (strcasecmp(pamentp->pam_service, "other") == 0) {
21410Sstevel@tonic-gate 				pam_trace(PAM_DEBUG_CONF,
21420Sstevel@tonic-gate 				    "read_pam_conf(%p): processing "
21430Sstevel@tonic-gate 				    "\"other\"[%d:%s]", (void *)pamh, i,
21440Sstevel@tonic-gate 				    pam_trace_cname(pamh));
21450Sstevel@tonic-gate 				if ((tpament = pamh->pam_conf_info[i]
21460Sstevel@tonic-gate 				    [pamentp->pam_type]) == NULL) {
21470Sstevel@tonic-gate 					/* add first "other" entry */
21480Sstevel@tonic-gate 					pam_trace(PAM_DEBUG_CONF,
21490Sstevel@tonic-gate 					    "read_pam_conf(%p): adding 1st "
21500Sstevel@tonic-gate 					    "other[%d:%s][%s]", (void *)pamh, i,
21510Sstevel@tonic-gate 					    pam_trace_cname(pamh),
21520Sstevel@tonic-gate 					    pam_snames[pamentp->pam_type]);
21530Sstevel@tonic-gate 					pamh->pam_conf_info[i]
21540Sstevel@tonic-gate 					    [pamentp->pam_type] = pamentp;
21550Sstevel@tonic-gate 				} else {
21560Sstevel@tonic-gate 					/* append more "other" entries */
21570Sstevel@tonic-gate 					pam_trace(PAM_DEBUG_CONF,
21580Sstevel@tonic-gate 					    "read_pam_conf(%p): adding more "
21590Sstevel@tonic-gate 					    "other[%d:%s][%s]", (void *)pamh, i,
21600Sstevel@tonic-gate 					    pam_trace_cname(pamh),
21610Sstevel@tonic-gate 					    pam_snames[pamentp->pam_type]);
21620Sstevel@tonic-gate 					while (tpament->next != NULL) {
21630Sstevel@tonic-gate 						tpament = tpament->next;
21640Sstevel@tonic-gate 					}
21650Sstevel@tonic-gate 					tpament->next = pamentp;
21660Sstevel@tonic-gate 				}
21670Sstevel@tonic-gate 			} else {
2168*3517Smp204432 				/* irrelevant entry */
21690Sstevel@tonic-gate 				free_pamconf(pamentp);
21700Sstevel@tonic-gate 			}
21710Sstevel@tonic-gate 		} else {
2172*3517Smp204432 			/* irrelevant entry */
21730Sstevel@tonic-gate 			free_pamconf(pamentp);
21740Sstevel@tonic-gate 		}
21750Sstevel@tonic-gate 	}
21760Sstevel@tonic-gate out:
21770Sstevel@tonic-gate 	(void) close_pam_conf(pam_fh);
21780Sstevel@tonic-gate 	if (error != PAM_SUCCESS)
21790Sstevel@tonic-gate 		free_pam_conf_info(pamh);
21800Sstevel@tonic-gate 	return (error);
21810Sstevel@tonic-gate }
21820Sstevel@tonic-gate 
21830Sstevel@tonic-gate /*
21840Sstevel@tonic-gate  * get_pam_conf_entry - get a pam.conf entry
21850Sstevel@tonic-gate  */
21860Sstevel@tonic-gate 
21870Sstevel@tonic-gate static int
21880Sstevel@tonic-gate get_pam_conf_entry(struct pam_fh *pam_fh, pam_handle_t *pamh, pamtab_t **pam)
21890Sstevel@tonic-gate {
21900Sstevel@tonic-gate 	char		*cp, *arg;
21910Sstevel@tonic-gate 	int		argc;
21920Sstevel@tonic-gate 	char		*tmp, *tmp_free;
21930Sstevel@tonic-gate 	int		i;
21940Sstevel@tonic-gate 	char		*current_line = NULL;
21950Sstevel@tonic-gate 	int		error = PAM_SYSTEM_ERR;	/* preset to error */
21962295Sgww 	int		err;
21970Sstevel@tonic-gate 
21980Sstevel@tonic-gate 	/* get the next line from pam.conf */
21992295Sgww 	if ((cp = nextline(pam_fh, pamh, &err)) == NULL) {
22000Sstevel@tonic-gate 		/* no more lines in pam.conf ==> return */
22010Sstevel@tonic-gate 		error = PAM_SUCCESS;
22020Sstevel@tonic-gate 		*pam = NULL;
22030Sstevel@tonic-gate 		goto out;
22040Sstevel@tonic-gate 	}
22050Sstevel@tonic-gate 
22060Sstevel@tonic-gate 	if ((*pam = (pamtab_t *)calloc(1, sizeof (pamtab_t))) == NULL) {
22070Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
22080Sstevel@tonic-gate 		goto out;
22090Sstevel@tonic-gate 	}
22100Sstevel@tonic-gate 
22110Sstevel@tonic-gate 	/* copy full line for error reporting */
22120Sstevel@tonic-gate 	if ((current_line = strdup(cp)) == NULL) {
22130Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
22140Sstevel@tonic-gate 		goto out;
22150Sstevel@tonic-gate 	}
22160Sstevel@tonic-gate 
22170Sstevel@tonic-gate 	pam_trace(PAM_DEBUG_CONF,
22180Sstevel@tonic-gate 	    "pam.conf[%s] entry:\t%s", pam_trace_cname(pamh), current_line);
22190Sstevel@tonic-gate 
22200Sstevel@tonic-gate 	/* get service name (e.g. login, su, passwd) */
22210Sstevel@tonic-gate 	if ((arg = read_next_token(&cp)) == 0) {
22220Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_CRIT,
22230Sstevel@tonic-gate 		    "illegal pam.conf[%s] entry: %s: missing SERVICE NAME",
22240Sstevel@tonic-gate 		    pam_trace_cname(pamh), current_line);
22250Sstevel@tonic-gate 		goto out;
22260Sstevel@tonic-gate 	}
22270Sstevel@tonic-gate 	if (((*pam)->pam_service = strdup(arg)) == 0) {
22280Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
22290Sstevel@tonic-gate 		goto out;
22300Sstevel@tonic-gate 	}
22310Sstevel@tonic-gate 
22320Sstevel@tonic-gate 	/* get module type (e.g. authentication, acct mgmt) */
22330Sstevel@tonic-gate 	if ((arg = read_next_token(&cp)) == 0) {
22340Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_CRIT,
22350Sstevel@tonic-gate 		    "illegal pam.conf[%s] entry: %s: missing MODULE TYPE",
22360Sstevel@tonic-gate 		    pam_trace_cname(pamh), current_line);
22370Sstevel@tonic-gate 		(*pam)->pam_type = -1;	/* 0 is a valid value */
22380Sstevel@tonic-gate 		goto getflag;
22390Sstevel@tonic-gate 	}
22400Sstevel@tonic-gate 	if (strcasecmp(arg, PAM_AUTH_NAME) == 0) {
22410Sstevel@tonic-gate 		(*pam)->pam_type = PAM_AUTH_MODULE;
22420Sstevel@tonic-gate 	} else if (strcasecmp(arg, PAM_ACCOUNT_NAME) == 0) {
22430Sstevel@tonic-gate 		(*pam)->pam_type = PAM_ACCOUNT_MODULE;
22440Sstevel@tonic-gate 	} else if (strcasecmp(arg, PAM_SESSION_NAME) == 0) {
22450Sstevel@tonic-gate 		(*pam)->pam_type = PAM_SESSION_MODULE;
22460Sstevel@tonic-gate 	} else if (strcasecmp(arg, PAM_PASSWORD_NAME) == 0) {
22470Sstevel@tonic-gate 		(*pam)->pam_type = PAM_PASSWORD_MODULE;
22480Sstevel@tonic-gate 	} else {
22490Sstevel@tonic-gate 		/* error */
22500Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_CRIT,
22510Sstevel@tonic-gate 		    "illegal pam.conf[%s] entry: %s: invalid module "
22520Sstevel@tonic-gate 		    "type: %s", pam_trace_cname(pamh), current_line, arg);
22530Sstevel@tonic-gate 		(*pam)->pam_type = -1;	/* 0 is a valid value */
22540Sstevel@tonic-gate 	}
22550Sstevel@tonic-gate 
22560Sstevel@tonic-gate getflag:
22570Sstevel@tonic-gate 	/* get pam flag (e.g., requisite, required, sufficient, optional) */
22580Sstevel@tonic-gate 	if ((arg = read_next_token(&cp)) == 0) {
22590Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_CRIT,
22600Sstevel@tonic-gate 		    "illegal pam.conf[%s] entry: %s: missing CONTROL FLAG",
22610Sstevel@tonic-gate 		    pam_trace_cname(pamh), current_line);
22620Sstevel@tonic-gate 		goto getpath;
22630Sstevel@tonic-gate 	}
22640Sstevel@tonic-gate 	if (strcasecmp(arg, PAM_BINDING_NAME) == 0) {
22650Sstevel@tonic-gate 		(*pam)->pam_flag = PAM_BINDING;
22660Sstevel@tonic-gate 	} else if (strcasecmp(arg, PAM_INCLUDE_NAME) == 0) {
22670Sstevel@tonic-gate 		(*pam)->pam_flag = PAM_INCLUDE;
22680Sstevel@tonic-gate 	} else if (strcasecmp(arg, PAM_OPTIONAL_NAME) == 0) {
22690Sstevel@tonic-gate 		(*pam)->pam_flag = PAM_OPTIONAL;
22700Sstevel@tonic-gate 	} else if (strcasecmp(arg, PAM_REQUIRED_NAME) == 0) {
22710Sstevel@tonic-gate 		(*pam)->pam_flag = PAM_REQUIRED;
22720Sstevel@tonic-gate 	} else if (strcasecmp(arg, PAM_REQUISITE_NAME) == 0) {
22730Sstevel@tonic-gate 		(*pam)->pam_flag = PAM_REQUISITE;
22740Sstevel@tonic-gate 	} else if (strcasecmp(arg, PAM_SUFFICIENT_NAME) == 0) {
22750Sstevel@tonic-gate 		(*pam)->pam_flag = PAM_SUFFICIENT;
22760Sstevel@tonic-gate 	} else {
22770Sstevel@tonic-gate 		/* error */
22780Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_CRIT,
22790Sstevel@tonic-gate 		    "illegal pam.conf[%s] entry: %s",
22800Sstevel@tonic-gate 		    pam_trace_cname(pamh), current_line);
22810Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_CRIT,
22820Sstevel@tonic-gate 		    "\tinvalid control flag: %s", arg);
22830Sstevel@tonic-gate 	}
22840Sstevel@tonic-gate 
22850Sstevel@tonic-gate getpath:
22860Sstevel@tonic-gate 	/* get module path (e.g. /usr/lib/security/pam_unix_auth.so.1) */
22870Sstevel@tonic-gate 	if ((arg = read_next_token(&cp)) == 0) {
22880Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_CRIT,
22890Sstevel@tonic-gate 		    "illegal pam.conf[%s] entry: %s: missing MODULE PATH",
22900Sstevel@tonic-gate 		    pam_trace_cname(pamh), current_line);
22910Sstevel@tonic-gate 		error = PAM_SUCCESS;	/* success */
22920Sstevel@tonic-gate 		goto out;
22930Sstevel@tonic-gate 	}
22940Sstevel@tonic-gate 	if (arg[0] != '/') {
22950Sstevel@tonic-gate 		size_t len;
22960Sstevel@tonic-gate 		/*
22970Sstevel@tonic-gate 		 * If module path does not start with "/", then
22980Sstevel@tonic-gate 		 * prepend PAM_LIB_DIR (/usr/lib/security/).
22990Sstevel@tonic-gate 		 */
23000Sstevel@tonic-gate 		/* sizeof (PAM_LIB_DIR) has room for '\0' */
23010Sstevel@tonic-gate 		len = sizeof (PAM_LIB_DIR) + sizeof (PAM_ISA_DIR) + strlen(arg);
23020Sstevel@tonic-gate 		if (((*pam)->module_path = malloc(len)) == NULL) {
23030Sstevel@tonic-gate 			__pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
23040Sstevel@tonic-gate 			goto out;
23050Sstevel@tonic-gate 		}
23060Sstevel@tonic-gate 		if ((*pam)->pam_flag & PAM_INCLUDE) {
23070Sstevel@tonic-gate 			(void) snprintf((*pam)->module_path, len, "%s%s",
23080Sstevel@tonic-gate 			    PAM_LIB_DIR, arg);
23090Sstevel@tonic-gate 		} else {
23100Sstevel@tonic-gate 			(void) snprintf((*pam)->module_path, len, "%s%s%s",
23110Sstevel@tonic-gate 			    PAM_LIB_DIR, PAM_ISA_DIR, arg);
23120Sstevel@tonic-gate 		}
23130Sstevel@tonic-gate 	} else {
23140Sstevel@tonic-gate 		/* Full path provided for module */
23150Sstevel@tonic-gate 		char *isa;
23160Sstevel@tonic-gate 
23170Sstevel@tonic-gate 		/* Check for Instruction Set Architecture indicator */
23180Sstevel@tonic-gate 		if ((isa = strstr(arg, PAM_ISA)) != NULL) {
23190Sstevel@tonic-gate 			size_t len;
23200Sstevel@tonic-gate 			len = strlen(arg) - (sizeof (PAM_ISA)-1) +
23210Sstevel@tonic-gate 			    sizeof (PAM_ISA_DIR);
23220Sstevel@tonic-gate 
23230Sstevel@tonic-gate 			/* substitute the architecture dependent path */
23240Sstevel@tonic-gate 			if (((*pam)->module_path = malloc(len)) == NULL) {
23250Sstevel@tonic-gate 				__pam_log(LOG_AUTH | LOG_ERR,
23260Sstevel@tonic-gate 				    "strdup: out of memory");
23270Sstevel@tonic-gate 				goto out;
23280Sstevel@tonic-gate 			}
23290Sstevel@tonic-gate 			*isa = '\000';
23300Sstevel@tonic-gate 			isa += strlen(PAM_ISA);
23310Sstevel@tonic-gate 			(void) snprintf((*pam)->module_path, len, "%s%s%s",
23320Sstevel@tonic-gate 			    arg, PAM_ISA_DIR, isa);
23330Sstevel@tonic-gate 		} else if (((*pam)->module_path = strdup(arg)) == 0) {
23340Sstevel@tonic-gate 			__pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
23350Sstevel@tonic-gate 			goto out;
23360Sstevel@tonic-gate 		}
23370Sstevel@tonic-gate 	}
23380Sstevel@tonic-gate 
23390Sstevel@tonic-gate 	/* count the number of module-specific options first */
23400Sstevel@tonic-gate 	argc = 0;
23410Sstevel@tonic-gate 	if ((tmp = strdup(cp)) == NULL) {
23420Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
23430Sstevel@tonic-gate 		goto out;
23440Sstevel@tonic-gate 	}
23450Sstevel@tonic-gate 	tmp_free = tmp;
23460Sstevel@tonic-gate 	for (arg = read_next_token(&tmp); arg; arg = read_next_token(&tmp))
23470Sstevel@tonic-gate 		argc++;
23480Sstevel@tonic-gate 	free(tmp_free);
23490Sstevel@tonic-gate 
23500Sstevel@tonic-gate 	/* allocate array for the module-specific options */
23510Sstevel@tonic-gate 	if (argc > 0) {
23520Sstevel@tonic-gate 		if (((*pam)->module_argv = (char **)
23530Sstevel@tonic-gate 			calloc(argc+1, sizeof (char *))) == 0) {
23540Sstevel@tonic-gate 			__pam_log(LOG_AUTH | LOG_ERR, "calloc: out of memory");
23550Sstevel@tonic-gate 			goto out;
23560Sstevel@tonic-gate 		}
23570Sstevel@tonic-gate 		i = 0;
23580Sstevel@tonic-gate 		for (arg = read_next_token(&cp); arg;
23590Sstevel@tonic-gate 			arg = read_next_token(&cp)) {
23600Sstevel@tonic-gate 			(*pam)->module_argv[i] = strdup(arg);
23610Sstevel@tonic-gate 			if ((*pam)->module_argv[i] == NULL) {
23620Sstevel@tonic-gate 				__pam_log(LOG_AUTH | LOG_ERR, "strdup failed");
23630Sstevel@tonic-gate 				goto out;
23640Sstevel@tonic-gate 			}
23650Sstevel@tonic-gate 			i++;
23660Sstevel@tonic-gate 		}
23670Sstevel@tonic-gate 		(*pam)->module_argv[argc] = NULL;
23680Sstevel@tonic-gate 	}
23690Sstevel@tonic-gate 	(*pam)->module_argc = argc;
23700Sstevel@tonic-gate 
23710Sstevel@tonic-gate 	error = PAM_SUCCESS;	/* success */
23722295Sgww 	(*pam)->pam_err = err;	/* was the line truncated */
23730Sstevel@tonic-gate 
23740Sstevel@tonic-gate out:
23750Sstevel@tonic-gate 	if (current_line)
23760Sstevel@tonic-gate 		free(current_line);
23770Sstevel@tonic-gate 	if (error != PAM_SUCCESS) {
23780Sstevel@tonic-gate 		/* on error free this */
23790Sstevel@tonic-gate 		if (*pam)
23800Sstevel@tonic-gate 			free_pamconf(*pam);
23810Sstevel@tonic-gate 	}
23820Sstevel@tonic-gate 	return (error);
23830Sstevel@tonic-gate }
23840Sstevel@tonic-gate 
23850Sstevel@tonic-gate 
23860Sstevel@tonic-gate /*
23870Sstevel@tonic-gate  * read_next_token - skip tab and space characters and return the next token
23880Sstevel@tonic-gate  */
23890Sstevel@tonic-gate 
23900Sstevel@tonic-gate static char *
23910Sstevel@tonic-gate read_next_token(char **cpp)
23920Sstevel@tonic-gate {
23930Sstevel@tonic-gate 	register char *cp = *cpp;
23940Sstevel@tonic-gate 	char *start;
23950Sstevel@tonic-gate 
23960Sstevel@tonic-gate 	if (cp == (char *)0) {
23970Sstevel@tonic-gate 		*cpp = (char *)0;
23980Sstevel@tonic-gate 		return ((char *)0);
23990Sstevel@tonic-gate 	}
24000Sstevel@tonic-gate 	while (*cp == ' ' || *cp == '\t')
24010Sstevel@tonic-gate 		cp++;
24020Sstevel@tonic-gate 	if (*cp == '\0') {
24030Sstevel@tonic-gate 		*cpp = (char *)0;
24040Sstevel@tonic-gate 		return ((char *)0);
24050Sstevel@tonic-gate 	}
24060Sstevel@tonic-gate 	start = cp;
24070Sstevel@tonic-gate 	while (*cp && *cp != ' ' && *cp != '\t')
24080Sstevel@tonic-gate 		cp++;
24090Sstevel@tonic-gate 	if (*cp != '\0')
24100Sstevel@tonic-gate 		*cp++ = '\0';
24110Sstevel@tonic-gate 	*cpp = cp;
24120Sstevel@tonic-gate 	return (start);
24130Sstevel@tonic-gate }
24140Sstevel@tonic-gate 
24150Sstevel@tonic-gate static char *
24160Sstevel@tonic-gate pam_conf_strnchr(char *sp, int c, intptr_t count)
24170Sstevel@tonic-gate {
24180Sstevel@tonic-gate 	while (count) {
24190Sstevel@tonic-gate 		if (*sp == (char)c)
24200Sstevel@tonic-gate 			return ((char *)sp);
24210Sstevel@tonic-gate 		else {
24220Sstevel@tonic-gate 			sp++;
24230Sstevel@tonic-gate 			count--;
24240Sstevel@tonic-gate 		}
24250Sstevel@tonic-gate 	};
24260Sstevel@tonic-gate 	return (NULL);
24270Sstevel@tonic-gate }
24280Sstevel@tonic-gate 
24290Sstevel@tonic-gate /*
24300Sstevel@tonic-gate  * nextline - skip all blank lines and comments
24310Sstevel@tonic-gate  */
24320Sstevel@tonic-gate 
24330Sstevel@tonic-gate static char *
24342295Sgww nextline(struct pam_fh *pam_fh, pam_handle_t *pamh, int *err)
24350Sstevel@tonic-gate {
24360Sstevel@tonic-gate 	char	*ll;
24370Sstevel@tonic-gate 	int	find_a_line = 0;
24380Sstevel@tonic-gate 	char	*data = pam_fh->data;
24390Sstevel@tonic-gate 	char	*bufferp = pam_fh->bufferp;
24400Sstevel@tonic-gate 	char	*bufferendp = &data[pam_fh->bufsize];
24412295Sgww 	size_t	input_len;
24420Sstevel@tonic-gate 
24430Sstevel@tonic-gate 	/*
24440Sstevel@tonic-gate 	 * Skip the blank line, comment line
24450Sstevel@tonic-gate 	 */
24460Sstevel@tonic-gate 	while (!find_a_line) {
24470Sstevel@tonic-gate 		/* if we are at the end of the buffer, there is no next line */
24480Sstevel@tonic-gate 		if (bufferp == bufferendp)
24490Sstevel@tonic-gate 			return (NULL);
24500Sstevel@tonic-gate 
24510Sstevel@tonic-gate 		/* skip blank line */
24520Sstevel@tonic-gate 		while (*bufferp == '\n') {
24530Sstevel@tonic-gate 			/*
24540Sstevel@tonic-gate 			 * If we are at the end of the buffer, there is
24550Sstevel@tonic-gate 			 * no next line.
24560Sstevel@tonic-gate 			 */
24572295Sgww 			if (++bufferp == bufferendp) {
24580Sstevel@tonic-gate 				return (NULL);
24592295Sgww 			}
24600Sstevel@tonic-gate 			/* else we check *bufferp again */
24610Sstevel@tonic-gate 		}
24620Sstevel@tonic-gate 
24630Sstevel@tonic-gate 		/* skip comment line */
24640Sstevel@tonic-gate 		while (*bufferp == '#') {
24650Sstevel@tonic-gate 			if ((ll = pam_conf_strnchr(bufferp, '\n',
24660Sstevel@tonic-gate 				bufferendp - bufferp)) != NULL) {
24670Sstevel@tonic-gate 				bufferp = ll;
24682295Sgww 			} else {
24692295Sgww 				/*
24702295Sgww 				 * this comment line the last line.
24712295Sgww 				 * no next line
24722295Sgww 				 */
24732295Sgww 				return (NULL);
24740Sstevel@tonic-gate 			}
24750Sstevel@tonic-gate 
24760Sstevel@tonic-gate 			/*
24770Sstevel@tonic-gate 			 * If we are at the end of the buffer, there is
24780Sstevel@tonic-gate 			 * no next line.
24790Sstevel@tonic-gate 			 */
24802295Sgww 			if (bufferp == bufferendp) {
24810Sstevel@tonic-gate 				return (NULL);
24822295Sgww 			}
24830Sstevel@tonic-gate 		}
24840Sstevel@tonic-gate 
24852295Sgww 		if ((*bufferp != '\n') && (*bufferp != '#')) {
24860Sstevel@tonic-gate 			find_a_line = 1;
24872295Sgww 		}
24880Sstevel@tonic-gate 	}
24890Sstevel@tonic-gate 
24902295Sgww 	*err = PAM_SUCCESS;
24910Sstevel@tonic-gate 	/* now we find one line */
24920Sstevel@tonic-gate 	if ((ll = pam_conf_strnchr(bufferp, '\n', bufferendp - bufferp))
24932295Sgww 	    != NULL) {
24942295Sgww 		if ((input_len = ll - bufferp) >= sizeof (pam_fh->line)) {
24952295Sgww 			__pam_log(LOG_AUTH | LOG_ERR,
24962295Sgww 			    "nextline[%d:%s]: pam.conf line too long %.256s",
24972295Sgww 			    pamh->include_depth, pam_trace_cname(pamh),
24982295Sgww 			    bufferp);
24992295Sgww 			input_len = sizeof (pam_fh->line) - 1;
25002295Sgww 			*err = PAM_SERVICE_ERR;
25012295Sgww 		}
25022295Sgww 		(void) strncpy(pam_fh->line, bufferp, input_len);
25032295Sgww 		pam_fh->line[input_len] = '\0';
25040Sstevel@tonic-gate 		pam_fh->bufferp = ll++;
25050Sstevel@tonic-gate 	} else {
25060Sstevel@tonic-gate 		ll = bufferendp;
25072295Sgww 		if ((input_len = ll - bufferp) >= sizeof (pam_fh->line)) {
25082295Sgww 			__pam_log(LOG_AUTH | LOG_ERR,
25092295Sgww 			    "nextline[%d:%s]: pam.conf line too long %.256s",
25102295Sgww 			    pamh->include_depth, pam_trace_cname(pamh),
25112295Sgww 			    bufferp);
25122295Sgww 			input_len = sizeof (pam_fh->line) - 1;
25132295Sgww 			*err = PAM_SERVICE_ERR;
25142295Sgww 		}
25152295Sgww 		(void) strncpy(pam_fh->line, bufferp, input_len);
25162295Sgww 		pam_fh->line[input_len] = '\0';
25170Sstevel@tonic-gate 		pam_fh->bufferp = ll;
25180Sstevel@tonic-gate 	}
25190Sstevel@tonic-gate 
25200Sstevel@tonic-gate 	return (pam_fh->line);
25210Sstevel@tonic-gate }
25220Sstevel@tonic-gate 
25230Sstevel@tonic-gate /*
25240Sstevel@tonic-gate  * verify_pam_conf - verify that the pam_conf entry is filled in.
25250Sstevel@tonic-gate  *
25262295Sgww  *	True = Error if there is no service.
25272295Sgww  *	True = Error if there is a service and it matches the requested service
25282295Sgww  *		but, the type, flag, line overflow, or path is in error.
25290Sstevel@tonic-gate  */
25300Sstevel@tonic-gate 
25310Sstevel@tonic-gate static int
25320Sstevel@tonic-gate verify_pam_conf(pamtab_t *pam, char *service)
25330Sstevel@tonic-gate {
25340Sstevel@tonic-gate 	return ((pam->pam_service == (char *)NULL) ||
25350Sstevel@tonic-gate 	    ((strcasecmp(pam->pam_service, service) == 0) &&
25360Sstevel@tonic-gate 	    ((pam->pam_type == -1) ||
25370Sstevel@tonic-gate 	    (pam->pam_flag == 0) ||
25382295Sgww 	    (pam->pam_err != PAM_SUCCESS) ||
25390Sstevel@tonic-gate 	    (pam->module_path == (char *)NULL))));
25400Sstevel@tonic-gate }
25410Sstevel@tonic-gate 
25420Sstevel@tonic-gate /*
25430Sstevel@tonic-gate  * Routines to free allocated storage
25440Sstevel@tonic-gate  */
25450Sstevel@tonic-gate 
25460Sstevel@tonic-gate /*
25470Sstevel@tonic-gate  * clean_up -  free allocated storage in the pam handle
25480Sstevel@tonic-gate  */
25490Sstevel@tonic-gate 
25500Sstevel@tonic-gate static void
25510Sstevel@tonic-gate clean_up(pam_handle_t *pamh)
25520Sstevel@tonic-gate {
25530Sstevel@tonic-gate 	int i;
25540Sstevel@tonic-gate 	pam_repository_t *auth_rep;
25550Sstevel@tonic-gate 
25560Sstevel@tonic-gate 	if (pamh) {
25570Sstevel@tonic-gate 		/* Cleanup Sun proprietary tag information */
25580Sstevel@tonic-gate 		if (pamh->pam_client_message_version_number)
25590Sstevel@tonic-gate 			free(pamh->pam_client_message_version_number);
25600Sstevel@tonic-gate 
25610Sstevel@tonic-gate 		while (pamh->include_depth >= 0) {
25620Sstevel@tonic-gate 			free_pam_conf_info(pamh);
25630Sstevel@tonic-gate 			pamh->include_depth--;
25640Sstevel@tonic-gate 		}
25650Sstevel@tonic-gate 
25660Sstevel@tonic-gate 		/* Cleanup PAM_REPOSITORY structure */
25670Sstevel@tonic-gate 		auth_rep = pamh->ps_item[PAM_REPOSITORY].pi_addr;
25680Sstevel@tonic-gate 		if (auth_rep != NULL) {
25690Sstevel@tonic-gate 			if (auth_rep->type != NULL)
25700Sstevel@tonic-gate 				free(auth_rep->type);
25710Sstevel@tonic-gate 			if (auth_rep->scope != NULL)
25720Sstevel@tonic-gate 				free(auth_rep->scope);
25730Sstevel@tonic-gate 		}
25740Sstevel@tonic-gate 
25750Sstevel@tonic-gate 		for (i = 0; i < PAM_MAX_ITEMS; i++) {
25760Sstevel@tonic-gate 			if (pamh->ps_item[i].pi_addr != NULL) {
25770Sstevel@tonic-gate 				if (i == PAM_AUTHTOK || i == PAM_OLDAUTHTOK) {
25780Sstevel@tonic-gate 					(void) memset(pamh->ps_item[i].pi_addr,
25790Sstevel@tonic-gate 					    0, pamh->ps_item[i].pi_size);
25800Sstevel@tonic-gate 				}
25810Sstevel@tonic-gate 				free(pamh->ps_item[i].pi_addr);
25820Sstevel@tonic-gate 			}
25830Sstevel@tonic-gate 		}
25840Sstevel@tonic-gate 		free(pamh);
25850Sstevel@tonic-gate 	}
25860Sstevel@tonic-gate }
25870Sstevel@tonic-gate 
25880Sstevel@tonic-gate /*
25890Sstevel@tonic-gate  * free_pamconf - free memory used to store pam.conf entry
25900Sstevel@tonic-gate  */
25910Sstevel@tonic-gate 
25920Sstevel@tonic-gate static void
25930Sstevel@tonic-gate free_pamconf(pamtab_t *cp)
25940Sstevel@tonic-gate {
25950Sstevel@tonic-gate 	int i;
25960Sstevel@tonic-gate 
25970Sstevel@tonic-gate 	if (cp) {
25980Sstevel@tonic-gate 		if (cp->pam_service)
25990Sstevel@tonic-gate 			free(cp->pam_service);
26000Sstevel@tonic-gate 		if (cp->module_path)
26010Sstevel@tonic-gate 			free(cp->module_path);
26020Sstevel@tonic-gate 		for (i = 0; i < cp->module_argc; i++) {
26030Sstevel@tonic-gate 			if (cp->module_argv[i])
26040Sstevel@tonic-gate 				free(cp->module_argv[i]);
26050Sstevel@tonic-gate 		}
26060Sstevel@tonic-gate 		if (cp->module_argc > 0)
26070Sstevel@tonic-gate 			free(cp->module_argv);
26080Sstevel@tonic-gate 		if (cp->function_ptr)
26090Sstevel@tonic-gate 			free(cp->function_ptr);
26100Sstevel@tonic-gate 
26110Sstevel@tonic-gate 		free(cp);
26120Sstevel@tonic-gate 	}
26130Sstevel@tonic-gate }
26140Sstevel@tonic-gate 
26150Sstevel@tonic-gate /*
26160Sstevel@tonic-gate  * free_pam_conf_info - free memory used to store all pam.conf info
26170Sstevel@tonic-gate  *			under the pam handle
26180Sstevel@tonic-gate  */
26190Sstevel@tonic-gate 
26200Sstevel@tonic-gate static void
26210Sstevel@tonic-gate free_pam_conf_info(pam_handle_t *pamh)
26220Sstevel@tonic-gate {
26230Sstevel@tonic-gate 	pamtab_t *pamentp;
26240Sstevel@tonic-gate 	pamtab_t *pament_trail;
26250Sstevel@tonic-gate 	int i = pamh->include_depth;
26260Sstevel@tonic-gate 	int j;
26270Sstevel@tonic-gate 
26280Sstevel@tonic-gate 	for (j = 0; j < PAM_NUM_MODULE_TYPES; j++) {
26290Sstevel@tonic-gate 		pamentp = pamh->pam_conf_info[i][j];
26300Sstevel@tonic-gate 		pamh->pam_conf_info[i][j] = NULL;
26310Sstevel@tonic-gate 		pament_trail = pamentp;
26320Sstevel@tonic-gate 		while (pamentp) {
26330Sstevel@tonic-gate 			pamentp = pamentp->next;
26340Sstevel@tonic-gate 			free_pamconf(pament_trail);
26350Sstevel@tonic-gate 			pament_trail = pamentp;
26360Sstevel@tonic-gate 		}
26370Sstevel@tonic-gate 	}
26380Sstevel@tonic-gate 	if (pamh->pam_conf_name[i] != NULL) {
26390Sstevel@tonic-gate 		free(pamh->pam_conf_name[i]);
26400Sstevel@tonic-gate 		pamh->pam_conf_name[i] = NULL;
26410Sstevel@tonic-gate 	}
26420Sstevel@tonic-gate }
26430Sstevel@tonic-gate 
26440Sstevel@tonic-gate static void
26450Sstevel@tonic-gate free_env(env_list *pam_env)
26460Sstevel@tonic-gate {
26470Sstevel@tonic-gate 	if (pam_env) {
26480Sstevel@tonic-gate 		if (pam_env->name)
26490Sstevel@tonic-gate 			free(pam_env->name);
26500Sstevel@tonic-gate 		if (pam_env->value)
26510Sstevel@tonic-gate 			free(pam_env->value);
26520Sstevel@tonic-gate 		free(pam_env);
26530Sstevel@tonic-gate 	}
26540Sstevel@tonic-gate }
26550Sstevel@tonic-gate 
26560Sstevel@tonic-gate /*
26570Sstevel@tonic-gate  *	Internal convenience functions for Solaris PAM service modules.
26580Sstevel@tonic-gate  */
26590Sstevel@tonic-gate 
26600Sstevel@tonic-gate #include <libintl.h>
26610Sstevel@tonic-gate #include <nl_types.h>
26620Sstevel@tonic-gate #include <synch.h>
26630Sstevel@tonic-gate #include <locale.h>
26640Sstevel@tonic-gate #include <thread.h>
26650Sstevel@tonic-gate 
26660Sstevel@tonic-gate typedef struct pam_msg_data {
26670Sstevel@tonic-gate 	nl_catd fd;
26680Sstevel@tonic-gate } pam_msg_data_t;
26690Sstevel@tonic-gate 
26700Sstevel@tonic-gate /*
26710Sstevel@tonic-gate  * free_resp():
26720Sstevel@tonic-gate  *	free storage for responses used in the call back "pam_conv" functions
26730Sstevel@tonic-gate  */
26740Sstevel@tonic-gate 
26750Sstevel@tonic-gate void
26760Sstevel@tonic-gate free_resp(int num_msg, struct pam_response *resp)
26770Sstevel@tonic-gate {
26780Sstevel@tonic-gate 	int			i;
26790Sstevel@tonic-gate 	struct pam_response	*r;
26800Sstevel@tonic-gate 
26810Sstevel@tonic-gate 	if (resp) {
26820Sstevel@tonic-gate 		r = resp;
26830Sstevel@tonic-gate 		for (i = 0; i < num_msg; i++, r++) {
26840Sstevel@tonic-gate 			if (r->resp) {
26850Sstevel@tonic-gate 				/* clear before freeing -- may be a password */
26860Sstevel@tonic-gate 				bzero(r->resp, strlen(r->resp));
26870Sstevel@tonic-gate 				free(r->resp);
26880Sstevel@tonic-gate 				r->resp = NULL;
26890Sstevel@tonic-gate 			}
26900Sstevel@tonic-gate 		}
26910Sstevel@tonic-gate 		free(resp);
26920Sstevel@tonic-gate 	}
26930Sstevel@tonic-gate }
26940Sstevel@tonic-gate 
26950Sstevel@tonic-gate static int
26960Sstevel@tonic-gate do_conv(pam_handle_t *pamh, int msg_style, int num_msg,
26970Sstevel@tonic-gate     char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], void *conv_apdp,
26980Sstevel@tonic-gate     struct pam_response *ret_respp[])
26990Sstevel@tonic-gate {
27000Sstevel@tonic-gate 	struct pam_message	*msg;
27010Sstevel@tonic-gate 	struct pam_message	*m;
27020Sstevel@tonic-gate 	int			i;
27030Sstevel@tonic-gate 	int			k;
27040Sstevel@tonic-gate 	int			retcode;
27050Sstevel@tonic-gate 	struct pam_conv		*pam_convp;
27060Sstevel@tonic-gate 
27070Sstevel@tonic-gate 	if ((retcode = pam_get_item(pamh, PAM_CONV,
27080Sstevel@tonic-gate 	    (void **)&pam_convp)) != PAM_SUCCESS) {
27090Sstevel@tonic-gate 		return (retcode);
27100Sstevel@tonic-gate 	}
27110Sstevel@tonic-gate 
27120Sstevel@tonic-gate 	/*
27130Sstevel@tonic-gate 	 * When pam_set_item() is called to set PAM_CONV and the
27140Sstevel@tonic-gate 	 * item is NULL, memset(pip->pi_addr, 0, size) is called.
27150Sstevel@tonic-gate 	 * So at this point, we should check whether pam_convp->conv
27160Sstevel@tonic-gate 	 * is NULL or not.
27170Sstevel@tonic-gate 	 */
27180Sstevel@tonic-gate 	if ((pam_convp == NULL) || (pam_convp->conv == NULL))
27190Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
27200Sstevel@tonic-gate 
27210Sstevel@tonic-gate 	i = 0;
27220Sstevel@tonic-gate 	k = num_msg;
27230Sstevel@tonic-gate 
27240Sstevel@tonic-gate 	msg = (struct pam_message *)calloc(num_msg,
27250Sstevel@tonic-gate 	    sizeof (struct pam_message));
27260Sstevel@tonic-gate 	if (msg == NULL) {
27270Sstevel@tonic-gate 		return (PAM_BUF_ERR);
27280Sstevel@tonic-gate 	}
27290Sstevel@tonic-gate 	m = msg;
27300Sstevel@tonic-gate 
27310Sstevel@tonic-gate 	while (k--) {
27320Sstevel@tonic-gate 		/*
27330Sstevel@tonic-gate 		 * fill out the message structure to display prompt message
27340Sstevel@tonic-gate 		 */
27350Sstevel@tonic-gate 		m->msg_style = msg_style;
27360Sstevel@tonic-gate 		m->msg = messages[i];
27370Sstevel@tonic-gate 		pam_trace(PAM_DEBUG_CONV,
27380Sstevel@tonic-gate 		    "pam_conv_msg(%p:%d[%d]=%s)",
27390Sstevel@tonic-gate 		    (void *)pamh, msg_style, i, messages[i]);
27400Sstevel@tonic-gate 		m++;
27410Sstevel@tonic-gate 		i++;
27420Sstevel@tonic-gate 	}
27430Sstevel@tonic-gate 
27440Sstevel@tonic-gate 	/*
27450Sstevel@tonic-gate 	 * The UNIX pam modules always calls __pam_get_authtok() and
27460Sstevel@tonic-gate 	 * __pam_display_msg() with a NULL pointer as the conv_apdp.
27470Sstevel@tonic-gate 	 * In case the conv_apdp is NULL and the pam_convp->appdata_ptr
27480Sstevel@tonic-gate 	 * is not NULL, we should pass the pam_convp->appdata_ptr
27490Sstevel@tonic-gate 	 * to the conversation function.
27500Sstevel@tonic-gate 	 */
27510Sstevel@tonic-gate 	if (conv_apdp == NULL && pam_convp->appdata_ptr != NULL)
27520Sstevel@tonic-gate 		conv_apdp = pam_convp->appdata_ptr;
27530Sstevel@tonic-gate 
27540Sstevel@tonic-gate 	/*
27550Sstevel@tonic-gate 	 * Call conv function to display the prompt.
27560Sstevel@tonic-gate 	 */
27570Sstevel@tonic-gate 	retcode = (pam_convp->conv)(num_msg, &msg, ret_respp, conv_apdp);
27580Sstevel@tonic-gate 	pam_trace(PAM_DEBUG_CONV,
27590Sstevel@tonic-gate 	    "pam_conv_resp(%p pam_conv = %s) ret_respp = %p",
27600Sstevel@tonic-gate 	    (void *)pamh, pam_strerror(pamh, retcode), (void *)ret_respp);
27610Sstevel@tonic-gate 	if (*ret_respp == NULL) {
27620Sstevel@tonic-gate 		pam_trace(PAM_DEBUG_CONV,
27630Sstevel@tonic-gate 		    "pam_conv_resp(%p No response requested)", (void *)pamh);
27640Sstevel@tonic-gate 	} else if ((pam_debug & (PAM_DEBUG_CONV | PAM_DEBUG_AUTHTOK)) != 0) {
27650Sstevel@tonic-gate 		struct pam_response *r = *ret_respp;
27660Sstevel@tonic-gate 
27670Sstevel@tonic-gate 		for (i = 0; i < num_msg; i++, r++) {
27680Sstevel@tonic-gate 			if (r->resp == NULL) {
27690Sstevel@tonic-gate 				pam_trace(PAM_DEBUG_CONV,
27700Sstevel@tonic-gate 				    "pam_conv_resp(%p:"
27710Sstevel@tonic-gate 				    "[%d] NULL response string)",
27720Sstevel@tonic-gate 				    (void *)pamh, i);
27730Sstevel@tonic-gate 			} else {
27740Sstevel@tonic-gate 				if (msg_style == PAM_PROMPT_ECHO_OFF) {
27750Sstevel@tonic-gate #ifdef	DEBUG
27760Sstevel@tonic-gate 					pam_trace(PAM_DEBUG_AUTHTOK,
27770Sstevel@tonic-gate 					    "pam_conv_resp(%p:[%d]=%s, "
27780Sstevel@tonic-gate 					    "code=%d)",
27790Sstevel@tonic-gate 					    (void *)pamh, i, r->resp,
27800Sstevel@tonic-gate 					    r->resp_retcode);
27810Sstevel@tonic-gate #endif	/* DEBUG */
27820Sstevel@tonic-gate 					pam_trace(PAM_DEBUG_CONV,
27830Sstevel@tonic-gate 					    "pam_conv_resp(%p:[%d] len=%lu, "
27840Sstevel@tonic-gate 					    "code=%d)",
27850Sstevel@tonic-gate 					    (void *)pamh, i,
27860Sstevel@tonic-gate 					    (ulong_t)strlen(r->resp),
27870Sstevel@tonic-gate 					    r->resp_retcode);
27880Sstevel@tonic-gate 				} else {
27890Sstevel@tonic-gate 					pam_trace(PAM_DEBUG_CONV,
27900Sstevel@tonic-gate 					    "pam_conv_resp(%p:[%d]=%s, "
27910Sstevel@tonic-gate 					    "code=%d)",
27920Sstevel@tonic-gate 					    (void *)pamh, i, r->resp,
27930Sstevel@tonic-gate 					    r->resp_retcode);
27940Sstevel@tonic-gate 				}
27950Sstevel@tonic-gate 			}
27960Sstevel@tonic-gate 		}
27970Sstevel@tonic-gate 	}
27980Sstevel@tonic-gate 
27990Sstevel@tonic-gate 	if (msg)
28000Sstevel@tonic-gate 		free(msg);
28010Sstevel@tonic-gate 	return (retcode);
28020Sstevel@tonic-gate }
28030Sstevel@tonic-gate 
28040Sstevel@tonic-gate /*
28050Sstevel@tonic-gate  * __pam_display_msg():
28060Sstevel@tonic-gate  *	display message by calling the call back functions
28070Sstevel@tonic-gate  *	provided by the application through "pam_conv" structure
28080Sstevel@tonic-gate  */
28090Sstevel@tonic-gate 
28100Sstevel@tonic-gate int
28110Sstevel@tonic-gate __pam_display_msg(pam_handle_t *pamh, int msg_style, int num_msg,
28120Sstevel@tonic-gate     char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], void *conv_apdp)
28130Sstevel@tonic-gate {
28140Sstevel@tonic-gate 	struct pam_response	*ret_respp = NULL;
28150Sstevel@tonic-gate 
28160Sstevel@tonic-gate 	return (do_conv(pamh, msg_style, num_msg, messages,
28170Sstevel@tonic-gate 	    conv_apdp, &ret_respp));
28180Sstevel@tonic-gate }
28190Sstevel@tonic-gate 
28200Sstevel@tonic-gate /*
28210Sstevel@tonic-gate  * __pam_get_authtok()
28220Sstevel@tonic-gate  *	retrieves a password of at most PASS_MAX length from the pam
28230Sstevel@tonic-gate  *	handle (pam_get_item) or from the input stream (do_conv).
28240Sstevel@tonic-gate  *
28250Sstevel@tonic-gate  * This function allocates memory for the new authtok.
28260Sstevel@tonic-gate  * Applications calling this function are responsible for
28270Sstevel@tonic-gate  * freeing this memory.
28280Sstevel@tonic-gate  *
28290Sstevel@tonic-gate  * If "source" is
28300Sstevel@tonic-gate  *	PAM_HANDLE
28310Sstevel@tonic-gate  * and "type" is:
28320Sstevel@tonic-gate  *	PAM_AUTHTOK - password is taken from pam handle (PAM_AUTHTOK)
28330Sstevel@tonic-gate  *	PAM_OLDAUTHTOK - password is taken from pam handle (PAM_OLDAUTHTOK)
28340Sstevel@tonic-gate  *
28350Sstevel@tonic-gate  * If "source" is
28360Sstevel@tonic-gate  *	PAM_PROMPT
28370Sstevel@tonic-gate  * and "type" is:
28380Sstevel@tonic-gate  *	0:		Prompt for new passwd, do not even attempt
28390Sstevel@tonic-gate  *			to store it in the pam handle.
28400Sstevel@tonic-gate  *	PAM_AUTHTOK:	Prompt for new passwd, store in pam handle as
28410Sstevel@tonic-gate  *			PAM_AUTHTOK item if this value is not already set.
28420Sstevel@tonic-gate  *	PAM_OLDAUTHTOK:	Prompt for new passwd, store in pam handle as
28430Sstevel@tonic-gate  *			PAM_OLDAUTHTOK item if this value is not
28440Sstevel@tonic-gate  *			already set.
28450Sstevel@tonic-gate  */
28460Sstevel@tonic-gate int
28470Sstevel@tonic-gate __pam_get_authtok(pam_handle_t *pamh, int source, int type, char *prompt,
28480Sstevel@tonic-gate     char **authtok)
28490Sstevel@tonic-gate {
28500Sstevel@tonic-gate 	int error = PAM_SYSTEM_ERR;
28510Sstevel@tonic-gate 	char *new_password = NULL;
28520Sstevel@tonic-gate 	struct pam_response *ret_resp = NULL;
28530Sstevel@tonic-gate 	char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
28540Sstevel@tonic-gate 
28550Sstevel@tonic-gate 	if ((*authtok = calloc(PASS_MAX+1, sizeof (char))) == NULL)
28560Sstevel@tonic-gate 		return (PAM_BUF_ERR);
28570Sstevel@tonic-gate 
28580Sstevel@tonic-gate 	if (prompt == NULL)
28590Sstevel@tonic-gate 		prompt = dgettext(TEXT_DOMAIN, "password: ");
28600Sstevel@tonic-gate 
28610Sstevel@tonic-gate 	switch (source) {
28620Sstevel@tonic-gate 	case PAM_HANDLE:
28630Sstevel@tonic-gate 
28640Sstevel@tonic-gate 		/* get password from pam handle item list */
28650Sstevel@tonic-gate 
28660Sstevel@tonic-gate 		switch (type) {
28670Sstevel@tonic-gate 		case PAM_AUTHTOK:
28680Sstevel@tonic-gate 		case PAM_OLDAUTHTOK:
28690Sstevel@tonic-gate 
28700Sstevel@tonic-gate 			if ((error = pam_get_item(pamh, type,
28710Sstevel@tonic-gate 			    (void **)&new_password)) != PAM_SUCCESS)
28720Sstevel@tonic-gate 				goto err_ret;
28730Sstevel@tonic-gate 
28740Sstevel@tonic-gate 			if (new_password == NULL || new_password[0] == '\0') {
28750Sstevel@tonic-gate 				free(*authtok);
28760Sstevel@tonic-gate 				*authtok = NULL;
28770Sstevel@tonic-gate 			} else {
28780Sstevel@tonic-gate 				(void) strlcpy(*authtok, new_password,
28790Sstevel@tonic-gate 				    PASS_MAX+1);
28800Sstevel@tonic-gate 			}
28810Sstevel@tonic-gate 			break;
28820Sstevel@tonic-gate 		default:
28830Sstevel@tonic-gate 			__pam_log(LOG_AUTH | LOG_ERR,
28840Sstevel@tonic-gate 			    "__pam_get_authtok() invalid type: %d", type);
28850Sstevel@tonic-gate 			error = PAM_SYMBOL_ERR;
28860Sstevel@tonic-gate 			goto err_ret;
28870Sstevel@tonic-gate 		}
28880Sstevel@tonic-gate 		break;
28890Sstevel@tonic-gate 	case PAM_PROMPT:
28900Sstevel@tonic-gate 
28910Sstevel@tonic-gate 		/*
28920Sstevel@tonic-gate 		 * Prompt for new password and save in pam handle item list
28930Sstevel@tonic-gate 		 * if the that item is not already set.
28940Sstevel@tonic-gate 		 */
28950Sstevel@tonic-gate 
28960Sstevel@tonic-gate 		(void) strncpy(messages[0], prompt, sizeof (messages[0]));
28970Sstevel@tonic-gate 		if ((error = do_conv(pamh, PAM_PROMPT_ECHO_OFF, 1, messages,
28980Sstevel@tonic-gate 		    NULL, &ret_resp)) != PAM_SUCCESS)
28990Sstevel@tonic-gate 			goto err_ret;
29000Sstevel@tonic-gate 
29010Sstevel@tonic-gate 		if (ret_resp->resp == NULL) {
29020Sstevel@tonic-gate 			/* getpass didn't return anything */
29030Sstevel@tonic-gate 			error = PAM_SYSTEM_ERR;
29040Sstevel@tonic-gate 			goto err_ret;
29050Sstevel@tonic-gate 		}
29060Sstevel@tonic-gate 
29070Sstevel@tonic-gate 		/* save the new password if this item was NULL */
29080Sstevel@tonic-gate 		if (type) {
29090Sstevel@tonic-gate 			if ((error = pam_get_item(pamh, type,
29100Sstevel@tonic-gate 			    (void **)&new_password)) != PAM_SUCCESS) {
29110Sstevel@tonic-gate 				free_resp(1, ret_resp);
29120Sstevel@tonic-gate 				goto err_ret;
29130Sstevel@tonic-gate 			}
29140Sstevel@tonic-gate 			if (new_password == NULL)
29150Sstevel@tonic-gate 				(void) pam_set_item(pamh, type, ret_resp->resp);
29160Sstevel@tonic-gate 		}
29170Sstevel@tonic-gate 
29180Sstevel@tonic-gate 		(void) strlcpy(*authtok, ret_resp->resp, PASS_MAX+1);
29190Sstevel@tonic-gate 		free_resp(1, ret_resp);
29200Sstevel@tonic-gate 		break;
29210Sstevel@tonic-gate 	default:
29220Sstevel@tonic-gate 		__pam_log(LOG_AUTH | LOG_ERR,
29230Sstevel@tonic-gate 		    "__pam_get_authtok() invalid source: %d", source);
29240Sstevel@tonic-gate 		error = PAM_SYMBOL_ERR;
29250Sstevel@tonic-gate 		goto err_ret;
29260Sstevel@tonic-gate 	}
29270Sstevel@tonic-gate 
29280Sstevel@tonic-gate 	return (PAM_SUCCESS);
29290Sstevel@tonic-gate 
29300Sstevel@tonic-gate err_ret:
29310Sstevel@tonic-gate 	bzero(*authtok, PASS_MAX+1);
29320Sstevel@tonic-gate 	free(*authtok);
29330Sstevel@tonic-gate 	*authtok = NULL;
29340Sstevel@tonic-gate 	return (error);
29350Sstevel@tonic-gate }
2936