openpam_dispatch.c revision 271947
1272343Sngie/*- 2272343Sngie * Copyright (c) 2002-2003 Networks Associates Technology, Inc. 3272343Sngie * Copyright (c) 2004-2011 Dag-Erling Sm��rgrav 4272343Sngie * All rights reserved. 5272343Sngie * 6272343Sngie * This software was developed for the FreeBSD Project by ThinkSec AS and 7272343Sngie * Network Associates Laboratories, the Security Research Division of 8272343Sngie * Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 9272343Sngie * ("CBOSS"), as part of the DARPA CHATS research program. 10272343Sngie * 11272343Sngie * Redistribution and use in source and binary forms, with or without 12272343Sngie * modification, are permitted provided that the following conditions 13272343Sngie * are met: 14272343Sngie * 1. Redistributions of source code must retain the above copyright 15272343Sngie * notice, this list of conditions and the following disclaimer. 16272343Sngie * 2. Redistributions in binary form must reproduce the above copyright 17272343Sngie * notice, this list of conditions and the following disclaimer in the 18272343Sngie * documentation and/or other materials provided with the distribution. 19272343Sngie * 3. The name of the author may not be used to endorse or promote 20272343Sngie * products derived from this software without specific prior written 21272343Sngie * permission. 22272343Sngie * 23272343Sngie * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24272343Sngie * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25272343Sngie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26272343Sngie * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27272343Sngie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28272343Sngie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29272343Sngie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30272343Sngie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31272343Sngie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32272343Sngie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33272343Sngie * SUCH DAMAGE. 34272343Sngie * 35272343Sngie * $Id: openpam_dispatch.c 807 2014-09-09 09:41:32Z des $ 36272343Sngie */ 37272343Sngie 38272343Sngie#ifdef HAVE_CONFIG_H 39272343Sngie# include "config.h" 40272343Sngie#endif 41272343Sngie 42272343Sngie#include <sys/param.h> 43272343Sngie 44272343Sngie#include <security/pam_appl.h> 45272343Sngie 46272343Sngie#include "openpam_impl.h" 47272343Sngie 48272343Sngie#if !defined(OPENPAM_RELAX_CHECKS) 49272343Sngiestatic void openpam_check_error_code(int, int); 50272343Sngie#else 51272343Sngie#define openpam_check_error_code(a, b) 52272343Sngie#endif /* !defined(OPENPAM_RELAX_CHECKS) */ 53272343Sngie 54272343Sngie/* 55272343Sngie * OpenPAM internal 56272343Sngie * 57272343Sngie * Execute a module chain 58272343Sngie */ 59272343Sngie 60272343Sngieint 61272343Sngieopenpam_dispatch(pam_handle_t *pamh, 62272343Sngie int primitive, 63272343Sngie int flags) 64272343Sngie{ 65272343Sngie pam_chain_t *chain; 66272343Sngie int err, fail, nsuccess, r; 67272343Sngie int debug; 68272343Sngie 69272343Sngie ENTER(); 70272343Sngie if (pamh == NULL) 71272343Sngie RETURNC(PAM_SYSTEM_ERR); 72272343Sngie 73272343Sngie /* prevent recursion */ 74272343Sngie if (pamh->current != NULL) { 75272343Sngie openpam_log(PAM_LOG_ERROR, 76272343Sngie "%s() called while %s::%s() is in progress", 77272343Sngie pam_func_name[primitive], 78272343Sngie pamh->current->module->path, 79272343Sngie pam_sm_func_name[pamh->primitive]); 80272343Sngie RETURNC(PAM_ABORT); 81272343Sngie } 82272343Sngie 83272343Sngie /* pick a chain */ 84272343Sngie switch (primitive) { 85272343Sngie case PAM_SM_AUTHENTICATE: 86272343Sngie case PAM_SM_SETCRED: 87272343Sngie chain = pamh->chains[PAM_AUTH]; 88272343Sngie break; 89272343Sngie case PAM_SM_ACCT_MGMT: 90272343Sngie chain = pamh->chains[PAM_ACCOUNT]; 91272343Sngie break; 92272343Sngie case PAM_SM_OPEN_SESSION: 93272343Sngie case PAM_SM_CLOSE_SESSION: 94272343Sngie chain = pamh->chains[PAM_SESSION]; 95272343Sngie break; 96272343Sngie case PAM_SM_CHAUTHTOK: 97272343Sngie chain = pamh->chains[PAM_PASSWORD]; 98272343Sngie break; 99272343Sngie default: 100272343Sngie RETURNC(PAM_SYSTEM_ERR); 101272343Sngie } 102272343Sngie 103272343Sngie /* execute */ 104272343Sngie err = PAM_SUCCESS; 105272343Sngie fail = nsuccess = 0; 106272343Sngie for (; chain != NULL; chain = chain->next) { 107272343Sngie if (chain->module->func[primitive] == NULL) { 108272343Sngie openpam_log(PAM_LOG_ERROR, "%s: no %s()", 109272343Sngie chain->module->path, pam_sm_func_name[primitive]); 110272343Sngie r = PAM_SYSTEM_ERR; 111272343Sngie } else { 112272343Sngie pamh->primitive = primitive; 113272343Sngie pamh->current = chain; 114272343Sngie debug = (openpam_get_option(pamh, "debug") != NULL); 115272343Sngie if (debug) 116272343Sngie ++openpam_debug; 117272343Sngie openpam_log(PAM_LOG_LIBDEBUG, "calling %s() in %s", 118272343Sngie pam_sm_func_name[primitive], chain->module->path); 119272343Sngie r = (chain->module->func[primitive])(pamh, flags, 120272343Sngie chain->optc, (const char **)chain->optv); 121272343Sngie pamh->current = NULL; 122272343Sngie openpam_log(PAM_LOG_LIBDEBUG, "%s: %s(): %s", 123272343Sngie chain->module->path, pam_sm_func_name[primitive], 124272343Sngie pam_strerror(pamh, r)); 125272343Sngie if (debug) 126272343Sngie --openpam_debug; 127272343Sngie } 128272343Sngie 129272343Sngie if (r == PAM_IGNORE) 130272343Sngie continue; 131272343Sngie if (r == PAM_SUCCESS) { 132272343Sngie ++nsuccess; 133272343Sngie /* 134272343Sngie * For pam_setcred() and pam_chauthtok() with the 135272343Sngie * PAM_PRELIM_CHECK flag, treat "sufficient" as 136272343Sngie * "optional". 137272343Sngie */ 138272343Sngie if ((chain->flag == PAM_SUFFICIENT || 139272343Sngie chain->flag == PAM_BINDING) && !fail && 140272343Sngie primitive != PAM_SM_SETCRED && 141272343Sngie !(primitive == PAM_SM_CHAUTHTOK && 142272343Sngie (flags & PAM_PRELIM_CHECK))) 143272343Sngie break; 144272343Sngie continue; 145272343Sngie } 146272343Sngie 147272343Sngie openpam_check_error_code(primitive, r); 148272343Sngie 149272343Sngie /* 150272343Sngie * Record the return code from the first module to 151272343Sngie * fail. If a required module fails, record the 152272343Sngie * return code from the first required module to fail. 153272343Sngie */ 154272343Sngie if (err == PAM_SUCCESS) 155272343Sngie err = r; 156272343Sngie if ((chain->flag == PAM_REQUIRED || 157272343Sngie chain->flag == PAM_BINDING) && !fail) { 158272343Sngie openpam_log(PAM_LOG_LIBDEBUG, "required module failed"); 159272343Sngie fail = 1; 160272343Sngie err = r; 161272343Sngie } 162272343Sngie 163272343Sngie /* 164272343Sngie * If a requisite module fails, terminate the chain 165272343Sngie * immediately. 166272343Sngie */ 167272343Sngie if (chain->flag == PAM_REQUISITE) { 168272343Sngie openpam_log(PAM_LOG_LIBDEBUG, "requisite module failed"); 169272343Sngie fail = 1; 170272343Sngie break; 171272343Sngie } 172272343Sngie } 173272343Sngie 174272343Sngie if (!fail && err != PAM_NEW_AUTHTOK_REQD) 175272343Sngie err = PAM_SUCCESS; 176272343Sngie 177272343Sngie /* 178272343Sngie * Require the chain to be non-empty, and at least one module 179272343Sngie * in the chain to be successful, so that we don't fail open. 180272343Sngie */ 181272343Sngie if (err == PAM_SUCCESS && nsuccess < 1) { 182272343Sngie openpam_log(PAM_LOG_ERROR, 183272343Sngie "all modules were unsuccessful for %s()", 184272343Sngie pam_sm_func_name[primitive]); 185272343Sngie err = PAM_SYSTEM_ERR; 186272343Sngie } 187272343Sngie 188272343Sngie RETURNC(err); 189272343Sngie} 190272343Sngie 191272343Sngie#if !defined(OPENPAM_RELAX_CHECKS) 192272343Sngiestatic void 193272343Sngieopenpam_check_error_code(int primitive, int r) 194272343Sngie{ 195272343Sngie /* common error codes */ 196272343Sngie if (r == PAM_SUCCESS || 197272343Sngie r == PAM_SYSTEM_ERR || 198272343Sngie r == PAM_SERVICE_ERR || 199272343Sngie r == PAM_BUF_ERR || 200272343Sngie r == PAM_CONV_ERR || 201272343Sngie r == PAM_PERM_DENIED || 202272343Sngie r == PAM_ABORT) 203272343Sngie return; 204272343Sngie 205272343Sngie /* specific error codes */ 206272343Sngie switch (primitive) { 207272343Sngie case PAM_SM_AUTHENTICATE: 208272343Sngie if (r == PAM_AUTH_ERR || 209272343Sngie r == PAM_CRED_INSUFFICIENT || 210272343Sngie r == PAM_AUTHINFO_UNAVAIL || 211272343Sngie r == PAM_USER_UNKNOWN || 212272343Sngie r == PAM_MAXTRIES) 213272343Sngie return; 214272343Sngie break; 215272343Sngie case PAM_SM_SETCRED: 216272343Sngie if (r == PAM_CRED_UNAVAIL || 217272343Sngie r == PAM_CRED_EXPIRED || 218272343Sngie r == PAM_USER_UNKNOWN || 219272343Sngie r == PAM_CRED_ERR) 220272343Sngie return; 221272343Sngie break; 222272343Sngie case PAM_SM_ACCT_MGMT: 223272343Sngie if (r == PAM_USER_UNKNOWN || 224272343Sngie r == PAM_AUTH_ERR || 225272343Sngie r == PAM_NEW_AUTHTOK_REQD || 226272343Sngie r == PAM_ACCT_EXPIRED) 227272343Sngie return; 228272343Sngie break; 229272343Sngie case PAM_SM_OPEN_SESSION: 230272343Sngie case PAM_SM_CLOSE_SESSION: 231272343Sngie if (r == PAM_SESSION_ERR) 232272343Sngie return; 233272343Sngie break; 234272343Sngie case PAM_SM_CHAUTHTOK: 235272343Sngie if (r == PAM_PERM_DENIED || 236272343Sngie r == PAM_AUTHTOK_ERR || 237272343Sngie r == PAM_AUTHTOK_RECOVERY_ERR || 238272343Sngie r == PAM_AUTHTOK_LOCK_BUSY || 239272343Sngie r == PAM_AUTHTOK_DISABLE_AGING || 240272343Sngie r == PAM_TRY_AGAIN) 241272343Sngie return; 242272343Sngie break; 243272343Sngie } 244272343Sngie 245272343Sngie openpam_log(PAM_LOG_ERROR, "%s(): unexpected return value %d", 246272343Sngie pam_sm_func_name[primitive], r); 247272343Sngie} 248272343Sngie#endif /* !defined(OPENPAM_RELAX_CHECKS) */ 249272343Sngie 250272343Sngie/* 251272343Sngie * NODOC 252272343Sngie * 253272343Sngie * Error codes: 254272343Sngie */ 255272343Sngie