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