openpam_dispatch.c revision 91100
1193326Sed/*- 2193326Sed * Copyright (c) 2002 Networks Associates Technologies, Inc. 3193326Sed * All rights reserved. 4193326Sed * 5193326Sed * This software was developed for the FreeBSD Project by ThinkSec AS and 6193326Sed * NAI Labs, the Security Research Division of Network Associates, Inc. 7193326Sed * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 8193326Sed * DARPA CHATS research program. 9193326Sed * 10193326Sed * Redistribution and use in source and binary forms, with or without 11193326Sed * modification, are permitted provided that the following conditions 12193326Sed * are met: 13193326Sed * 1. Redistributions of source code must retain the above copyright 14193326Sed * notice, this list of conditions and the following disclaimer. 15193326Sed * 2. Redistributions in binary form must reproduce the above copyright 16193326Sed * notice, this list of conditions and the following disclaimer in the 17193326Sed * documentation and/or other materials provided with the distribution. 18193326Sed * 3. The name of the author may not be used to endorse or promote 19193326Sed * products derived from this software without specific prior written 20202379Srdivacky * permission. 21224145Sdim * 22218893Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23193326Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24224145Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25193326Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26193326Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27193326Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28198092Srdivacky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29193326Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30193326Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31193326Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32193326Sed * SUCH DAMAGE. 33193326Sed * 34198092Srdivacky * $Id$ 35207619Srdivacky */ 36193326Sed 37193326Sed#include <sys/param.h> 38198398Srdivacky 39193326Sed#include <security/pam_appl.h> 40210299Sed 41193326Sed#include "openpam_impl.h" 42193326Sed 43193326Sed#if !defined(OPENPAM_RELAX_CHECKS) 44212904Sdimstatic void _openpam_check_error_code(int, int); 45193326Sed#else 46193326Sed#define _openpam_check_error_code(a, b) 47221345Sdim#endif /* !defined(OPENPAM_RELAX_CHECKS) */ 48198092Srdivacky 49193326Sed/* 50218893Sdim * OpenPAM internal 51193326Sed * 52193326Sed * Execute a module chain 53193326Sed */ 54193326Sed 55193326Sedint 56193326Sedopenpam_dispatch(pam_handle_t *pamh, 57193326Sed int primitive, 58193326Sed int flags) 59193326Sed{ 60193326Sed pam_chain_t *chain; 61193326Sed int err, fail, r; 62204643Srdivacky 63193326Sed if (pamh == NULL) 64193326Sed return (PAM_SYSTEM_ERR); 65193326Sed 66193326Sed /* prevent recursion */ 67193326Sed if (pamh->current != NULL) { 68224145Sdim openpam_log(PAM_LOG_ERROR, "indirect recursion"); 69193326Sed return (PAM_ABORT); 70193326Sed } 71193326Sed 72193326Sed /* pick a chain */ 73193326Sed switch (primitive) { 74193326Sed case PAM_SM_AUTHENTICATE: 75208600Srdivacky case PAM_SM_SETCRED: 76212904Sdim chain = pamh->chains[PAM_AUTH]; 77218893Sdim break; 78218893Sdim case PAM_SM_ACCT_MGMT: 79193326Sed chain = pamh->chains[PAM_ACCOUNT]; 80210299Sed break; 81210299Sed case PAM_SM_OPEN_SESSION: 82210299Sed case PAM_SM_CLOSE_SESSION: 83210299Sed chain = pamh->chains[PAM_SESSION]; 84210299Sed break; 85210299Sed case PAM_SM_CHAUTHTOK: 86210299Sed chain = pamh->chains[PAM_PASSWORD]; 87212904Sdim break; 88212904Sdim default: 89212904Sdim return (PAM_SYSTEM_ERR); 90212904Sdim } 91210299Sed 92212904Sdim /* execute */ 93210299Sed for (err = fail = 0; chain != NULL; chain = chain->next) { 94210299Sed openpam_log(PAM_LOG_DEBUG, "calling %s() in %s", 95210299Sed _pam_sm_func_name[primitive], chain->module->path); 96210299Sed if (chain->module->func[primitive] == NULL) { 97210299Sed openpam_log(PAM_LOG_ERROR, "%s: no %s()", 98212904Sdim chain->module->path, _pam_sm_func_name[primitive]); 99212904Sdim continue; 100212904Sdim } else { 101212904Sdim pamh->current = chain; 102212904Sdim r = (chain->module->func[primitive])(pamh, flags, 103210299Sed chain->optc, (const char **)chain->optv); 104210299Sed pamh->current = NULL; 105218893Sdim openpam_log(PAM_LOG_DEBUG, "%s: %s(): %s", 106218893Sdim chain->module->path, _pam_sm_func_name[primitive], 107218893Sdim pam_strerror(pamh, r)); 108218893Sdim } 109218893Sdim 110218893Sdim if (r == PAM_IGNORE) 111218893Sdim continue; 112218893Sdim if (r == PAM_SUCCESS) { 113218893Sdim /* 114218893Sdim * For pam_setcred(), treat "sufficient" as 115218893Sdim * "optional". 116218893Sdim * 117218893Sdim * Note that Solaris libpam does not terminate 118218893Sdim * the chain here if a required module has 119218893Sdim * previously failed. I'm not sure why. 120218893Sdim */ 121218893Sdim if (chain->flag == PAM_SUFFICIENT && 122218893Sdim primitive != PAM_SM_SETCRED) 123218893Sdim break; 124218893Sdim continue; 125218893Sdim } 126218893Sdim 127212904Sdim _openpam_check_error_code(primitive, r); 128212904Sdim 129212904Sdim /* 130212904Sdim * Record the return code from the first module to 131210299Sed * fail. If a required module fails, record the 132212904Sdim * return code from the first required module to fail. 133212904Sdim */ 134212904Sdim if (err == 0) 135212904Sdim err = r; 136212904Sdim if (chain->flag == PAM_REQUIRED && !fail) { 137212904Sdim openpam_log(PAM_LOG_DEBUG, "required module failed"); 138210299Sed fail = 1; 139210299Sed err = r; 140210299Sed } 141210299Sed 142210299Sed /* 143210299Sed * If a requisite module fails, terminate the chain 144210299Sed * immediately. 145210299Sed */ 146210299Sed if (chain->flag == PAM_REQUISITE) { 147210299Sed openpam_log(PAM_LOG_DEBUG, "requisite module failed"); 148210299Sed fail = 1; 149210299Sed break; 150210299Sed } 151210299Sed } 152210299Sed 153210299Sed if (!fail) 154210299Sed err = PAM_SUCCESS; 155210299Sed openpam_log(PAM_LOG_DEBUG, "returning: %s", pam_strerror(pamh, err)); 156210299Sed return (err); 157210299Sed} 158212904Sdim 159212904Sdim#if !defined(OPENPAM_RELAX_CHECKS) 160212904Sdimstatic void 161212904Sdim_openpam_check_error_code(int primitive, int r) 162212904Sdim{ 163212904Sdim /* common error codes */ 164212904Sdim if (r == PAM_SUCCESS || 165212904Sdim r == PAM_SERVICE_ERR || 166212904Sdim r == PAM_BUF_ERR || 167212904Sdim r == PAM_CONV_ERR || 168212904Sdim r == PAM_PERM_DENIED || 169210299Sed r == PAM_ABORT) 170210299Sed return; 171210299Sed 172210299Sed /* specific error codes */ 173210299Sed switch (primitive) { 174210299Sed case PAM_SM_AUTHENTICATE: 175210299Sed if (r == PAM_AUTH_ERR || 176210299Sed r == PAM_CRED_INSUFFICIENT || 177212904Sdim r == PAM_AUTHINFO_UNAVAIL || 178212904Sdim r == PAM_USER_UNKNOWN || 179212904Sdim r == PAM_MAXTRIES) 180212904Sdim return; 181210299Sed break; 182212904Sdim case PAM_SM_SETCRED: 183210299Sed if (r == PAM_CRED_UNAVAIL || 184212904Sdim r == PAM_CRED_EXPIRED || 185224145Sdim r == PAM_USER_UNKNOWN || 186224145Sdim r == PAM_CRED_ERR) 187210299Sed return; 188224145Sdim break; 189224145Sdim case PAM_SM_ACCT_MGMT: 190224145Sdim if (r == PAM_USER_UNKNOWN || 191224145Sdim r == PAM_AUTH_ERR || 192224145Sdim r == PAM_NEW_AUTHTOK_REQD || 193224145Sdim r == PAM_ACCT_EXPIRED) 194224145Sdim return; 195224145Sdim break; 196210299Sed case PAM_SM_OPEN_SESSION: 197224145Sdim case PAM_SM_CLOSE_SESSION: 198224145Sdim if (r == PAM_SESSION_ERR) 199224145Sdim return; 200224145Sdim break; 201224145Sdim case PAM_SM_CHAUTHTOK: 202224145Sdim if (r == PAM_PERM_DENIED || 203224145Sdim r == PAM_AUTHTOK_ERR || 204224145Sdim r == PAM_AUTHTOK_RECOVERY_ERR || 205224145Sdim r == PAM_AUTHTOK_LOCK_BUSY || 206224145Sdim r == PAM_AUTHTOK_DISABLE_AGING) 207224145Sdim return; 208224145Sdim break; 209224145Sdim } 210224145Sdim 211224145Sdim openpam_log(PAM_LOG_ERROR, "%s(): unexpected return value %d", 212224145Sdim _pam_sm_func_name[primitive], r); 213224145Sdim} 214224145Sdim#endif /* !defined(OPENPAM_RELAX_CHECKS) */ 215224145Sdim 216224145Sdim/* 217224145Sdim * NODOC 218224145Sdim * 219210299Sed * Error codes: 220210299Sed */ 221210299Sed