xref: /dflybsd-src/lib/libpam/modules/pam_exec/pam_exec.c (revision c98db40744766ab0803912f29557df02814bcd9d)
1242be47eSzrj /*-
2*c98db407SSascha Wildner  * SPDX-License-Identifier: BSD-3-Clause
3*c98db407SSascha Wildner  *
4242be47eSzrj  * Copyright (c) 2001,2003 Networks Associates Technology, Inc.
5242be47eSzrj  * All rights reserved.
6242be47eSzrj  *
7242be47eSzrj  * This software was developed for the FreeBSD Project by ThinkSec AS and
8242be47eSzrj  * NAI Labs, the Security Research Division of Network Associates, Inc.
9242be47eSzrj  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
10242be47eSzrj  * DARPA CHATS research program.
11242be47eSzrj  *
12242be47eSzrj  * Redistribution and use in source and binary forms, with or without
13242be47eSzrj  * modification, are permitted provided that the following conditions
14242be47eSzrj  * are met:
15242be47eSzrj  * 1. Redistributions of source code must retain the above copyright
16242be47eSzrj  *    notice, this list of conditions and the following disclaimer.
17242be47eSzrj  * 2. Redistributions in binary form must reproduce the above copyright
18242be47eSzrj  *    notice, this list of conditions and the following disclaimer in the
19242be47eSzrj  *    documentation and/or other materials provided with the distribution.
20242be47eSzrj  * 3. The name of the author may not be used to endorse or promote
21242be47eSzrj  *    products derived from this software without specific prior written
22242be47eSzrj  *    permission.
23242be47eSzrj  *
24242be47eSzrj  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25242be47eSzrj  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26242be47eSzrj  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27242be47eSzrj  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28242be47eSzrj  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29242be47eSzrj  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30242be47eSzrj  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31242be47eSzrj  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32242be47eSzrj  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33242be47eSzrj  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34242be47eSzrj  * SUCH DAMAGE.
35242be47eSzrj  *
36*c98db407SSascha Wildner  * $FreeBSD: head/lib/libpam/modules/pam_exec/pam_exec.c 315164 2017-03-12 17:41:51Z pfg $
37242be47eSzrj  */
38242be47eSzrj 
39242be47eSzrj #include <sys/types.h>
40242be47eSzrj #include <sys/wait.h>
41242be47eSzrj 
42242be47eSzrj #include <errno.h>
43242be47eSzrj #include <stdio.h>
44242be47eSzrj #include <stdlib.h>
45242be47eSzrj #include <string.h>
46242be47eSzrj #include <unistd.h>
47242be47eSzrj 
48242be47eSzrj #include <security/pam_appl.h>
49242be47eSzrj #include <security/pam_modules.h>
50242be47eSzrj #include <security/openpam.h>
51242be47eSzrj 
52242be47eSzrj #define ENV_ITEM(n) { (n), #n }
53242be47eSzrj static struct {
54242be47eSzrj 	int item;
55242be47eSzrj 	const char *name;
56242be47eSzrj } env_items[] = {
57242be47eSzrj 	ENV_ITEM(PAM_SERVICE),
58242be47eSzrj 	ENV_ITEM(PAM_USER),
59242be47eSzrj 	ENV_ITEM(PAM_TTY),
60242be47eSzrj 	ENV_ITEM(PAM_RHOST),
61242be47eSzrj 	ENV_ITEM(PAM_RUSER),
62242be47eSzrj };
63242be47eSzrj 
64242be47eSzrj struct pe_opts {
65242be47eSzrj 	int	return_prog_exit_status;
66242be47eSzrj };
67242be47eSzrj 
68242be47eSzrj #define	PAM_RV_COUNT 24
69242be47eSzrj 
70242be47eSzrj static int
parse_options(const char * func,int * argc,const char ** argv[],struct pe_opts * options)71242be47eSzrj parse_options(const char *func, int *argc, const char **argv[],
72242be47eSzrj     struct pe_opts *options)
73242be47eSzrj {
74242be47eSzrj 	int i;
75242be47eSzrj 
76242be47eSzrj 	/*
77242be47eSzrj 	 * Parse options:
78242be47eSzrj 	 *   return_prog_exit_status:
79242be47eSzrj 	 *     use the program exit status as the return code of pam_exec
80242be47eSzrj 	 *   --:
81242be47eSzrj 	 *     stop options parsing; what follows is the command to execute
82242be47eSzrj 	 */
83242be47eSzrj 	options->return_prog_exit_status = 0;
84242be47eSzrj 
85242be47eSzrj 	for (i = 0; i < *argc; ++i) {
86242be47eSzrj 		if (strcmp((*argv)[i], "return_prog_exit_status") == 0) {
87242be47eSzrj 			openpam_log(PAM_LOG_DEBUG,
88242be47eSzrj 			    "%s: Option \"return_prog_exit_status\" enabled",
89242be47eSzrj 			    func);
90242be47eSzrj 			options->return_prog_exit_status = 1;
91242be47eSzrj 		} else {
92242be47eSzrj 			if (strcmp((*argv)[i], "--") == 0) {
93242be47eSzrj 				(*argc)--;
94242be47eSzrj 				(*argv)++;
95242be47eSzrj 			}
96242be47eSzrj 
97242be47eSzrj 			break;
98242be47eSzrj 		}
99242be47eSzrj 	}
100242be47eSzrj 
101242be47eSzrj 	(*argc) -= i;
102242be47eSzrj 	(*argv) += i;
103242be47eSzrj 
104242be47eSzrj 	return (0);
105242be47eSzrj }
106242be47eSzrj 
107242be47eSzrj static int
_pam_exec(pam_handle_t * pamh __unused,const char * func,int flags __unused,int argc,const char * argv[],struct pe_opts * options)108242be47eSzrj _pam_exec(pam_handle_t *pamh __unused,
109242be47eSzrj     const char *func, int flags __unused, int argc, const char *argv[],
110242be47eSzrj     struct pe_opts *options)
111242be47eSzrj {
112242be47eSzrj 	int envlen, i, nitems, pam_err, status;
113242be47eSzrj 	int nitems_rv;
114242be47eSzrj 	char **envlist, **tmp, *envstr;
115242be47eSzrj 	volatile int childerr;
116242be47eSzrj 	pid_t pid;
117242be47eSzrj 
118242be47eSzrj 	/*
119242be47eSzrj 	 * XXX For additional credit, divert child's stdin/stdout/stderr
120242be47eSzrj 	 * to the conversation function.
121242be47eSzrj 	 */
122242be47eSzrj 
123242be47eSzrj 	/* Check there's a program name left after parsing options. */
124242be47eSzrj 	if (argc < 1) {
125242be47eSzrj 		openpam_log(PAM_LOG_ERROR, "%s: No program specified: aborting",
126242be47eSzrj 		    func);
127242be47eSzrj 		return (PAM_SERVICE_ERR);
128242be47eSzrj 	}
129242be47eSzrj 
130242be47eSzrj 	/*
131242be47eSzrj 	 * Set up the child's environment list. It consists of the PAM
132242be47eSzrj 	 * environment, plus a few hand-picked PAM items, the pam_sm_*
133242be47eSzrj 	 * function name calling it and, if return_prog_exit_status is
134242be47eSzrj 	 * set, the valid return codes numerical values.
135242be47eSzrj 	 */
136242be47eSzrj 	envlist = pam_getenvlist(pamh);
137242be47eSzrj 	for (envlen = 0; envlist[envlen] != NULL; ++envlen)
138242be47eSzrj 		/* nothing */ ;
139242be47eSzrj 	nitems = sizeof(env_items) / sizeof(*env_items);
140242be47eSzrj 	/* Count PAM return values put in the environment. */
141242be47eSzrj 	nitems_rv = options->return_prog_exit_status ? PAM_RV_COUNT : 0;
142242be47eSzrj 	tmp = realloc(envlist, (envlen + nitems + 1 + nitems_rv + 1) *
143242be47eSzrj 	    sizeof(*envlist));
144242be47eSzrj 	if (tmp == NULL) {
145242be47eSzrj 		openpam_free_envlist(envlist);
146242be47eSzrj 		return (PAM_BUF_ERR);
147242be47eSzrj 	}
148242be47eSzrj 	envlist = tmp;
149242be47eSzrj 	for (i = 0; i < nitems; ++i) {
150242be47eSzrj 		const void *item;
151242be47eSzrj 
152242be47eSzrj 		pam_err = pam_get_item(pamh, env_items[i].item, &item);
153242be47eSzrj 		if (pam_err != PAM_SUCCESS || item == NULL)
154242be47eSzrj 			continue;
155242be47eSzrj 		asprintf(&envstr, "%s=%s", env_items[i].name,
156242be47eSzrj 		    (const char *)item);
157242be47eSzrj 		if (envstr == NULL) {
158242be47eSzrj 			openpam_free_envlist(envlist);
159242be47eSzrj 			return (PAM_BUF_ERR);
160242be47eSzrj 		}
161242be47eSzrj 		envlist[envlen++] = envstr;
162242be47eSzrj 		envlist[envlen] = NULL;
163242be47eSzrj 	}
164242be47eSzrj 
165242be47eSzrj 	/* Add the pam_sm_* function name to the environment. */
166242be47eSzrj 	asprintf(&envstr, "PAM_SM_FUNC=%s", func);
167242be47eSzrj 	if (envstr == NULL) {
168242be47eSzrj 		openpam_free_envlist(envlist);
169242be47eSzrj 		return (PAM_BUF_ERR);
170242be47eSzrj 	}
171242be47eSzrj 	envlist[envlen++] = envstr;
172242be47eSzrj 
173242be47eSzrj 	/* Add the PAM return values to the environment. */
174242be47eSzrj 	if (options->return_prog_exit_status) {
175242be47eSzrj #define	ADD_PAM_RV_TO_ENV(name)						\
176242be47eSzrj 		asprintf(&envstr, #name "=%d", name);			\
177242be47eSzrj 		if (envstr == NULL) {					\
178242be47eSzrj 			openpam_free_envlist(envlist);			\
179242be47eSzrj 			return (PAM_BUF_ERR);				\
180242be47eSzrj 		}							\
181242be47eSzrj 		envlist[envlen++] = envstr
182242be47eSzrj 		/*
183242be47eSzrj 		 * CAUTION: When adding/removing an item in the list
184242be47eSzrj 		 * below, be sure to update the value of PAM_RV_COUNT.
185242be47eSzrj 		 */
186242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_ABORT);
187242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_ACCT_EXPIRED);
188242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_AUTHINFO_UNAVAIL);
189242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_AUTHTOK_DISABLE_AGING);
190242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_AUTHTOK_ERR);
191242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_AUTHTOK_LOCK_BUSY);
192242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_AUTHTOK_RECOVERY_ERR);
193242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_AUTH_ERR);
194242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_BUF_ERR);
195242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_CONV_ERR);
196242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_CRED_ERR);
197242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_CRED_EXPIRED);
198242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_CRED_INSUFFICIENT);
199242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_CRED_UNAVAIL);
200242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_IGNORE);
201242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_MAXTRIES);
202242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_NEW_AUTHTOK_REQD);
203242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_PERM_DENIED);
204242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_SERVICE_ERR);
205242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_SESSION_ERR);
206242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_SUCCESS);
207242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_SYSTEM_ERR);
208242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_TRY_AGAIN);
209242be47eSzrj 		ADD_PAM_RV_TO_ENV(PAM_USER_UNKNOWN);
210242be47eSzrj 	}
211242be47eSzrj 
212242be47eSzrj 	envlist[envlen] = NULL;
213242be47eSzrj 
214242be47eSzrj 	/*
215242be47eSzrj 	 * Fork and run the command.  By using vfork() instead of fork(),
216242be47eSzrj 	 * we can distinguish between an execve() failure and a non-zero
217242be47eSzrj 	 * exit status from the command.
218242be47eSzrj 	 */
219242be47eSzrj 	childerr = 0;
220242be47eSzrj 	if ((pid = vfork()) == 0) {
221242be47eSzrj 		execve(argv[0], (char * const *)argv, (char * const *)envlist);
222242be47eSzrj 		childerr = errno;
223242be47eSzrj 		_exit(1);
224242be47eSzrj 	}
225242be47eSzrj 	openpam_free_envlist(envlist);
226242be47eSzrj 	if (pid == -1) {
227242be47eSzrj 		openpam_log(PAM_LOG_ERROR, "%s: vfork(): %m", func);
228242be47eSzrj 		return (PAM_SYSTEM_ERR);
229242be47eSzrj 	}
230242be47eSzrj 	while (waitpid(pid, &status, 0) == -1) {
231242be47eSzrj 		if (errno == EINTR)
232242be47eSzrj 			continue;
233242be47eSzrj 		openpam_log(PAM_LOG_ERROR, "%s: waitpid(): %m", func);
234242be47eSzrj 		return (PAM_SYSTEM_ERR);
235242be47eSzrj 	}
236242be47eSzrj 	if (childerr != 0) {
237242be47eSzrj 		openpam_log(PAM_LOG_ERROR, "%s: execve(): %m", func);
238242be47eSzrj 		return (PAM_SYSTEM_ERR);
239242be47eSzrj 	}
240242be47eSzrj 	if (WIFSIGNALED(status)) {
241242be47eSzrj 		openpam_log(PAM_LOG_ERROR, "%s: %s caught signal %d%s",
242242be47eSzrj 		    func, argv[0], WTERMSIG(status),
243242be47eSzrj 		    WCOREDUMP(status) ? " (core dumped)" : "");
244242be47eSzrj 		return (PAM_SERVICE_ERR);
245242be47eSzrj 	}
246242be47eSzrj 	if (!WIFEXITED(status)) {
247242be47eSzrj 		openpam_log(PAM_LOG_ERROR, "%s: unknown status 0x%x",
248242be47eSzrj 		    func, status);
249242be47eSzrj 		return (PAM_SERVICE_ERR);
250242be47eSzrj 	}
251242be47eSzrj 
252242be47eSzrj 	if (options->return_prog_exit_status) {
253242be47eSzrj 		openpam_log(PAM_LOG_DEBUG,
254242be47eSzrj 		    "%s: Use program exit status as return value: %d",
255242be47eSzrj 		    func, WEXITSTATUS(status));
256242be47eSzrj 		return (WEXITSTATUS(status));
257242be47eSzrj 	} else {
258242be47eSzrj 		return (WEXITSTATUS(status) == 0 ?
259242be47eSzrj 		    PAM_SUCCESS : PAM_PERM_DENIED);
260242be47eSzrj 	}
261242be47eSzrj }
262242be47eSzrj 
263242be47eSzrj PAM_EXTERN int
pam_sm_authenticate(pam_handle_t * pamh,int flags,int argc,const char * argv[])264*c98db407SSascha Wildner pam_sm_authenticate(pam_handle_t *pamh, int flags,
265*c98db407SSascha Wildner     int argc, const char *argv[])
266242be47eSzrj {
267242be47eSzrj 	int ret;
268242be47eSzrj 	struct pe_opts options;
269242be47eSzrj 
270242be47eSzrj 	ret = parse_options(__func__, &argc, &argv, &options);
271242be47eSzrj 	if (ret != 0)
272242be47eSzrj 		return (PAM_SERVICE_ERR);
273242be47eSzrj 
274242be47eSzrj 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
275242be47eSzrj 
276242be47eSzrj 	/*
277242be47eSzrj 	 * We must check that the program returned a valid code for this
278242be47eSzrj 	 * function.
279242be47eSzrj 	 */
280242be47eSzrj 	switch (ret) {
281242be47eSzrj 	case PAM_SUCCESS:
282242be47eSzrj 	case PAM_ABORT:
283242be47eSzrj 	case PAM_AUTHINFO_UNAVAIL:
284242be47eSzrj 	case PAM_AUTH_ERR:
285242be47eSzrj 	case PAM_BUF_ERR:
286242be47eSzrj 	case PAM_CONV_ERR:
287242be47eSzrj 	case PAM_CRED_INSUFFICIENT:
288242be47eSzrj 	case PAM_IGNORE:
289242be47eSzrj 	case PAM_MAXTRIES:
290242be47eSzrj 	case PAM_PERM_DENIED:
291242be47eSzrj 	case PAM_SERVICE_ERR:
292242be47eSzrj 	case PAM_SYSTEM_ERR:
293242be47eSzrj 	case PAM_USER_UNKNOWN:
294242be47eSzrj 		break;
295242be47eSzrj 	default:
296242be47eSzrj 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
297242be47eSzrj 		    argv[0], ret);
298242be47eSzrj 		ret = PAM_SERVICE_ERR;
299242be47eSzrj 	}
300242be47eSzrj 
301242be47eSzrj 	return (ret);
302242be47eSzrj }
303242be47eSzrj 
304242be47eSzrj PAM_EXTERN int
pam_sm_setcred(pam_handle_t * pamh,int flags,int argc,const char * argv[])305*c98db407SSascha Wildner pam_sm_setcred(pam_handle_t *pamh, int flags,
306*c98db407SSascha Wildner     int argc, const char *argv[])
307242be47eSzrj {
308242be47eSzrj 	int ret;
309242be47eSzrj 	struct pe_opts options;
310242be47eSzrj 
311242be47eSzrj 	ret = parse_options(__func__, &argc, &argv, &options);
312242be47eSzrj 	if (ret != 0)
313242be47eSzrj 		return (PAM_SERVICE_ERR);
314242be47eSzrj 
315242be47eSzrj 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
316242be47eSzrj 
317242be47eSzrj 	/*
318242be47eSzrj 	 * We must check that the program returned a valid code for this
319242be47eSzrj 	 * function.
320242be47eSzrj 	 */
321242be47eSzrj 	switch (ret) {
322242be47eSzrj 	case PAM_SUCCESS:
323242be47eSzrj 	case PAM_ABORT:
324242be47eSzrj 	case PAM_BUF_ERR:
325242be47eSzrj 	case PAM_CONV_ERR:
326242be47eSzrj 	case PAM_CRED_ERR:
327242be47eSzrj 	case PAM_CRED_EXPIRED:
328242be47eSzrj 	case PAM_CRED_UNAVAIL:
329242be47eSzrj 	case PAM_IGNORE:
330242be47eSzrj 	case PAM_PERM_DENIED:
331242be47eSzrj 	case PAM_SERVICE_ERR:
332242be47eSzrj 	case PAM_SYSTEM_ERR:
333242be47eSzrj 	case PAM_USER_UNKNOWN:
334242be47eSzrj 		break;
335242be47eSzrj 	default:
336242be47eSzrj 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
337242be47eSzrj 		    argv[0], ret);
338242be47eSzrj 		ret = PAM_SERVICE_ERR;
339242be47eSzrj 	}
340242be47eSzrj 
341242be47eSzrj 	return (ret);
342242be47eSzrj }
343242be47eSzrj 
344242be47eSzrj PAM_EXTERN int
pam_sm_acct_mgmt(pam_handle_t * pamh,int flags,int argc,const char * argv[])345*c98db407SSascha Wildner pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
346*c98db407SSascha Wildner     int argc, const char *argv[])
347242be47eSzrj {
348242be47eSzrj 	int ret;
349242be47eSzrj 	struct pe_opts options;
350242be47eSzrj 
351242be47eSzrj 	ret = parse_options(__func__, &argc, &argv, &options);
352242be47eSzrj 	if (ret != 0)
353242be47eSzrj 		return (PAM_SERVICE_ERR);
354242be47eSzrj 
355242be47eSzrj 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
356242be47eSzrj 
357242be47eSzrj 	/*
358242be47eSzrj 	 * We must check that the program returned a valid code for this
359242be47eSzrj 	 * function.
360242be47eSzrj 	 */
361242be47eSzrj 	switch (ret) {
362242be47eSzrj 	case PAM_SUCCESS:
363242be47eSzrj 	case PAM_ABORT:
364242be47eSzrj 	case PAM_ACCT_EXPIRED:
365242be47eSzrj 	case PAM_AUTH_ERR:
366242be47eSzrj 	case PAM_BUF_ERR:
367242be47eSzrj 	case PAM_CONV_ERR:
368242be47eSzrj 	case PAM_IGNORE:
369242be47eSzrj 	case PAM_NEW_AUTHTOK_REQD:
370242be47eSzrj 	case PAM_PERM_DENIED:
371242be47eSzrj 	case PAM_SERVICE_ERR:
372242be47eSzrj 	case PAM_SYSTEM_ERR:
373242be47eSzrj 	case PAM_USER_UNKNOWN:
374242be47eSzrj 		break;
375242be47eSzrj 	default:
376242be47eSzrj 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
377242be47eSzrj 		    argv[0], ret);
378242be47eSzrj 		ret = PAM_SERVICE_ERR;
379242be47eSzrj 	}
380242be47eSzrj 
381242be47eSzrj 	return (ret);
382242be47eSzrj }
383242be47eSzrj 
384242be47eSzrj PAM_EXTERN int
pam_sm_open_session(pam_handle_t * pamh,int flags,int argc,const char * argv[])385*c98db407SSascha Wildner pam_sm_open_session(pam_handle_t *pamh, int flags,
386*c98db407SSascha Wildner     int argc, const char *argv[])
387242be47eSzrj {
388242be47eSzrj 	int ret;
389242be47eSzrj 	struct pe_opts options;
390242be47eSzrj 
391242be47eSzrj 	ret = parse_options(__func__, &argc, &argv, &options);
392242be47eSzrj 	if (ret != 0)
393242be47eSzrj 		return (PAM_SERVICE_ERR);
394242be47eSzrj 
395242be47eSzrj 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
396242be47eSzrj 
397242be47eSzrj 	/*
398242be47eSzrj 	 * We must check that the program returned a valid code for this
399242be47eSzrj 	 * function.
400242be47eSzrj 	 */
401242be47eSzrj 	switch (ret) {
402242be47eSzrj 	case PAM_SUCCESS:
403242be47eSzrj 	case PAM_ABORT:
404242be47eSzrj 	case PAM_BUF_ERR:
405242be47eSzrj 	case PAM_CONV_ERR:
406242be47eSzrj 	case PAM_IGNORE:
407242be47eSzrj 	case PAM_PERM_DENIED:
408242be47eSzrj 	case PAM_SERVICE_ERR:
409242be47eSzrj 	case PAM_SESSION_ERR:
410242be47eSzrj 	case PAM_SYSTEM_ERR:
411242be47eSzrj 		break;
412242be47eSzrj 	default:
413242be47eSzrj 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
414242be47eSzrj 		    argv[0], ret);
415242be47eSzrj 		ret = PAM_SERVICE_ERR;
416242be47eSzrj 	}
417242be47eSzrj 
418242be47eSzrj 	return (ret);
419242be47eSzrj }
420242be47eSzrj 
421242be47eSzrj PAM_EXTERN int
pam_sm_close_session(pam_handle_t * pamh,int flags,int argc,const char * argv[])422242be47eSzrj pam_sm_close_session(pam_handle_t *pamh, int flags,
423242be47eSzrj     int argc, const char *argv[])
424242be47eSzrj {
425242be47eSzrj 	int ret;
426242be47eSzrj 	struct pe_opts options;
427242be47eSzrj 
428242be47eSzrj 	ret = parse_options(__func__, &argc, &argv, &options);
429242be47eSzrj 	if (ret != 0)
430242be47eSzrj 		return (PAM_SERVICE_ERR);
431242be47eSzrj 
432242be47eSzrj 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
433242be47eSzrj 
434242be47eSzrj 	/*
435242be47eSzrj 	 * We must check that the program returned a valid code for this
436242be47eSzrj 	 * function.
437242be47eSzrj 	 */
438242be47eSzrj 	switch (ret) {
439242be47eSzrj 	case PAM_SUCCESS:
440242be47eSzrj 	case PAM_ABORT:
441242be47eSzrj 	case PAM_BUF_ERR:
442242be47eSzrj 	case PAM_CONV_ERR:
443242be47eSzrj 	case PAM_IGNORE:
444242be47eSzrj 	case PAM_PERM_DENIED:
445242be47eSzrj 	case PAM_SERVICE_ERR:
446242be47eSzrj 	case PAM_SESSION_ERR:
447242be47eSzrj 	case PAM_SYSTEM_ERR:
448242be47eSzrj 		break;
449242be47eSzrj 	default:
450242be47eSzrj 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
451242be47eSzrj 		    argv[0], ret);
452242be47eSzrj 		ret = PAM_SERVICE_ERR;
453242be47eSzrj 	}
454242be47eSzrj 
455242be47eSzrj 	return (ret);
456242be47eSzrj }
457242be47eSzrj 
458242be47eSzrj PAM_EXTERN int
pam_sm_chauthtok(pam_handle_t * pamh,int flags,int argc,const char * argv[])459*c98db407SSascha Wildner pam_sm_chauthtok(pam_handle_t *pamh, int flags,
460*c98db407SSascha Wildner     int argc, const char *argv[])
461242be47eSzrj {
462242be47eSzrj 	int ret;
463242be47eSzrj 	struct pe_opts options;
464242be47eSzrj 
465242be47eSzrj 	ret = parse_options(__func__, &argc, &argv, &options);
466242be47eSzrj 	if (ret != 0)
467242be47eSzrj 		return (PAM_SERVICE_ERR);
468242be47eSzrj 
469242be47eSzrj 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
470242be47eSzrj 
471242be47eSzrj 	/*
472242be47eSzrj 	 * We must check that the program returned a valid code for this
473242be47eSzrj 	 * function.
474242be47eSzrj 	 */
475242be47eSzrj 	switch (ret) {
476242be47eSzrj 	case PAM_SUCCESS:
477242be47eSzrj 	case PAM_ABORT:
478242be47eSzrj 	case PAM_AUTHTOK_DISABLE_AGING:
479242be47eSzrj 	case PAM_AUTHTOK_ERR:
480242be47eSzrj 	case PAM_AUTHTOK_LOCK_BUSY:
481242be47eSzrj 	case PAM_AUTHTOK_RECOVERY_ERR:
482242be47eSzrj 	case PAM_BUF_ERR:
483242be47eSzrj 	case PAM_CONV_ERR:
484242be47eSzrj 	case PAM_IGNORE:
485242be47eSzrj 	case PAM_PERM_DENIED:
486242be47eSzrj 	case PAM_SERVICE_ERR:
487242be47eSzrj 	case PAM_SYSTEM_ERR:
488242be47eSzrj 	case PAM_TRY_AGAIN:
489242be47eSzrj 		break;
490242be47eSzrj 	default:
491242be47eSzrj 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
492242be47eSzrj 		    argv[0], ret);
493242be47eSzrj 		ret = PAM_SERVICE_ERR;
494242be47eSzrj 	}
495242be47eSzrj 
496242be47eSzrj 	return (ret);
497242be47eSzrj }
498242be47eSzrj 
499242be47eSzrj PAM_MODULE_ENTRY("pam_exec");
500