openpam_dispatch.c revision 115619
191094Sdes/*- 2115619Sdes * Copyright (c) 2002-2003 Networks Associates Technology, Inc. 391094Sdes * All rights reserved. 491094Sdes * 591094Sdes * This software was developed for the FreeBSD Project by ThinkSec AS and 699158Sdes * Network Associates Laboratories, the Security Research Division of 799158Sdes * Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 899158Sdes * ("CBOSS"), as part of the DARPA CHATS research program. 991094Sdes * 1091094Sdes * Redistribution and use in source and binary forms, with or without 1191094Sdes * modification, are permitted provided that the following conditions 1291094Sdes * are met: 1391094Sdes * 1. Redistributions of source code must retain the above copyright 1491094Sdes * notice, this list of conditions and the following disclaimer. 1591094Sdes * 2. Redistributions in binary form must reproduce the above copyright 1691094Sdes * notice, this list of conditions and the following disclaimer in the 1791094Sdes * documentation and/or other materials provided with the distribution. 1891094Sdes * 3. The name of the author may not be used to endorse or promote 1991094Sdes * products derived from this software without specific prior written 2091094Sdes * permission. 2191094Sdes * 2291094Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2391094Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2491094Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2591094Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2691094Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2791094Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2891094Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2991094Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3091094Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3191094Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3291094Sdes * SUCH DAMAGE. 3391094Sdes * 34115619Sdes * $P4: //depot/projects/openpam/lib/openpam_dispatch.c#21 $ 3591094Sdes */ 3691094Sdes 3791094Sdes#include <sys/param.h> 3891094Sdes 3991094Sdes#include <security/pam_appl.h> 4091094Sdes 4191094Sdes#include "openpam_impl.h" 4291094Sdes 4391094Sdes#if !defined(OPENPAM_RELAX_CHECKS) 4491094Sdesstatic void _openpam_check_error_code(int, int); 4591094Sdes#else 4691094Sdes#define _openpam_check_error_code(a, b) 4791094Sdes#endif /* !defined(OPENPAM_RELAX_CHECKS) */ 4891094Sdes 4991094Sdes/* 5091100Sdes * OpenPAM internal 5191100Sdes * 5291094Sdes * Execute a module chain 5391094Sdes */ 5491094Sdes 5591094Sdesint 5691094Sdesopenpam_dispatch(pam_handle_t *pamh, 5791094Sdes int primitive, 5891094Sdes int flags) 5991094Sdes{ 6091094Sdes pam_chain_t *chain; 6191094Sdes int err, fail, r; 62114536Sdes#ifdef DEBUG 63114536Sdes int debug; 64114536Sdes#endif 6591094Sdes 66107937Sdes ENTER(); 6791094Sdes if (pamh == NULL) 68107937Sdes RETURNC(PAM_SYSTEM_ERR); 6991094Sdes 7091094Sdes /* prevent recursion */ 7191094Sdes if (pamh->current != NULL) { 72107937Sdes openpam_log(PAM_LOG_ERROR, 73107937Sdes "%s() called while %s::%s() is in progress", 74107937Sdes _pam_func_name[primitive], 75107937Sdes pamh->current->module->path, 76107937Sdes _pam_sm_func_name[pamh->primitive]); 77107937Sdes RETURNC(PAM_ABORT); 7891094Sdes } 7991094Sdes 8091094Sdes /* pick a chain */ 8191094Sdes switch (primitive) { 8291094Sdes case PAM_SM_AUTHENTICATE: 8391094Sdes case PAM_SM_SETCRED: 8491094Sdes chain = pamh->chains[PAM_AUTH]; 8591094Sdes break; 8691094Sdes case PAM_SM_ACCT_MGMT: 8791094Sdes chain = pamh->chains[PAM_ACCOUNT]; 8891094Sdes break; 8991094Sdes case PAM_SM_OPEN_SESSION: 9091094Sdes case PAM_SM_CLOSE_SESSION: 9191094Sdes chain = pamh->chains[PAM_SESSION]; 9291094Sdes break; 9391094Sdes case PAM_SM_CHAUTHTOK: 9491094Sdes chain = pamh->chains[PAM_PASSWORD]; 9591094Sdes break; 9691094Sdes default: 97107937Sdes RETURNC(PAM_SYSTEM_ERR); 9891094Sdes } 9991094Sdes 10091094Sdes /* execute */ 10191094Sdes for (err = fail = 0; chain != NULL; chain = chain->next) { 10291094Sdes if (chain->module->func[primitive] == NULL) { 10391094Sdes openpam_log(PAM_LOG_ERROR, "%s: no %s()", 10491094Sdes chain->module->path, _pam_sm_func_name[primitive]); 10591094Sdes continue; 10691094Sdes } else { 107107937Sdes pamh->primitive = primitive; 10891094Sdes pamh->current = chain; 109114536Sdes#ifdef DEBUG 110114536Sdes debug = (openpam_get_option(pamh, "debug") != NULL); 111114536Sdes if (debug) 112114536Sdes ++_openpam_debug; 113114536Sdes openpam_log(PAM_LOG_DEBUG, "calling %s() in %s", 114114536Sdes _pam_sm_func_name[primitive], chain->module->path); 115114536Sdes#endif 11691094Sdes r = (chain->module->func[primitive])(pamh, flags, 11791094Sdes chain->optc, (const char **)chain->optv); 11891094Sdes pamh->current = NULL; 119114536Sdes#ifdef DEBUG 12091094Sdes openpam_log(PAM_LOG_DEBUG, "%s: %s(): %s", 12191094Sdes chain->module->path, _pam_sm_func_name[primitive], 12291094Sdes pam_strerror(pamh, r)); 123114536Sdes if (debug) 124114536Sdes --_openpam_debug; 125114536Sdes#endif 12691094Sdes } 12791094Sdes 12891094Sdes if (r == PAM_IGNORE) 12991094Sdes continue; 13091094Sdes if (r == PAM_SUCCESS) { 13191094Sdes /* 13291684Sdes * For pam_setcred() and pam_chauthtok() with the 13391684Sdes * PAM_PRELIM_CHECK flag, treat "sufficient" as 13491094Sdes * "optional". 13591094Sdes */ 13699158Sdes if ((chain->flag == PAM_SUFFICIENT || 13799158Sdes chain->flag == PAM_BINDING) && !fail && 13891684Sdes primitive != PAM_SM_SETCRED && 13999158Sdes !(primitive == PAM_SM_CHAUTHTOK && 14099158Sdes (flags & PAM_PRELIM_CHECK))) 14191094Sdes break; 14291097Sdes continue; 14391094Sdes } 14491094Sdes 14591094Sdes _openpam_check_error_code(primitive, r); 14691094Sdes 14791094Sdes /* 14891094Sdes * Record the return code from the first module to 14991094Sdes * fail. If a required module fails, record the 15091094Sdes * return code from the first required module to fail. 15191094Sdes */ 15291094Sdes if (err == 0) 15391094Sdes err = r; 15499158Sdes if ((chain->flag == PAM_REQUIRED || 15599158Sdes chain->flag == PAM_BINDING) && !fail) { 15691097Sdes openpam_log(PAM_LOG_DEBUG, "required module failed"); 15791094Sdes fail = 1; 15891094Sdes err = r; 15991094Sdes } 16091094Sdes 16191094Sdes /* 16291094Sdes * If a requisite module fails, terminate the chain 16391094Sdes * immediately. 16491094Sdes */ 16591094Sdes if (chain->flag == PAM_REQUISITE) { 16691097Sdes openpam_log(PAM_LOG_DEBUG, "requisite module failed"); 16791094Sdes fail = 1; 16891094Sdes break; 16991094Sdes } 17091094Sdes } 17191094Sdes 17299158Sdes if (!fail && err != PAM_NEW_AUTHTOK_REQD) 17391097Sdes err = PAM_SUCCESS; 174107937Sdes RETURNC(err); 17591094Sdes} 17691094Sdes 17791094Sdes#if !defined(OPENPAM_RELAX_CHECKS) 17891094Sdesstatic void 17991094Sdes_openpam_check_error_code(int primitive, int r) 18091094Sdes{ 18191094Sdes /* common error codes */ 18291097Sdes if (r == PAM_SUCCESS || 18391097Sdes r == PAM_SERVICE_ERR || 18491094Sdes r == PAM_BUF_ERR || 18591094Sdes r == PAM_CONV_ERR || 18691097Sdes r == PAM_PERM_DENIED || 18791097Sdes r == PAM_ABORT) 18891094Sdes return; 18991094Sdes 19091094Sdes /* specific error codes */ 19191094Sdes switch (primitive) { 19291094Sdes case PAM_SM_AUTHENTICATE: 19391094Sdes if (r == PAM_AUTH_ERR || 19491094Sdes r == PAM_CRED_INSUFFICIENT || 19591094Sdes r == PAM_AUTHINFO_UNAVAIL || 19691094Sdes r == PAM_USER_UNKNOWN || 19791094Sdes r == PAM_MAXTRIES) 19891094Sdes return; 19991094Sdes break; 20091094Sdes case PAM_SM_SETCRED: 20191094Sdes if (r == PAM_CRED_UNAVAIL || 20291094Sdes r == PAM_CRED_EXPIRED || 20391094Sdes r == PAM_USER_UNKNOWN || 20491094Sdes r == PAM_CRED_ERR) 20591094Sdes return; 20691094Sdes break; 20791094Sdes case PAM_SM_ACCT_MGMT: 20891094Sdes if (r == PAM_USER_UNKNOWN || 20991094Sdes r == PAM_AUTH_ERR || 21091094Sdes r == PAM_NEW_AUTHTOK_REQD || 21191094Sdes r == PAM_ACCT_EXPIRED) 21291094Sdes return; 21391094Sdes break; 21491094Sdes case PAM_SM_OPEN_SESSION: 21591094Sdes case PAM_SM_CLOSE_SESSION: 21691094Sdes if (r == PAM_SESSION_ERR) 21791094Sdes return; 21891094Sdes break; 21991094Sdes case PAM_SM_CHAUTHTOK: 22091094Sdes if (r == PAM_PERM_DENIED || 22191094Sdes r == PAM_AUTHTOK_ERR || 22291094Sdes r == PAM_AUTHTOK_RECOVERY_ERR || 22391094Sdes r == PAM_AUTHTOK_LOCK_BUSY || 22491684Sdes r == PAM_AUTHTOK_DISABLE_AGING || 22591684Sdes r == PAM_TRY_AGAIN) 22691094Sdes return; 22791094Sdes break; 22891094Sdes } 22991094Sdes 23091094Sdes openpam_log(PAM_LOG_ERROR, "%s(): unexpected return value %d", 23191094Sdes _pam_sm_func_name[primitive], r); 23291094Sdes} 23391094Sdes#endif /* !defined(OPENPAM_RELAX_CHECKS) */ 23491100Sdes 23591100Sdes/* 23691100Sdes * NODOC 23791100Sdes * 23891100Sdes * Error codes: 23991100Sdes */ 240