openpam_dispatch.c revision 99158
191094Sdes/*- 292289Sdes * Copyright (c) 2002 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 * 3499158Sdes * $P4: //depot/projects/openpam/lib/openpam_dispatch.c#17 $ 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; 6291094Sdes 6391094Sdes if (pamh == NULL) 6491094Sdes return (PAM_SYSTEM_ERR); 6591094Sdes 6691094Sdes /* prevent recursion */ 6791094Sdes if (pamh->current != NULL) { 6891094Sdes openpam_log(PAM_LOG_ERROR, "indirect recursion"); 6991094Sdes return (PAM_ABORT); 7091094Sdes } 7191094Sdes 7291094Sdes /* pick a chain */ 7391094Sdes switch (primitive) { 7491094Sdes case PAM_SM_AUTHENTICATE: 7591094Sdes case PAM_SM_SETCRED: 7691094Sdes chain = pamh->chains[PAM_AUTH]; 7791094Sdes break; 7891094Sdes case PAM_SM_ACCT_MGMT: 7991094Sdes chain = pamh->chains[PAM_ACCOUNT]; 8091094Sdes break; 8191094Sdes case PAM_SM_OPEN_SESSION: 8291094Sdes case PAM_SM_CLOSE_SESSION: 8391094Sdes chain = pamh->chains[PAM_SESSION]; 8491094Sdes break; 8591094Sdes case PAM_SM_CHAUTHTOK: 8691094Sdes chain = pamh->chains[PAM_PASSWORD]; 8791094Sdes break; 8891094Sdes default: 8991094Sdes return (PAM_SYSTEM_ERR); 9091094Sdes } 9191094Sdes 9291094Sdes /* execute */ 9391094Sdes for (err = fail = 0; chain != NULL; chain = chain->next) { 9491097Sdes openpam_log(PAM_LOG_DEBUG, "calling %s() in %s", 9591097Sdes _pam_sm_func_name[primitive], chain->module->path); 9691094Sdes if (chain->module->func[primitive] == NULL) { 9791094Sdes openpam_log(PAM_LOG_ERROR, "%s: no %s()", 9891094Sdes chain->module->path, _pam_sm_func_name[primitive]); 9991094Sdes continue; 10091094Sdes } else { 10191094Sdes pamh->current = chain; 10291094Sdes r = (chain->module->func[primitive])(pamh, flags, 10391094Sdes chain->optc, (const char **)chain->optv); 10491094Sdes pamh->current = NULL; 10591094Sdes openpam_log(PAM_LOG_DEBUG, "%s: %s(): %s", 10691094Sdes chain->module->path, _pam_sm_func_name[primitive], 10791094Sdes pam_strerror(pamh, r)); 10891094Sdes } 10991094Sdes 11091094Sdes if (r == PAM_IGNORE) 11191094Sdes continue; 11291094Sdes if (r == PAM_SUCCESS) { 11391094Sdes /* 11491684Sdes * For pam_setcred() and pam_chauthtok() with the 11591684Sdes * PAM_PRELIM_CHECK flag, treat "sufficient" as 11691094Sdes * "optional". 11791094Sdes */ 11899158Sdes if ((chain->flag == PAM_SUFFICIENT || 11999158Sdes chain->flag == PAM_BINDING) && !fail && 12091684Sdes primitive != PAM_SM_SETCRED && 12199158Sdes !(primitive == PAM_SM_CHAUTHTOK && 12299158Sdes (flags & PAM_PRELIM_CHECK))) 12391094Sdes break; 12491097Sdes continue; 12591094Sdes } 12691094Sdes 12791094Sdes _openpam_check_error_code(primitive, r); 12891094Sdes 12991094Sdes /* 13091094Sdes * Record the return code from the first module to 13191094Sdes * fail. If a required module fails, record the 13291094Sdes * return code from the first required module to fail. 13391094Sdes */ 13491094Sdes if (err == 0) 13591094Sdes err = r; 13699158Sdes if ((chain->flag == PAM_REQUIRED || 13799158Sdes chain->flag == PAM_BINDING) && !fail) { 13891097Sdes openpam_log(PAM_LOG_DEBUG, "required module failed"); 13991094Sdes fail = 1; 14091094Sdes err = r; 14191094Sdes } 14291094Sdes 14391094Sdes /* 14491094Sdes * If a requisite module fails, terminate the chain 14591094Sdes * immediately. 14691094Sdes */ 14791094Sdes if (chain->flag == PAM_REQUISITE) { 14891097Sdes openpam_log(PAM_LOG_DEBUG, "requisite module failed"); 14991094Sdes fail = 1; 15091094Sdes break; 15191094Sdes } 15291094Sdes } 15391094Sdes 15499158Sdes if (!fail && err != PAM_NEW_AUTHTOK_REQD) 15591097Sdes err = PAM_SUCCESS; 15691097Sdes openpam_log(PAM_LOG_DEBUG, "returning: %s", pam_strerror(pamh, err)); 15791097Sdes return (err); 15891094Sdes} 15991094Sdes 16091094Sdes#if !defined(OPENPAM_RELAX_CHECKS) 16191094Sdesstatic void 16291094Sdes_openpam_check_error_code(int primitive, int r) 16391094Sdes{ 16491094Sdes /* common error codes */ 16591097Sdes if (r == PAM_SUCCESS || 16691097Sdes r == PAM_SERVICE_ERR || 16791094Sdes r == PAM_BUF_ERR || 16891094Sdes r == PAM_CONV_ERR || 16991097Sdes r == PAM_PERM_DENIED || 17091097Sdes r == PAM_ABORT) 17191094Sdes return; 17291094Sdes 17391094Sdes /* specific error codes */ 17491094Sdes switch (primitive) { 17591094Sdes case PAM_SM_AUTHENTICATE: 17691094Sdes if (r == PAM_AUTH_ERR || 17791094Sdes r == PAM_CRED_INSUFFICIENT || 17891094Sdes r == PAM_AUTHINFO_UNAVAIL || 17991094Sdes r == PAM_USER_UNKNOWN || 18091094Sdes r == PAM_MAXTRIES) 18191094Sdes return; 18291094Sdes break; 18391094Sdes case PAM_SM_SETCRED: 18491094Sdes if (r == PAM_CRED_UNAVAIL || 18591094Sdes r == PAM_CRED_EXPIRED || 18691094Sdes r == PAM_USER_UNKNOWN || 18791094Sdes r == PAM_CRED_ERR) 18891094Sdes return; 18991094Sdes break; 19091094Sdes case PAM_SM_ACCT_MGMT: 19191094Sdes if (r == PAM_USER_UNKNOWN || 19291094Sdes r == PAM_AUTH_ERR || 19391094Sdes r == PAM_NEW_AUTHTOK_REQD || 19491094Sdes r == PAM_ACCT_EXPIRED) 19591094Sdes return; 19691094Sdes break; 19791094Sdes case PAM_SM_OPEN_SESSION: 19891094Sdes case PAM_SM_CLOSE_SESSION: 19991094Sdes if (r == PAM_SESSION_ERR) 20091094Sdes return; 20191094Sdes break; 20291094Sdes case PAM_SM_CHAUTHTOK: 20391094Sdes if (r == PAM_PERM_DENIED || 20491094Sdes r == PAM_AUTHTOK_ERR || 20591094Sdes r == PAM_AUTHTOK_RECOVERY_ERR || 20691094Sdes r == PAM_AUTHTOK_LOCK_BUSY || 20791684Sdes r == PAM_AUTHTOK_DISABLE_AGING || 20891684Sdes r == PAM_TRY_AGAIN) 20991094Sdes return; 21091094Sdes break; 21191094Sdes } 21291094Sdes 21391094Sdes openpam_log(PAM_LOG_ERROR, "%s(): unexpected return value %d", 21491094Sdes _pam_sm_func_name[primitive], r); 21591094Sdes} 21691094Sdes#endif /* !defined(OPENPAM_RELAX_CHECKS) */ 21791100Sdes 21891100Sdes/* 21991100Sdes * NODOC 22091100Sdes * 22191100Sdes * Error codes: 22291100Sdes */ 223