2 * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
3 * Copyright (c) 2004-2007 Dag-Erling Smørgrav
6 * This software was developed for the FreeBSD Project by ThinkSec AS and
7 * Network Associates Laboratories, the Security Research Division of
8 * Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
9 * ("CBOSS"), as part of the DARPA CHATS research program.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote
20 * products derived from this software without specific prior written
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * $Id: openpam_dispatch.c,v 1.4 2008/01/27 01:22:59 christos Exp $
38 #include <sys/param.h>
40 #include <security/pam_appl.h>
42 #include "openpam_impl.h"
44 #if !defined(OPENPAM_RELAX_CHECKS)
45 static void _openpam_check_error_code(int, int);
47 #define _openpam_check_error_code(a, b)
48 #endif /* !defined(OPENPAM_RELAX_CHECKS) */
53 * Execute a module chain
57 openpam_dispatch(pam_handle_t
*pamh
,
69 RETURNC(PAM_SYSTEM_ERR
);
71 /* prevent recursion */
72 if (pamh
->current
!= NULL
) {
73 openpam_log(PAM_LOG_ERROR
,
74 "%s() called while %s::%s() is in progress",
75 _pam_func_name
[primitive
],
76 pamh
->current
->module
->path
,
77 _pam_sm_func_name
[pamh
->primitive
]);
83 case PAM_SM_AUTHENTICATE
:
85 chain
= pamh
->chains
[PAM_AUTH
];
87 case PAM_SM_ACCT_MGMT
:
88 chain
= pamh
->chains
[PAM_ACCOUNT
];
90 case PAM_SM_OPEN_SESSION
:
91 case PAM_SM_CLOSE_SESSION
:
92 chain
= pamh
->chains
[PAM_SESSION
];
94 case PAM_SM_CHAUTHTOK
:
95 chain
= pamh
->chains
[PAM_PASSWORD
];
98 RETURNC(PAM_SYSTEM_ERR
);
102 /* Require chains to exist, so that we don't fail open */
104 RETURNC(PAM_SYSTEM_ERR
);
108 for (err
= fail
= 0; chain
!= NULL
; chain
= chain
->next
) {
109 if (chain
->module
->func
[primitive
] == NULL
) {
110 openpam_log(PAM_LOG_ERROR
, "%s: no %s()",
111 chain
->module
->path
, _pam_sm_func_name
[primitive
]);
114 pamh
->primitive
= primitive
;
115 pamh
->current
= chain
;
117 debug
= (openpam_get_option(pamh
, "debug") != NULL
);
120 openpam_log(PAM_LOG_DEBUG
, "calling %s() in %s",
121 _pam_sm_func_name
[primitive
], chain
->module
->path
);
123 r
= (chain
->module
->func
[primitive
])(pamh
, flags
,
124 chain
->optc
, (const char **)chain
->optv
);
125 pamh
->current
= NULL
;
127 openpam_log(PAM_LOG_DEBUG
, "%s: %s(): %s",
128 chain
->module
->path
, _pam_sm_func_name
[primitive
],
129 pam_strerror(pamh
, r
));
137 if (r
== PAM_SUCCESS
) {
139 * For pam_setcred() and pam_chauthtok() with the
140 * PAM_PRELIM_CHECK flag, treat "sufficient" as
143 if ((chain
->flag
== PAM_SUFFICIENT
||
144 chain
->flag
== PAM_BINDING
) && !fail
&&
145 primitive
!= PAM_SM_SETCRED
&&
146 !(primitive
== PAM_SM_CHAUTHTOK
&&
147 (flags
& PAM_PRELIM_CHECK
)))
152 _openpam_check_error_code(primitive
, r
);
155 * Record the return code from the first module to
156 * fail. If a required module fails, record the
157 * return code from the first required module to fail.
161 if ((chain
->flag
== PAM_REQUIRED
||
162 chain
->flag
== PAM_BINDING
) && !fail
) {
163 openpam_log(PAM_LOG_DEBUG
, "required module failed");
169 * If a requisite module fails, terminate the chain
172 if (chain
->flag
== PAM_REQUISITE
) {
173 openpam_log(PAM_LOG_DEBUG
, "requisite module failed");
179 if (!fail
&& err
!= PAM_NEW_AUTHTOK_REQD
)
185 #if !defined(OPENPAM_RELAX_CHECKS)
187 _openpam_check_error_code(int primitive
, int r
)
189 /* common error codes */
190 if (r
== PAM_SUCCESS
||
191 r
== PAM_SERVICE_ERR
||
194 r
== PAM_PERM_DENIED
||
198 /* specific error codes */
200 case PAM_SM_AUTHENTICATE
:
201 if (r
== PAM_AUTH_ERR
||
202 r
== PAM_CRED_INSUFFICIENT
||
203 r
== PAM_AUTHINFO_UNAVAIL
||
204 r
== PAM_USER_UNKNOWN
||
209 if (r
== PAM_CRED_UNAVAIL
||
210 r
== PAM_CRED_EXPIRED
||
211 r
== PAM_USER_UNKNOWN
||
215 case PAM_SM_ACCT_MGMT
:
216 if (r
== PAM_USER_UNKNOWN
||
218 r
== PAM_NEW_AUTHTOK_REQD
||
219 r
== PAM_ACCT_EXPIRED
)
222 case PAM_SM_OPEN_SESSION
:
223 case PAM_SM_CLOSE_SESSION
:
224 if (r
== PAM_SESSION_ERR
)
227 case PAM_SM_CHAUTHTOK
:
228 if (r
== PAM_PERM_DENIED
||
229 r
== PAM_AUTHTOK_ERR
||
230 r
== PAM_AUTHTOK_RECOVERY_ERR
||
231 r
== PAM_AUTHTOK_LOCK_BUSY
||
232 r
== PAM_AUTHTOK_DISABLE_AGING
||
238 openpam_log(PAM_LOG_ERROR
, "%s(): unexpected return value %d",
239 _pam_sm_func_name
[primitive
], r
);
241 #endif /* !defined(OPENPAM_RELAX_CHECKS) */