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