openpam_dispatch.c revision 91684
180709Sjake/*- 280709Sjake * Copyright (c) 2002 Networks Associates Technologies, Inc. 380709Sjake * All rights reserved. 480709Sjake * 580709Sjake * This software was developed for the FreeBSD Project by ThinkSec AS and 680709Sjake * NAI Labs, the Security Research Division of Network Associates, Inc. 780709Sjake * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 880709Sjake * DARPA CHATS research program. 980709Sjake * 1080709Sjake * Redistribution and use in source and binary forms, with or without 1180709Sjake * modification, are permitted provided that the following conditions 1280709Sjake * are met: 1380709Sjake * 1. Redistributions of source code must retain the above copyright 1481337Sobrien * notice, this list of conditions and the following disclaimer. 1580709Sjake * 2. Redistributions in binary form must reproduce the above copyright 1680709Sjake * notice, this list of conditions and the following disclaimer in the 1781337Sobrien * documentation and/or other materials provided with the distribution. 1880709Sjake * 3. The name of the author may not be used to endorse or promote 1980709Sjake * products derived from this software without specific prior written 2080709Sjake * permission. 2180709Sjake * 2280709Sjake * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2380709Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2480709Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2580709Sjake * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2680709Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2780709Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2880709Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2980709Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3080709Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3180709Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3280709Sjake * SUCH DAMAGE. 3382910Sjake * 3480709Sjake * $P4: //depot/projects/openpam/lib/openpam_dispatch.c#13 $ 3580709Sjake */ 3680709Sjake 3784186Sjake#include <sys/param.h> 3880709Sjake 3980709Sjake#include <security/pam_appl.h> 4081381Sjake 4181381Sjake#include "openpam_impl.h" 4281381Sjake 4381381Sjake#if !defined(OPENPAM_RELAX_CHECKS) 4480709Sjakestatic void _openpam_check_error_code(int, int); 4580709Sjake#else 4680709Sjake#define _openpam_check_error_code(a, b) 4780709Sjake#endif /* !defined(OPENPAM_RELAX_CHECKS) */ 4881135Stmm 4980709Sjake/* 5080709Sjake * OpenPAM internal 5181614Sjake * 5280709Sjake * Execute a module chain 5380709Sjake */ 5480709Sjake 5582910Sjakeint 5680709Sjakeopenpam_dispatch(pam_handle_t *pamh, 5780709Sjake int primitive, 5880709Sjake int flags) 5980709Sjake{ 6082010Sjake pam_chain_t *chain; 6180709Sjake int err, fail, r; 6283756Sjake 6383756Sjake if (pamh == NULL) 6480709Sjake return (PAM_SYSTEM_ERR); 6580709Sjake 6680709Sjake /* prevent recursion */ 6783366Sjulian if (pamh->current != NULL) { 6884186Sjake openpam_log(PAM_LOG_ERROR, "indirect recursion"); 6983366Sjulian return (PAM_ABORT); 7080709Sjake } 7180709Sjake 7282910Sjake /* pick a chain */ 7380709Sjake switch (primitive) { 7481135Stmm case PAM_SM_AUTHENTICATE: 7581135Stmm case PAM_SM_SETCRED: 7681135Stmm chain = pamh->chains[PAM_AUTH]; 7781135Stmm break; 7881381Sjake case PAM_SM_ACCT_MGMT: 7981381Sjake chain = pamh->chains[PAM_ACCOUNT]; 8081381Sjake break; 8181381Sjake case PAM_SM_OPEN_SESSION: 8280709Sjake case PAM_SM_CLOSE_SESSION: 8381381Sjake chain = pamh->chains[PAM_SESSION]; 8481381Sjake break; 8581381Sjake case PAM_SM_CHAUTHTOK: 8680709Sjake chain = pamh->chains[PAM_PASSWORD]; 8785244Sjake break; 8880709Sjake default: 8980709Sjake return (PAM_SYSTEM_ERR); 9080709Sjake } 9180709Sjake 9282910Sjake /* execute */ 9385244Sjake for (err = fail = 0; chain != NULL; chain = chain->next) { 9484186Sjake openpam_log(PAM_LOG_DEBUG, "calling %s() in %s", 9584186Sjake _pam_sm_func_name[primitive], chain->module->path); 9684186Sjake if (chain->module->func[primitive] == NULL) { 9782910Sjake openpam_log(PAM_LOG_ERROR, "%s: no %s()", 9885244Sjake chain->module->path, _pam_sm_func_name[primitive]); 9985244Sjake continue; 10085244Sjake } else { 10182910Sjake pamh->current = chain; 10282910Sjake r = (chain->module->func[primitive])(pamh, flags, 10382910Sjake chain->optc, (const char **)chain->optv); 10482910Sjake pamh->current = NULL; 10582910Sjake openpam_log(PAM_LOG_DEBUG, "%s: %s(): %s", 10682910Sjake chain->module->path, _pam_sm_func_name[primitive], 10782910Sjake pam_strerror(pamh, r)); 10882910Sjake } 10982910Sjake 11080709Sjake if (r == PAM_IGNORE) 11180709Sjake continue; 11281381Sjake if (r == PAM_SUCCESS) { 11380709Sjake /* 11481381Sjake * For pam_setcred() and pam_chauthtok() with the 11580709Sjake * PAM_PRELIM_CHECK flag, treat "sufficient" as 11680709Sjake * "optional". 11780709Sjake * 11880709Sjake * Note that Solaris libpam does not terminate 11981614Sjake * the chain here if a required module has 12081381Sjake * previously failed. I'm not sure why. 12180709Sjake */ 12280709Sjake if (chain->flag == PAM_SUFFICIENT && 12380709Sjake primitive != PAM_SM_SETCRED && 12480709Sjake (primitive != PAM_SM_CHAUTHTOK || 12580709Sjake !(flags & PAM_PRELIM_CHECK))) 12680709Sjake break; 12780709Sjake continue; 12884186Sjake } 12984186Sjake 13083366Sjulian _openpam_check_error_code(primitive, r); 13180709Sjake 13282910Sjake /* 13380709Sjake * Record the return code from the first module to 13484186Sjake * fail. If a required module fails, record the 13584186Sjake * return code from the first required module to fail. 13684186Sjake */ 13781614Sjake if (err == 0) 13881614Sjake err = r; 13981614Sjake if (chain->flag == PAM_REQUIRED && !fail) { 14081614Sjake openpam_log(PAM_LOG_DEBUG, "required module failed"); 14181614Sjake fail = 1; 14281614Sjake err = r; 14381614Sjake } 14481614Sjake 14581614Sjake /* 14681614Sjake * If a requisite module fails, terminate the chain 14781614Sjake * immediately. 14881614Sjake */ 14981614Sjake if (chain->flag == PAM_REQUISITE) { 15081614Sjake openpam_log(PAM_LOG_DEBUG, "requisite module failed"); 15181614Sjake fail = 1; 15281614Sjake break; 15385244Sjake } 15485244Sjake } 15580709Sjake 15680709Sjake if (!fail) 15780709Sjake err = PAM_SUCCESS; 15880709Sjake openpam_log(PAM_LOG_DEBUG, "returning: %s", pam_strerror(pamh, err)); 15983366Sjulian return (err); 16083366Sjulian} 16182910Sjake 16282910Sjake#if !defined(OPENPAM_RELAX_CHECKS) 16382910Sjakestatic void 16480709Sjake_openpam_check_error_code(int primitive, int r) 16580709Sjake{ 16683366Sjulian /* common error codes */ 16783366Sjulian if (r == PAM_SUCCESS || 16883366Sjulian r == PAM_SERVICE_ERR || 16983366Sjulian r == PAM_BUF_ERR || 17083366Sjulian r == PAM_CONV_ERR || 17183366Sjulian r == PAM_PERM_DENIED || 17283366Sjulian r == PAM_ABORT) 17383366Sjulian return; 17484186Sjake 17581135Stmm /* specific error codes */ 17680709Sjake switch (primitive) { 17780709Sjake case PAM_SM_AUTHENTICATE: 17882010Sjake if (r == PAM_AUTH_ERR || 17980709Sjake r == PAM_CRED_INSUFFICIENT || 18082010Sjake r == PAM_AUTHINFO_UNAVAIL || 18182910Sjake r == PAM_USER_UNKNOWN || 18282910Sjake r == PAM_MAXTRIES) 18382910Sjake return; 18480709Sjake break; 18581381Sjake case PAM_SM_SETCRED: 18681381Sjake if (r == PAM_CRED_UNAVAIL || 18781381Sjake r == PAM_CRED_EXPIRED || 18881381Sjake r == PAM_USER_UNKNOWN || 18981135Stmm r == PAM_CRED_ERR) 19081135Stmm return; 19181135Stmm break; 19281135Stmm case PAM_SM_ACCT_MGMT: 19381135Stmm if (r == PAM_USER_UNKNOWN || 19481135Stmm r == PAM_AUTH_ERR || 19581135Stmm r == PAM_NEW_AUTHTOK_REQD || 19680709Sjake r == PAM_ACCT_EXPIRED) 19780709Sjake return; 19880709Sjake break; 19982910Sjake case PAM_SM_OPEN_SESSION: 20082010Sjake case PAM_SM_CLOSE_SESSION: 20180709Sjake if (r == PAM_SESSION_ERR) 20280709Sjake return; 20380709Sjake break; 20480709Sjake case PAM_SM_CHAUTHTOK: 20580709Sjake if (r == PAM_PERM_DENIED || 20680709Sjake r == PAM_AUTHTOK_ERR || 20780709Sjake r == PAM_AUTHTOK_RECOVERY_ERR || 20880709Sjake r == PAM_AUTHTOK_LOCK_BUSY || 20980709Sjake r == PAM_AUTHTOK_DISABLE_AGING || 21080709Sjake r == PAM_TRY_AGAIN) 21180709Sjake return; 21280709Sjake break; 21380709Sjake } 21480709Sjake 21580709Sjake openpam_log(PAM_LOG_ERROR, "%s(): unexpected return value %d", 21680709Sjake _pam_sm_func_name[primitive], r); 21780709Sjake} 21880709Sjake#endif /* !defined(OPENPAM_RELAX_CHECKS) */ 21980709Sjake 22080709Sjake/* 22180709Sjake * NODOC 22280709Sjake * 22380709Sjake * Error codes: 22480709Sjake */ 22582910Sjake