xref: /dflybsd-src/contrib/openpam/lib/libpam/openpam_dispatch.c (revision 7031abe4d1ef8c309d4113438494530b74f3f3fe)
1*10b5fe87SSascha Wildner /*-
2*10b5fe87SSascha Wildner  * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
3*10b5fe87SSascha Wildner  * Copyright (c) 2004-2017 Dag-Erling Smørgrav
4*10b5fe87SSascha Wildner  * All rights reserved.
5*10b5fe87SSascha Wildner  *
6*10b5fe87SSascha Wildner  * This software was developed for the FreeBSD Project by ThinkSec AS and
7*10b5fe87SSascha Wildner  * Network Associates Laboratories, the Security Research Division of
8*10b5fe87SSascha Wildner  * Network Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
9*10b5fe87SSascha Wildner  * ("CBOSS"), as part of the DARPA CHATS research program.
10*10b5fe87SSascha Wildner  *
11*10b5fe87SSascha Wildner  * Redistribution and use in source and binary forms, with or without
12*10b5fe87SSascha Wildner  * modification, are permitted provided that the following conditions
13*10b5fe87SSascha Wildner  * are met:
14*10b5fe87SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
15*10b5fe87SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
16*10b5fe87SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
17*10b5fe87SSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
18*10b5fe87SSascha Wildner  *    documentation and/or other materials provided with the distribution.
19*10b5fe87SSascha Wildner  * 3. The name of the author may not be used to endorse or promote
20*10b5fe87SSascha Wildner  *    products derived from this software without specific prior written
21*10b5fe87SSascha Wildner  *    permission.
22*10b5fe87SSascha Wildner  *
23*10b5fe87SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24*10b5fe87SSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25*10b5fe87SSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26*10b5fe87SSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27*10b5fe87SSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28*10b5fe87SSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29*10b5fe87SSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30*10b5fe87SSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31*10b5fe87SSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32*10b5fe87SSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33*10b5fe87SSascha Wildner  * SUCH DAMAGE.
34*10b5fe87SSascha Wildner  *
35*10b5fe87SSascha Wildner  * $OpenPAM: openpam_dispatch.c 938 2017-04-30 21:34:42Z des $
36*10b5fe87SSascha Wildner  */
37*10b5fe87SSascha Wildner 
38*10b5fe87SSascha Wildner #ifdef HAVE_CONFIG_H
39*10b5fe87SSascha Wildner # include "config.h"
40*10b5fe87SSascha Wildner #endif
41*10b5fe87SSascha Wildner 
42*10b5fe87SSascha Wildner #include <sys/param.h>
43*10b5fe87SSascha Wildner 
44*10b5fe87SSascha Wildner #include <stdint.h>
45*10b5fe87SSascha Wildner 
46*10b5fe87SSascha Wildner #include <security/pam_appl.h>
47*10b5fe87SSascha Wildner 
48*10b5fe87SSascha Wildner #include "openpam_impl.h"
49*10b5fe87SSascha Wildner 
50*10b5fe87SSascha Wildner #if !defined(OPENPAM_RELAX_CHECKS)
51*10b5fe87SSascha Wildner static void openpam_check_error_code(int, int);
52*10b5fe87SSascha Wildner #else
53*10b5fe87SSascha Wildner #define openpam_check_error_code(a, b)
54*10b5fe87SSascha Wildner #endif /* !defined(OPENPAM_RELAX_CHECKS) */
55*10b5fe87SSascha Wildner 
56*10b5fe87SSascha Wildner /*
57*10b5fe87SSascha Wildner  * OpenPAM internal
58*10b5fe87SSascha Wildner  *
59*10b5fe87SSascha Wildner  * Execute a module chain
60*10b5fe87SSascha Wildner  */
61*10b5fe87SSascha Wildner 
62*10b5fe87SSascha Wildner int
openpam_dispatch(pam_handle_t * pamh,int primitive,int flags)63*10b5fe87SSascha Wildner openpam_dispatch(pam_handle_t *pamh,
64*10b5fe87SSascha Wildner 	int primitive,
65*10b5fe87SSascha Wildner 	int flags)
66*10b5fe87SSascha Wildner {
67*10b5fe87SSascha Wildner 	pam_chain_t *chain;
68*10b5fe87SSascha Wildner 	int err, fail, nsuccess, r;
69*10b5fe87SSascha Wildner 	int debug;
70*10b5fe87SSascha Wildner 
71*10b5fe87SSascha Wildner 	ENTER();
72*10b5fe87SSascha Wildner 
73*10b5fe87SSascha Wildner 	/* prevent recursion */
74*10b5fe87SSascha Wildner 	if (pamh->current != NULL) {
75*10b5fe87SSascha Wildner 		openpam_log(PAM_LOG_ERROR,
76*10b5fe87SSascha Wildner 		    "%s() called while %s::%s() is in progress",
77*10b5fe87SSascha Wildner 		    pam_func_name[primitive],
78*10b5fe87SSascha Wildner 		    pamh->current->module->path,
79*10b5fe87SSascha Wildner 		    pam_sm_func_name[pamh->primitive]);
80*10b5fe87SSascha Wildner 		RETURNC(PAM_ABORT);
81*10b5fe87SSascha Wildner 	}
82*10b5fe87SSascha Wildner 
83*10b5fe87SSascha Wildner 	/* pick a chain */
84*10b5fe87SSascha Wildner 	switch (primitive) {
85*10b5fe87SSascha Wildner 	case PAM_SM_AUTHENTICATE:
86*10b5fe87SSascha Wildner 	case PAM_SM_SETCRED:
87*10b5fe87SSascha Wildner 		chain = pamh->chains[PAM_AUTH];
88*10b5fe87SSascha Wildner 		break;
89*10b5fe87SSascha Wildner 	case PAM_SM_ACCT_MGMT:
90*10b5fe87SSascha Wildner 		chain = pamh->chains[PAM_ACCOUNT];
91*10b5fe87SSascha Wildner 		break;
92*10b5fe87SSascha Wildner 	case PAM_SM_OPEN_SESSION:
93*10b5fe87SSascha Wildner 	case PAM_SM_CLOSE_SESSION:
94*10b5fe87SSascha Wildner 		chain = pamh->chains[PAM_SESSION];
95*10b5fe87SSascha Wildner 		break;
96*10b5fe87SSascha Wildner 	case PAM_SM_CHAUTHTOK:
97*10b5fe87SSascha Wildner 		chain = pamh->chains[PAM_PASSWORD];
98*10b5fe87SSascha Wildner 		break;
99*10b5fe87SSascha Wildner 	default:
100*10b5fe87SSascha Wildner 		RETURNC(PAM_SYSTEM_ERR);
101*10b5fe87SSascha Wildner 	}
102*10b5fe87SSascha Wildner 
103*10b5fe87SSascha Wildner 	/* execute */
104*10b5fe87SSascha Wildner 	err = PAM_SUCCESS;
105*10b5fe87SSascha Wildner 	fail = nsuccess = 0;
106*10b5fe87SSascha Wildner 	for (; chain != NULL; chain = chain->next) {
107*10b5fe87SSascha Wildner 		if (chain->module->func[primitive] == NULL) {
108*10b5fe87SSascha Wildner 			openpam_log(PAM_LOG_ERROR, "%s: no %s()",
109*10b5fe87SSascha Wildner 			    chain->module->path, pam_sm_func_name[primitive]);
110*10b5fe87SSascha Wildner 			r = PAM_SYMBOL_ERR;
111*10b5fe87SSascha Wildner 		} else {
112*10b5fe87SSascha Wildner 			pamh->primitive = primitive;
113*10b5fe87SSascha Wildner 			pamh->current = chain;
114*10b5fe87SSascha Wildner 			debug = (openpam_get_option(pamh, "debug") != NULL);
115*10b5fe87SSascha Wildner 			if (debug)
116*10b5fe87SSascha Wildner 				++openpam_debug;
117*10b5fe87SSascha Wildner 			openpam_log(PAM_LOG_LIBDEBUG, "calling %s() in %s",
118*10b5fe87SSascha Wildner 			    pam_sm_func_name[primitive], chain->module->path);
119*10b5fe87SSascha Wildner 			r = (chain->module->func[primitive])(pamh, flags,
120*10b5fe87SSascha Wildner 			    chain->optc, (const char **)(intptr_t)chain->optv);
121*10b5fe87SSascha Wildner 			pamh->current = NULL;
122*10b5fe87SSascha Wildner 			openpam_log(PAM_LOG_LIBDEBUG, "%s: %s(): %s",
123*10b5fe87SSascha Wildner 			    chain->module->path, pam_sm_func_name[primitive],
124*10b5fe87SSascha Wildner 			    pam_strerror(pamh, r));
125*10b5fe87SSascha Wildner 			if (debug)
126*10b5fe87SSascha Wildner 				--openpam_debug;
127*10b5fe87SSascha Wildner 		}
128*10b5fe87SSascha Wildner 
129*10b5fe87SSascha Wildner 		if (r == PAM_IGNORE)
130*10b5fe87SSascha Wildner 			continue;
131*10b5fe87SSascha Wildner 		if (r == PAM_SUCCESS) {
132*10b5fe87SSascha Wildner 			++nsuccess;
133*10b5fe87SSascha Wildner 			/*
134*10b5fe87SSascha Wildner 			 * For pam_setcred() and pam_chauthtok() with the
135*10b5fe87SSascha Wildner 			 * PAM_PRELIM_CHECK flag, treat "sufficient" as
136*10b5fe87SSascha Wildner 			 * "optional".
137*10b5fe87SSascha Wildner 			 */
138*10b5fe87SSascha Wildner 			if ((chain->flag == PAM_SUFFICIENT ||
139*10b5fe87SSascha Wildner 			    chain->flag == PAM_BINDING) && !fail &&
140*10b5fe87SSascha Wildner 			    primitive != PAM_SM_SETCRED &&
141*10b5fe87SSascha Wildner 			    !(primitive == PAM_SM_CHAUTHTOK &&
142*10b5fe87SSascha Wildner 				(flags & PAM_PRELIM_CHECK)))
143*10b5fe87SSascha Wildner 				break;
144*10b5fe87SSascha Wildner 			continue;
145*10b5fe87SSascha Wildner 		}
146*10b5fe87SSascha Wildner 
147*10b5fe87SSascha Wildner 		openpam_check_error_code(primitive, r);
148*10b5fe87SSascha Wildner 
149*10b5fe87SSascha Wildner 		/*
150*10b5fe87SSascha Wildner 		 * Record the return code from the first module to
151*10b5fe87SSascha Wildner 		 * fail.  If a required module fails, record the
152*10b5fe87SSascha Wildner 		 * return code from the first required module to fail.
153*10b5fe87SSascha Wildner 		 */
154*10b5fe87SSascha Wildner 		if (err == PAM_SUCCESS)
155*10b5fe87SSascha Wildner 			err = r;
156*10b5fe87SSascha Wildner 		if ((chain->flag == PAM_REQUIRED ||
157*10b5fe87SSascha Wildner 		    chain->flag == PAM_BINDING) && !fail) {
158*10b5fe87SSascha Wildner 			openpam_log(PAM_LOG_LIBDEBUG, "required module failed");
159*10b5fe87SSascha Wildner 			fail = 1;
160*10b5fe87SSascha Wildner 			err = r;
161*10b5fe87SSascha Wildner 		}
162*10b5fe87SSascha Wildner 
163*10b5fe87SSascha Wildner 		/*
164*10b5fe87SSascha Wildner 		 * If a requisite module fails, terminate the chain
165*10b5fe87SSascha Wildner 		 * immediately.
166*10b5fe87SSascha Wildner 		 */
167*10b5fe87SSascha Wildner 		if (chain->flag == PAM_REQUISITE) {
168*10b5fe87SSascha Wildner 			openpam_log(PAM_LOG_LIBDEBUG, "requisite module failed");
169*10b5fe87SSascha Wildner 			fail = 1;
170*10b5fe87SSascha Wildner 			break;
171*10b5fe87SSascha Wildner 		}
172*10b5fe87SSascha Wildner 	}
173*10b5fe87SSascha Wildner 
174*10b5fe87SSascha Wildner 	if (!fail && err != PAM_NEW_AUTHTOK_REQD)
175*10b5fe87SSascha Wildner 		err = PAM_SUCCESS;
176*10b5fe87SSascha Wildner 
177*10b5fe87SSascha Wildner 	/*
178*10b5fe87SSascha Wildner 	 * Require the chain to be non-empty, and at least one module
179*10b5fe87SSascha Wildner 	 * in the chain to be successful, so that we don't fail open.
180*10b5fe87SSascha Wildner 	 */
181*10b5fe87SSascha Wildner 	if (err == PAM_SUCCESS && nsuccess < 1) {
182*10b5fe87SSascha Wildner 		openpam_log(PAM_LOG_ERROR,
183*10b5fe87SSascha Wildner 		    "all modules were unsuccessful for %s()",
184*10b5fe87SSascha Wildner 		    pam_sm_func_name[primitive]);
185*10b5fe87SSascha Wildner 		err = PAM_SYSTEM_ERR;
186*10b5fe87SSascha Wildner 	}
187*10b5fe87SSascha Wildner 
188*10b5fe87SSascha Wildner 	RETURNC(err);
189*10b5fe87SSascha Wildner }
190*10b5fe87SSascha Wildner 
191*10b5fe87SSascha Wildner #if !defined(OPENPAM_RELAX_CHECKS)
192*10b5fe87SSascha Wildner static void
openpam_check_error_code(int primitive,int r)193*10b5fe87SSascha Wildner openpam_check_error_code(int primitive, int r)
194*10b5fe87SSascha Wildner {
195*10b5fe87SSascha Wildner 	/* common error codes */
196*10b5fe87SSascha Wildner 	if (r == PAM_SUCCESS ||
197*10b5fe87SSascha Wildner 	    r == PAM_SYSTEM_ERR ||
198*10b5fe87SSascha Wildner 	    r == PAM_SERVICE_ERR ||
199*10b5fe87SSascha Wildner 	    r == PAM_BUF_ERR ||
200*10b5fe87SSascha Wildner 	    r == PAM_CONV_ERR ||
201*10b5fe87SSascha Wildner 	    r == PAM_PERM_DENIED ||
202*10b5fe87SSascha Wildner 	    r == PAM_ABORT)
203*10b5fe87SSascha Wildner 		return;
204*10b5fe87SSascha Wildner 
205*10b5fe87SSascha Wildner 	/* specific error codes */
206*10b5fe87SSascha Wildner 	switch (primitive) {
207*10b5fe87SSascha Wildner 	case PAM_SM_AUTHENTICATE:
208*10b5fe87SSascha Wildner 		if (r == PAM_AUTH_ERR ||
209*10b5fe87SSascha Wildner 		    r == PAM_CRED_INSUFFICIENT ||
210*10b5fe87SSascha Wildner 		    r == PAM_AUTHINFO_UNAVAIL ||
211*10b5fe87SSascha Wildner 		    r == PAM_USER_UNKNOWN ||
212*10b5fe87SSascha Wildner 		    r == PAM_MAXTRIES)
213*10b5fe87SSascha Wildner 			return;
214*10b5fe87SSascha Wildner 		break;
215*10b5fe87SSascha Wildner 	case PAM_SM_SETCRED:
216*10b5fe87SSascha Wildner 		if (r == PAM_CRED_UNAVAIL ||
217*10b5fe87SSascha Wildner 		    r == PAM_CRED_EXPIRED ||
218*10b5fe87SSascha Wildner 		    r == PAM_USER_UNKNOWN ||
219*10b5fe87SSascha Wildner 		    r == PAM_CRED_ERR)
220*10b5fe87SSascha Wildner 			return;
221*10b5fe87SSascha Wildner 		break;
222*10b5fe87SSascha Wildner 	case PAM_SM_ACCT_MGMT:
223*10b5fe87SSascha Wildner 		if (r == PAM_USER_UNKNOWN ||
224*10b5fe87SSascha Wildner 		    r == PAM_AUTH_ERR ||
225*10b5fe87SSascha Wildner 		    r == PAM_NEW_AUTHTOK_REQD ||
226*10b5fe87SSascha Wildner 		    r == PAM_ACCT_EXPIRED)
227*10b5fe87SSascha Wildner 			return;
228*10b5fe87SSascha Wildner 		break;
229*10b5fe87SSascha Wildner 	case PAM_SM_OPEN_SESSION:
230*10b5fe87SSascha Wildner 	case PAM_SM_CLOSE_SESSION:
231*10b5fe87SSascha Wildner 		if (r == PAM_SESSION_ERR)
232*10b5fe87SSascha Wildner 			return;
233*10b5fe87SSascha Wildner 		break;
234*10b5fe87SSascha Wildner 	case PAM_SM_CHAUTHTOK:
235*10b5fe87SSascha Wildner 		if (r == PAM_PERM_DENIED ||
236*10b5fe87SSascha Wildner 		    r == PAM_AUTHTOK_ERR ||
237*10b5fe87SSascha Wildner 		    r == PAM_AUTHTOK_RECOVERY_ERR ||
238*10b5fe87SSascha Wildner 		    r == PAM_AUTHTOK_LOCK_BUSY ||
239*10b5fe87SSascha Wildner 		    r == PAM_AUTHTOK_DISABLE_AGING ||
240*10b5fe87SSascha Wildner 		    r == PAM_TRY_AGAIN)
241*10b5fe87SSascha Wildner 			return;
242*10b5fe87SSascha Wildner 		break;
243*10b5fe87SSascha Wildner 	}
244*10b5fe87SSascha Wildner 
245*10b5fe87SSascha Wildner 	openpam_log(PAM_LOG_ERROR, "%s(): unexpected return value %d",
246*10b5fe87SSascha Wildner 	    pam_sm_func_name[primitive], r);
247*10b5fe87SSascha Wildner }
248*10b5fe87SSascha Wildner #endif /* !defined(OPENPAM_RELAX_CHECKS) */
249*10b5fe87SSascha Wildner 
250*10b5fe87SSascha Wildner /*
251*10b5fe87SSascha Wildner  * NODOC
252*10b5fe87SSascha Wildner  *
253*10b5fe87SSascha Wildner  * Error codes:
254*10b5fe87SSascha Wildner  */
255