openpam_dispatch.c revision 91684
1239674Srwatson/*- 2239674Srwatson * Copyright (c) 2002 Networks Associates Technologies, Inc. 3239674Srwatson * All rights reserved. 4239674Srwatson * 5239674Srwatson * This software was developed for the FreeBSD Project by ThinkSec AS and 6239674Srwatson * NAI Labs, the Security Research Division of Network Associates, Inc. 7239674Srwatson * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 8239674Srwatson * DARPA CHATS research program. 9239674Srwatson * 10239674Srwatson * Redistribution and use in source and binary forms, with or without 11239674Srwatson * modification, are permitted provided that the following conditions 12239674Srwatson * are met: 13239674Srwatson * 1. Redistributions of source code must retain the above copyright 14239674Srwatson * notice, this list of conditions and the following disclaimer. 15239674Srwatson * 2. Redistributions in binary form must reproduce the above copyright 16239674Srwatson * notice, this list of conditions and the following disclaimer in the 17239674Srwatson * documentation and/or other materials provided with the distribution. 18239674Srwatson * 3. The name of the author may not be used to endorse or promote 19239674Srwatson * products derived from this software without specific prior written 20239674Srwatson * permission. 21239674Srwatson * 22239674Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23239674Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24239674Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25239674Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26239674Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27239674Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28239674Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29239674Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30239674Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31239674Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32239674Srwatson * SUCH DAMAGE. 33239674Srwatson * 34239674Srwatson * $P4: //depot/projects/openpam/lib/openpam_dispatch.c#13 $ 35239674Srwatson */ 36239674Srwatson 37239674Srwatson#include <sys/param.h> 38239674Srwatson 39239674Srwatson#include <security/pam_appl.h> 40239674Srwatson 41239674Srwatson#include "openpam_impl.h" 42239674Srwatson 43239674Srwatson#if !defined(OPENPAM_RELAX_CHECKS) 44239674Srwatsonstatic void _openpam_check_error_code(int, int); 45239674Srwatson#else 46239674Srwatson#define _openpam_check_error_code(a, b) 47239674Srwatson#endif /* !defined(OPENPAM_RELAX_CHECKS) */ 48239674Srwatson 49239674Srwatson/* 50239674Srwatson * OpenPAM internal 51239674Srwatson * 52239674Srwatson * Execute a module chain 53239674Srwatson */ 54239674Srwatson 55239674Srwatsonint 56239674Srwatsonopenpam_dispatch(pam_handle_t *pamh, 57239674Srwatson int primitive, 58239674Srwatson int flags) 59256114Sjmg{ 60256114Sjmg pam_chain_t *chain; 61256114Sjmg int err, fail, r; 62239674Srwatson 63256114Sjmg if (pamh == NULL) 64239674Srwatson return (PAM_SYSTEM_ERR); 65239674Srwatson 66239674Srwatson /* prevent recursion */ 67239674Srwatson if (pamh->current != NULL) { 68239674Srwatson openpam_log(PAM_LOG_ERROR, "indirect recursion"); 69239674Srwatson return (PAM_ABORT); 70239674Srwatson } 71239674Srwatson 72239674Srwatson /* pick a chain */ 73239674Srwatson switch (primitive) { 74239674Srwatson case PAM_SM_AUTHENTICATE: 75239674Srwatson case PAM_SM_SETCRED: 76239674Srwatson chain = pamh->chains[PAM_AUTH]; 77239674Srwatson break; 78239674Srwatson case PAM_SM_ACCT_MGMT: 79239674Srwatson chain = pamh->chains[PAM_ACCOUNT]; 80239674Srwatson break; 81239674Srwatson case PAM_SM_OPEN_SESSION: 82239677Sjoel case PAM_SM_CLOSE_SESSION: 83239674Srwatson chain = pamh->chains[PAM_SESSION]; 84239674Srwatson break; 85239674Srwatson case PAM_SM_CHAUTHTOK: 86239674Srwatson chain = pamh->chains[PAM_PASSWORD]; 87239674Srwatson break; 88239674Srwatson default: 89239674Srwatson return (PAM_SYSTEM_ERR); 90239674Srwatson } 91239674Srwatson 92239674Srwatson /* execute */ 93239674Srwatson for (err = fail = 0; chain != NULL; chain = chain->next) { 94239674Srwatson openpam_log(PAM_LOG_DEBUG, "calling %s() in %s", 95239674Srwatson _pam_sm_func_name[primitive], chain->module->path); 96239674Srwatson if (chain->module->func[primitive] == NULL) { 97239674Srwatson openpam_log(PAM_LOG_ERROR, "%s: no %s()", 98239674Srwatson chain->module->path, _pam_sm_func_name[primitive]); 99239674Srwatson continue; 100239674Srwatson } else { 101239674Srwatson pamh->current = chain; 102239674Srwatson r = (chain->module->func[primitive])(pamh, flags, 103239674Srwatson chain->optc, (const char **)chain->optv); 104239674Srwatson pamh->current = NULL; 105239674Srwatson openpam_log(PAM_LOG_DEBUG, "%s: %s(): %s", 106239674Srwatson chain->module->path, _pam_sm_func_name[primitive], 107239674Srwatson pam_strerror(pamh, r)); 108239674Srwatson } 109239674Srwatson 110239674Srwatson if (r == PAM_IGNORE) 111239674Srwatson continue; 112239674Srwatson if (r == PAM_SUCCESS) { 113239674Srwatson /* 114239674Srwatson * For pam_setcred() and pam_chauthtok() with the 115239674Srwatson * PAM_PRELIM_CHECK flag, treat "sufficient" as 116239674Srwatson * "optional". 117239674Srwatson * 118239674Srwatson * Note that Solaris libpam does not terminate 119239674Srwatson * the chain here if a required module has 120239674Srwatson * previously failed. I'm not sure why. 121239674Srwatson */ 122239674Srwatson if (chain->flag == PAM_SUFFICIENT && 123239674Srwatson primitive != PAM_SM_SETCRED && 124239674Srwatson (primitive != PAM_SM_CHAUTHTOK || 125239674Srwatson !(flags & PAM_PRELIM_CHECK))) 126239674Srwatson break; 127239674Srwatson continue; 128239674Srwatson } 129239674Srwatson 130239674Srwatson _openpam_check_error_code(primitive, r); 131239674Srwatson 132239674Srwatson /* 133239674Srwatson * Record the return code from the first module to 134239674Srwatson * fail. If a required module fails, record the 135239674Srwatson * return code from the first required module to fail. 136239674Srwatson */ 137239674Srwatson if (err == 0) 138239674Srwatson err = r; 139239674Srwatson if (chain->flag == PAM_REQUIRED && !fail) { 140239674Srwatson openpam_log(PAM_LOG_DEBUG, "required module failed"); 141239674Srwatson fail = 1; 142239674Srwatson err = r; 143239674Srwatson } 144239674Srwatson 145239674Srwatson /* 146239674Srwatson * If a requisite module fails, terminate the chain 147239674Srwatson * immediately. 148239674Srwatson */ 149239674Srwatson if (chain->flag == PAM_REQUISITE) { 150239674Srwatson openpam_log(PAM_LOG_DEBUG, "requisite module failed"); 151239674Srwatson fail = 1; 152239674Srwatson break; 153239674Srwatson } 154239674Srwatson } 155239674Srwatson 156 if (!fail) 157 err = PAM_SUCCESS; 158 openpam_log(PAM_LOG_DEBUG, "returning: %s", pam_strerror(pamh, err)); 159 return (err); 160} 161 162#if !defined(OPENPAM_RELAX_CHECKS) 163static void 164_openpam_check_error_code(int primitive, int r) 165{ 166 /* common error codes */ 167 if (r == PAM_SUCCESS || 168 r == PAM_SERVICE_ERR || 169 r == PAM_BUF_ERR || 170 r == PAM_CONV_ERR || 171 r == PAM_PERM_DENIED || 172 r == PAM_ABORT) 173 return; 174 175 /* specific error codes */ 176 switch (primitive) { 177 case PAM_SM_AUTHENTICATE: 178 if (r == PAM_AUTH_ERR || 179 r == PAM_CRED_INSUFFICIENT || 180 r == PAM_AUTHINFO_UNAVAIL || 181 r == PAM_USER_UNKNOWN || 182 r == PAM_MAXTRIES) 183 return; 184 break; 185 case PAM_SM_SETCRED: 186 if (r == PAM_CRED_UNAVAIL || 187 r == PAM_CRED_EXPIRED || 188 r == PAM_USER_UNKNOWN || 189 r == PAM_CRED_ERR) 190 return; 191 break; 192 case PAM_SM_ACCT_MGMT: 193 if (r == PAM_USER_UNKNOWN || 194 r == PAM_AUTH_ERR || 195 r == PAM_NEW_AUTHTOK_REQD || 196 r == PAM_ACCT_EXPIRED) 197 return; 198 break; 199 case PAM_SM_OPEN_SESSION: 200 case PAM_SM_CLOSE_SESSION: 201 if (r == PAM_SESSION_ERR) 202 return; 203 break; 204 case PAM_SM_CHAUTHTOK: 205 if (r == PAM_PERM_DENIED || 206 r == PAM_AUTHTOK_ERR || 207 r == PAM_AUTHTOK_RECOVERY_ERR || 208 r == PAM_AUTHTOK_LOCK_BUSY || 209 r == PAM_AUTHTOK_DISABLE_AGING || 210 r == PAM_TRY_AGAIN) 211 return; 212 break; 213 } 214 215 openpam_log(PAM_LOG_ERROR, "%s(): unexpected return value %d", 216 _pam_sm_func_name[primitive], r); 217} 218#endif /* !defined(OPENPAM_RELAX_CHECKS) */ 219 220/* 221 * NODOC 222 * 223 * Error codes: 224 */ 225