xref: /freebsd/lib/libpam/modules/pam_exec/pam_exec.c (revision 228005931ca9c800e306e7b7d4aa0803197fea7d)
1f65b2180SDag-Erling Smørgrav /*-
25e53a4f9SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
35e53a4f9SPedro F. Giffuni  *
437def36fSDag-Erling Smørgrav  * Copyright (c) 2001,2003 Networks Associates Technology, Inc.
54d34b914SDag-Erling Smørgrav  * Copyright (c) 2017-2019 Dag-Erling Smørgrav
6bb3ba83eSDag-Erling Smørgrav  * Copyright (c) 2018 Thomas Munro
7f65b2180SDag-Erling Smørgrav  * All rights reserved.
8f65b2180SDag-Erling Smørgrav  *
9f65b2180SDag-Erling Smørgrav  * This software was developed for the FreeBSD Project by ThinkSec AS and
10f65b2180SDag-Erling Smørgrav  * NAI Labs, the Security Research Division of Network Associates, Inc.
11f65b2180SDag-Erling Smørgrav  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
12f65b2180SDag-Erling Smørgrav  * DARPA CHATS research program.
13f65b2180SDag-Erling Smørgrav  *
14f65b2180SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
15f65b2180SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
16f65b2180SDag-Erling Smørgrav  * are met:
17f65b2180SDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
18f65b2180SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer.
19f65b2180SDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
20f65b2180SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
21f65b2180SDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
22f65b2180SDag-Erling Smørgrav  * 3. The name of the author may not be used to endorse or promote
23f65b2180SDag-Erling Smørgrav  *    products derived from this software without specific prior written
24f65b2180SDag-Erling Smørgrav  *    permission.
25f65b2180SDag-Erling Smørgrav  *
26f65b2180SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
27f65b2180SDag-Erling Smørgrav  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28f65b2180SDag-Erling Smørgrav  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29f65b2180SDag-Erling Smørgrav  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
30f65b2180SDag-Erling Smørgrav  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31f65b2180SDag-Erling Smørgrav  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32f65b2180SDag-Erling Smørgrav  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33f65b2180SDag-Erling Smørgrav  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34f65b2180SDag-Erling Smørgrav  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35f65b2180SDag-Erling Smørgrav  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36f65b2180SDag-Erling Smørgrav  * SUCH DAMAGE.
37f65b2180SDag-Erling Smørgrav  */
38f65b2180SDag-Erling Smørgrav 
39f65b2180SDag-Erling Smørgrav #include <sys/cdefs.h>
40f65b2180SDag-Erling Smørgrav __FBSDID("$FreeBSD$");
41f65b2180SDag-Erling Smørgrav 
42f65b2180SDag-Erling Smørgrav #include <sys/types.h>
433869fb78SDag-Erling Smørgrav #include <sys/poll.h>
443869fb78SDag-Erling Smørgrav #include <sys/procdesc.h>
45f65b2180SDag-Erling Smørgrav #include <sys/wait.h>
46f65b2180SDag-Erling Smørgrav 
47f65b2180SDag-Erling Smørgrav #include <errno.h>
483869fb78SDag-Erling Smørgrav #include <fcntl.h>
498bdb099aSEd Schouten #include <stdio.h>
50f65b2180SDag-Erling Smørgrav #include <stdlib.h>
51f65b2180SDag-Erling Smørgrav #include <string.h>
52f65b2180SDag-Erling Smørgrav #include <unistd.h>
53f65b2180SDag-Erling Smørgrav 
54f65b2180SDag-Erling Smørgrav #include <security/pam_appl.h>
55f65b2180SDag-Erling Smørgrav #include <security/pam_modules.h>
56f65b2180SDag-Erling Smørgrav #include <security/openpam.h>
57f65b2180SDag-Erling Smørgrav 
583869fb78SDag-Erling Smørgrav #define PAM_ITEM_ENV(n) { (n), #n }
599d97c7eeSDag-Erling Smørgrav static struct {
609d97c7eeSDag-Erling Smørgrav 	int item;
619d97c7eeSDag-Erling Smørgrav 	const char *name;
623869fb78SDag-Erling Smørgrav } pam_item_env[] = {
633869fb78SDag-Erling Smørgrav 	PAM_ITEM_ENV(PAM_SERVICE),
643869fb78SDag-Erling Smørgrav 	PAM_ITEM_ENV(PAM_USER),
653869fb78SDag-Erling Smørgrav 	PAM_ITEM_ENV(PAM_TTY),
663869fb78SDag-Erling Smørgrav 	PAM_ITEM_ENV(PAM_RHOST),
673869fb78SDag-Erling Smørgrav 	PAM_ITEM_ENV(PAM_RUSER),
689d97c7eeSDag-Erling Smørgrav };
693869fb78SDag-Erling Smørgrav #define NUM_PAM_ITEM_ENV (sizeof(pam_item_env) / sizeof(pam_item_env[0]))
703869fb78SDag-Erling Smørgrav 
713869fb78SDag-Erling Smørgrav #define PAM_ERR_ENV_X(str, num) str "=" #num
723869fb78SDag-Erling Smørgrav #define PAM_ERR_ENV(pam_err) PAM_ERR_ENV_X(#pam_err, pam_err)
733869fb78SDag-Erling Smørgrav static const char *pam_err_env[] = {
743869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_SUCCESS),
753869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_OPEN_ERR),
763869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_SYMBOL_ERR),
773869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_SERVICE_ERR),
783869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_SYSTEM_ERR),
793869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_BUF_ERR),
803869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_CONV_ERR),
813869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_PERM_DENIED),
823869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_MAXTRIES),
833869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_AUTH_ERR),
843869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_NEW_AUTHTOK_REQD),
853869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_CRED_INSUFFICIENT),
863869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_AUTHINFO_UNAVAIL),
873869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_USER_UNKNOWN),
883869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_CRED_UNAVAIL),
893869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_CRED_EXPIRED),
903869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_CRED_ERR),
913869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_ACCT_EXPIRED),
923869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_AUTHTOK_EXPIRED),
933869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_SESSION_ERR),
943869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_AUTHTOK_ERR),
953869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_AUTHTOK_RECOVERY_ERR),
963869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_AUTHTOK_LOCK_BUSY),
973869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_AUTHTOK_DISABLE_AGING),
983869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_NO_MODULE_DATA),
993869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_IGNORE),
1003869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_ABORT),
1013869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_TRY_AGAIN),
1023869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_MODULE_UNKNOWN),
1033869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_DOMAIN_UNKNOWN),
1043869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_NUM_ERR),
1053869fb78SDag-Erling Smørgrav };
1063869fb78SDag-Erling Smørgrav #define NUM_PAM_ERR_ENV (sizeof(pam_err_env) / sizeof(pam_err_env[0]))
1079d97c7eeSDag-Erling Smørgrav 
1083902d8a9SJean-Sébastien Pédron struct pe_opts {
1093902d8a9SJean-Sébastien Pédron 	int	return_prog_exit_status;
1103869fb78SDag-Erling Smørgrav 	int	capture_stdout;
1113869fb78SDag-Erling Smørgrav 	int	capture_stderr;
112bb3ba83eSDag-Erling Smørgrav 	int	expose_authtok;
1134d34b914SDag-Erling Smørgrav 	int	use_first_pass;
1143902d8a9SJean-Sébastien Pédron };
1153902d8a9SJean-Sébastien Pédron 
116f65b2180SDag-Erling Smørgrav static int
1173902d8a9SJean-Sébastien Pédron parse_options(const char *func, int *argc, const char **argv[],
1183902d8a9SJean-Sébastien Pédron     struct pe_opts *options)
119f65b2180SDag-Erling Smørgrav {
1203902d8a9SJean-Sébastien Pédron 	int i;
1219d97c7eeSDag-Erling Smørgrav 
1229d97c7eeSDag-Erling Smørgrav 	/*
1237e3d5c1fSJean-Sébastien Pédron 	 * Parse options:
1247e3d5c1fSJean-Sébastien Pédron 	 *   return_prog_exit_status:
1257e3d5c1fSJean-Sébastien Pédron 	 *     use the program exit status as the return code of pam_exec
1267e3d5c1fSJean-Sébastien Pédron 	 *   --:
1277e3d5c1fSJean-Sébastien Pédron 	 *     stop options parsing; what follows is the command to execute
1287e3d5c1fSJean-Sébastien Pédron 	 */
1293869fb78SDag-Erling Smørgrav 	memset(options, 0, sizeof(*options));
1303902d8a9SJean-Sébastien Pédron 
1313902d8a9SJean-Sébastien Pédron 	for (i = 0; i < *argc; ++i) {
1323869fb78SDag-Erling Smørgrav 		if (strcmp((*argv)[i], "debug") == 0 ||
1333869fb78SDag-Erling Smørgrav 		    strcmp((*argv)[i], "no_warn") == 0) {
1343869fb78SDag-Erling Smørgrav 			/* ignore */
1353869fb78SDag-Erling Smørgrav 		} else if (strcmp((*argv)[i], "capture_stdout") == 0) {
1363869fb78SDag-Erling Smørgrav 			options->capture_stdout = 1;
1373869fb78SDag-Erling Smørgrav 		} else if (strcmp((*argv)[i], "capture_stderr") == 0) {
1383869fb78SDag-Erling Smørgrav 			options->capture_stderr = 1;
1393869fb78SDag-Erling Smørgrav 		} else if (strcmp((*argv)[i], "return_prog_exit_status") == 0) {
1403902d8a9SJean-Sébastien Pédron 			options->return_prog_exit_status = 1;
141bb3ba83eSDag-Erling Smørgrav 		} else if (strcmp((*argv)[i], "expose_authtok") == 0) {
142bb3ba83eSDag-Erling Smørgrav 			options->expose_authtok = 1;
1434d34b914SDag-Erling Smørgrav 		} else if (strcmp((*argv)[i], "use_first_pass") == 0) {
1444d34b914SDag-Erling Smørgrav 			options->use_first_pass = 1;
1457e3d5c1fSJean-Sébastien Pédron 		} else {
1463902d8a9SJean-Sébastien Pédron 			if (strcmp((*argv)[i], "--") == 0) {
1473902d8a9SJean-Sébastien Pédron 				(*argc)--;
1483902d8a9SJean-Sébastien Pédron 				(*argv)++;
1497e3d5c1fSJean-Sébastien Pédron 			}
1507e3d5c1fSJean-Sébastien Pédron 			break;
1517e3d5c1fSJean-Sébastien Pédron 		}
1523869fb78SDag-Erling Smørgrav 		openpam_log(PAM_LOG_DEBUG, "%s: option \"%s\" enabled",
1533869fb78SDag-Erling Smørgrav 		    func, (*argv)[i]);
1547e3d5c1fSJean-Sébastien Pédron 	}
1557e3d5c1fSJean-Sébastien Pédron 
1563902d8a9SJean-Sébastien Pédron 	(*argc) -= i;
1573902d8a9SJean-Sébastien Pédron 	(*argv) += i;
1583902d8a9SJean-Sébastien Pédron 
1593902d8a9SJean-Sébastien Pédron 	return (0);
1603902d8a9SJean-Sébastien Pédron }
1613902d8a9SJean-Sébastien Pédron 
1623902d8a9SJean-Sébastien Pédron static int
1633869fb78SDag-Erling Smørgrav _pam_exec(pam_handle_t *pamh,
1643902d8a9SJean-Sébastien Pédron     const char *func, int flags __unused, int argc, const char *argv[],
1653902d8a9SJean-Sébastien Pédron     struct pe_opts *options)
1663902d8a9SJean-Sébastien Pédron {
1673869fb78SDag-Erling Smørgrav 	char buf[PAM_MAX_MSG_SIZE];
168bb3ba83eSDag-Erling Smørgrav 	struct pollfd pfd[4];
1693869fb78SDag-Erling Smørgrav 	const void *item;
1703869fb78SDag-Erling Smørgrav 	char **envlist, *envstr, *resp, **tmp;
171bb3ba83eSDag-Erling Smørgrav 	ssize_t rlen, wlen;
1723869fb78SDag-Erling Smørgrav 	int envlen, extralen, i;
1733869fb78SDag-Erling Smørgrav 	int pam_err, serrno, status;
174bb3ba83eSDag-Erling Smørgrav 	int chin[2], chout[2], cherr[2], pd;
175bb3ba83eSDag-Erling Smørgrav 	nfds_t nfds, nreadfds;
1763902d8a9SJean-Sébastien Pédron 	pid_t pid;
177bb3ba83eSDag-Erling Smørgrav 	const char *authtok;
178bb3ba83eSDag-Erling Smørgrav 	size_t authtok_size;
179bb3ba83eSDag-Erling Smørgrav 	int rc;
1803902d8a9SJean-Sébastien Pédron 
1813869fb78SDag-Erling Smørgrav 	pd = -1;
1823869fb78SDag-Erling Smørgrav 	pid = 0;
183bb3ba83eSDag-Erling Smørgrav 	chin[0] = chin[1] = chout[0] = chout[1] = cherr[0] = cherr[1] = -1;
1843869fb78SDag-Erling Smørgrav 	envlist = NULL;
1853869fb78SDag-Erling Smørgrav 
1863869fb78SDag-Erling Smørgrav #define OUT(ret) do { pam_err = (ret); goto out; } while (0)
1877e3d5c1fSJean-Sébastien Pédron 
1887e3d5c1fSJean-Sébastien Pédron 	/* Check there's a program name left after parsing options. */
1897e3d5c1fSJean-Sébastien Pédron 	if (argc < 1) {
1907e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s: No program specified: aborting",
1917e3d5c1fSJean-Sébastien Pédron 		    func);
1923869fb78SDag-Erling Smørgrav 		OUT(PAM_SERVICE_ERR);
1937e3d5c1fSJean-Sébastien Pédron 	}
1947e3d5c1fSJean-Sébastien Pédron 
1957e3d5c1fSJean-Sébastien Pédron 	/*
1969d97c7eeSDag-Erling Smørgrav 	 * Set up the child's environment list.  It consists of the PAM
1973869fb78SDag-Erling Smørgrav 	 * environment, a few hand-picked PAM items, the name of the
1983869fb78SDag-Erling Smørgrav 	 * service function, and if return_prog_exit_status is set, the
1993869fb78SDag-Erling Smørgrav 	 * numerical values of all PAM error codes.
2009d97c7eeSDag-Erling Smørgrav 	 */
2013869fb78SDag-Erling Smørgrav 
2023869fb78SDag-Erling Smørgrav 	/* compute the final size of the environment. */
203a76a4d44SDag-Erling Smørgrav 	envlist = pam_getenvlist(pamh);
2049d97c7eeSDag-Erling Smørgrav 	for (envlen = 0; envlist[envlen] != NULL; ++envlen)
2059d97c7eeSDag-Erling Smørgrav 		/* nothing */ ;
2063869fb78SDag-Erling Smørgrav 	extralen = NUM_PAM_ITEM_ENV + 1;
2073869fb78SDag-Erling Smørgrav 	if (options->return_prog_exit_status)
2083869fb78SDag-Erling Smørgrav 		extralen += NUM_PAM_ERR_ENV;
2093869fb78SDag-Erling Smørgrav 	tmp = reallocarray(envlist, envlen + extralen + 1, sizeof(*envlist));
2103869fb78SDag-Erling Smørgrav 	openpam_log(PAM_LOG_DEBUG, "envlen = %d extralen = %d tmp = %p",
2113869fb78SDag-Erling Smørgrav 	    envlen, extralen, tmp);
2123869fb78SDag-Erling Smørgrav 	if (tmp == NULL)
2133869fb78SDag-Erling Smørgrav 		OUT(PAM_BUF_ERR);
2149d97c7eeSDag-Erling Smørgrav 	envlist = tmp;
2153869fb78SDag-Erling Smørgrav 	extralen += envlen;
2169d97c7eeSDag-Erling Smørgrav 
2173869fb78SDag-Erling Smørgrav 	/* copy selected PAM items to the environment */
2183869fb78SDag-Erling Smørgrav 	for (i = 0; i < NUM_PAM_ITEM_ENV; ++i) {
2193869fb78SDag-Erling Smørgrav 		pam_err = pam_get_item(pamh, pam_item_env[i].item, &item);
2209d97c7eeSDag-Erling Smørgrav 		if (pam_err != PAM_SUCCESS || item == NULL)
2219d97c7eeSDag-Erling Smørgrav 			continue;
222*22800593SDimitry Andric 		if (asprintf(&envstr, "%s=%s", pam_item_env[i].name,
223*22800593SDimitry Andric 		    (const char *)item) < 0)
2243869fb78SDag-Erling Smørgrav 			OUT(PAM_BUF_ERR);
2259d97c7eeSDag-Erling Smørgrav 		envlist[envlen++] = envstr;
2269d97c7eeSDag-Erling Smørgrav 		envlist[envlen] = NULL;
2273869fb78SDag-Erling Smørgrav 		openpam_log(PAM_LOG_DEBUG, "setenv %s", envstr);
2289d97c7eeSDag-Erling Smørgrav 	}
2299d97c7eeSDag-Erling Smørgrav 
2303869fb78SDag-Erling Smørgrav 	/* add the name of the service function to the environment */
2313869fb78SDag-Erling Smørgrav 	if (asprintf(&envstr, "PAM_SM_FUNC=%s", func) < 0)
2323869fb78SDag-Erling Smørgrav 		OUT(PAM_BUF_ERR);
2337e3d5c1fSJean-Sébastien Pédron 	envlist[envlen++] = envstr;
2343869fb78SDag-Erling Smørgrav 	envlist[envlen] = NULL;
2357e3d5c1fSJean-Sébastien Pédron 
2363869fb78SDag-Erling Smørgrav 	/* add the PAM error codes to the environment. */
2373902d8a9SJean-Sébastien Pédron 	if (options->return_prog_exit_status) {
2383869fb78SDag-Erling Smørgrav 		for (i = 0; i < (int)NUM_PAM_ERR_ENV; ++i) {
2393869fb78SDag-Erling Smørgrav 			if ((envstr = strdup(pam_err_env[i])) == NULL)
2403869fb78SDag-Erling Smørgrav 				OUT(PAM_BUF_ERR);
2413869fb78SDag-Erling Smørgrav 			envlist[envlen++] = envstr;
2423869fb78SDag-Erling Smørgrav 			envlist[envlen] = NULL;
2433869fb78SDag-Erling Smørgrav 		}
2447e3d5c1fSJean-Sébastien Pédron 	}
2457e3d5c1fSJean-Sébastien Pédron 
2463869fb78SDag-Erling Smørgrav 	openpam_log(PAM_LOG_DEBUG, "envlen = %d extralen = %d envlist = %p",
2473869fb78SDag-Erling Smørgrav 	    envlen, extralen, envlist);
2487e3d5c1fSJean-Sébastien Pédron 
249bb3ba83eSDag-Erling Smørgrav 	/* set up pipe and get authtok if requested */
250bb3ba83eSDag-Erling Smørgrav 	if (options->expose_authtok) {
251bb3ba83eSDag-Erling Smørgrav 		if (pipe(chin) != 0) {
252bb3ba83eSDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func);
253bb3ba83eSDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
254bb3ba83eSDag-Erling Smørgrav 		}
255bb3ba83eSDag-Erling Smørgrav 		if (fcntl(chin[1], F_SETFL, O_NONBLOCK)) {
256bb3ba83eSDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: fcntl(): %m", func);
257bb3ba83eSDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
258bb3ba83eSDag-Erling Smørgrav 		}
2594d34b914SDag-Erling Smørgrav 		if (options->use_first_pass ||
2604d34b914SDag-Erling Smørgrav 		    strcmp(func, "pam_sm_setcred") == 0) {
2614d34b914SDag-Erling Smørgrav 			/* don't prompt, only expose existing token */
2624d34b914SDag-Erling Smørgrav 			rc = pam_get_item(pamh, PAM_AUTHTOK, &item);
2634d34b914SDag-Erling Smørgrav 			authtok = item;
2644d34b914SDag-Erling Smørgrav 		} else {
265bb3ba83eSDag-Erling Smørgrav 			rc = pam_get_authtok(pamh, PAM_AUTHTOK, &authtok, NULL);
2664d34b914SDag-Erling Smørgrav 		}
267bb3ba83eSDag-Erling Smørgrav 		if (rc == PAM_SUCCESS) {
2684d34b914SDag-Erling Smørgrav 			/* We include the trailing null terminator. */
269e165d7bcSDag-Erling Smørgrav 			authtok_size = strlen(authtok) + 1;
270bb3ba83eSDag-Erling Smørgrav 		} else {
2714d34b914SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: pam_get_authtok(): %s",
2724d34b914SDag-Erling Smørgrav 			    func, pam_strerror(pamh, rc));
273bb3ba83eSDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
274bb3ba83eSDag-Erling Smørgrav 		}
275bb3ba83eSDag-Erling Smørgrav 	}
2763869fb78SDag-Erling Smørgrav 	/* set up pipes if capture was requested */
2773869fb78SDag-Erling Smørgrav 	if (options->capture_stdout) {
2783869fb78SDag-Erling Smørgrav 		if (pipe(chout) != 0) {
2793869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func);
2803869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
2813869fb78SDag-Erling Smørgrav 		}
2823869fb78SDag-Erling Smørgrav 		if (fcntl(chout[0], F_SETFL, O_NONBLOCK) != 0) {
2833869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: fcntl(): %m", func);
2843869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
2853869fb78SDag-Erling Smørgrav 		}
2863869fb78SDag-Erling Smørgrav 	} else {
2873869fb78SDag-Erling Smørgrav 		if ((chout[1] = open("/dev/null", O_RDWR)) < 0) {
2883869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: /dev/null: %m", func);
2893869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
2903869fb78SDag-Erling Smørgrav 		}
2913869fb78SDag-Erling Smørgrav 	}
2923869fb78SDag-Erling Smørgrav 	if (options->capture_stderr) {
2933869fb78SDag-Erling Smørgrav 		if (pipe(cherr) != 0) {
2943869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func);
2953869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
2963869fb78SDag-Erling Smørgrav 		}
2973869fb78SDag-Erling Smørgrav 		if (fcntl(cherr[0], F_SETFL, O_NONBLOCK) != 0) {
2983869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: fcntl(): %m", func);
2993869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
3003869fb78SDag-Erling Smørgrav 		}
3013869fb78SDag-Erling Smørgrav 	} else {
3023869fb78SDag-Erling Smørgrav 		if ((cherr[1] = open("/dev/null", O_RDWR)) < 0) {
3033869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: /dev/null: %m", func);
3043869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
3053869fb78SDag-Erling Smørgrav 		}
3063869fb78SDag-Erling Smørgrav 	}
3073869fb78SDag-Erling Smørgrav 
3083869fb78SDag-Erling Smørgrav 	if ((pid = pdfork(&pd, 0)) == 0) {
3093869fb78SDag-Erling Smørgrav 		/* child */
310bb3ba83eSDag-Erling Smørgrav 		if ((chin[1] >= 0 && close(chin[1]) != 0) ||
311bb3ba83eSDag-Erling Smørgrav 			(chout[0] >= 0 && close(chout[0]) != 0) ||
3123869fb78SDag-Erling Smørgrav 		    (cherr[0] >= 0 && close(cherr[0]) != 0)) {
3133869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: close(): %m", func);
314bb3ba83eSDag-Erling Smørgrav 		} else if (chin[0] >= 0 &&
315bb3ba83eSDag-Erling Smørgrav 			dup2(chin[0], STDIN_FILENO) != STDIN_FILENO) {
316bb3ba83eSDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: dup2(): %m", func);
3173869fb78SDag-Erling Smørgrav 		} else if (dup2(chout[1], STDOUT_FILENO) != STDOUT_FILENO ||
3183869fb78SDag-Erling Smørgrav 		    dup2(cherr[1], STDERR_FILENO) != STDERR_FILENO) {
3193869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: dup2(): %m", func);
3203869fb78SDag-Erling Smørgrav 		} else {
3213869fb78SDag-Erling Smørgrav 			execve(argv[0], (char * const *)argv,
3223869fb78SDag-Erling Smørgrav 			    (char * const *)envlist);
3233869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: execve(%s): %m",
3243869fb78SDag-Erling Smørgrav 			    func, argv[0]);
3253869fb78SDag-Erling Smørgrav 		}
326f65b2180SDag-Erling Smørgrav 		_exit(1);
327a76a4d44SDag-Erling Smørgrav 	}
3283869fb78SDag-Erling Smørgrav 	/* parent */
329a76a4d44SDag-Erling Smørgrav 	if (pid == -1) {
3303869fb78SDag-Erling Smørgrav 		openpam_log(PAM_LOG_ERROR, "%s: pdfork(): %m", func);
3313869fb78SDag-Erling Smørgrav 		OUT(PAM_SYSTEM_ERR);
332f65b2180SDag-Erling Smørgrav 	}
333bb3ba83eSDag-Erling Smørgrav 	/* use poll() to watch the process and stdin / stdout / stderr */
334bb3ba83eSDag-Erling Smørgrav 	if (chin[0] >= 0)
335bb3ba83eSDag-Erling Smørgrav 		close(chin[0]);
3363869fb78SDag-Erling Smørgrav 	if (chout[1] >= 0)
3373869fb78SDag-Erling Smørgrav 		close(chout[1]);
3383869fb78SDag-Erling Smørgrav 	if (cherr[1] >= 0)
3393869fb78SDag-Erling Smørgrav 		close(cherr[1]);
3403869fb78SDag-Erling Smørgrav 	memset(pfd, 0, sizeof pfd);
3413869fb78SDag-Erling Smørgrav 	pfd[0].fd = pd;
3423869fb78SDag-Erling Smørgrav 	pfd[0].events = POLLHUP;
3433869fb78SDag-Erling Smørgrav 	nfds = 1;
344bb3ba83eSDag-Erling Smørgrav 	nreadfds = 0;
3453869fb78SDag-Erling Smørgrav 	if (options->capture_stdout) {
3463869fb78SDag-Erling Smørgrav 		pfd[nfds].fd = chout[0];
3473869fb78SDag-Erling Smørgrav 		pfd[nfds].events = POLLIN|POLLERR|POLLHUP;
3483869fb78SDag-Erling Smørgrav 		nfds++;
349bb3ba83eSDag-Erling Smørgrav 		nreadfds++;
3503869fb78SDag-Erling Smørgrav 	}
3513869fb78SDag-Erling Smørgrav 	if (options->capture_stderr) {
3523869fb78SDag-Erling Smørgrav 		pfd[nfds].fd = cherr[0];
3533869fb78SDag-Erling Smørgrav 		pfd[nfds].events = POLLIN|POLLERR|POLLHUP;
3543869fb78SDag-Erling Smørgrav 		nfds++;
355bb3ba83eSDag-Erling Smørgrav 		nreadfds++;
356bb3ba83eSDag-Erling Smørgrav 	}
357bb3ba83eSDag-Erling Smørgrav 	if (options->expose_authtok) {
358bb3ba83eSDag-Erling Smørgrav 		pfd[nfds].fd = chin[1];
359bb3ba83eSDag-Erling Smørgrav 		pfd[nfds].events = POLLOUT|POLLERR|POLLHUP;
360bb3ba83eSDag-Erling Smørgrav 		nfds++;
3613869fb78SDag-Erling Smørgrav 	}
3623869fb78SDag-Erling Smørgrav 
3633869fb78SDag-Erling Smørgrav 	/* loop until the process exits */
3643869fb78SDag-Erling Smørgrav 	do {
3653869fb78SDag-Erling Smørgrav 		if (poll(pfd, nfds, INFTIM) < 0) {
3663869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: poll(): %m", func);
3673869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
3683869fb78SDag-Erling Smørgrav 		}
369bb3ba83eSDag-Erling Smørgrav 		/* are the stderr / stdout pipes ready for reading? */
370bb3ba83eSDag-Erling Smørgrav 		for (i = 1; i < 1 + nreadfds; ++i) {
3713869fb78SDag-Erling Smørgrav 			if ((pfd[i].revents & POLLIN) == 0)
3723869fb78SDag-Erling Smørgrav 				continue;
3733869fb78SDag-Erling Smørgrav 			if ((rlen = read(pfd[i].fd, buf, sizeof(buf) - 1)) < 0) {
3743869fb78SDag-Erling Smørgrav 				openpam_log(PAM_LOG_ERROR, "%s: read(): %m",
3753869fb78SDag-Erling Smørgrav 				    func);
3763869fb78SDag-Erling Smørgrav 				OUT(PAM_SYSTEM_ERR);
3773869fb78SDag-Erling Smørgrav 			} else if (rlen == 0) {
3783869fb78SDag-Erling Smørgrav 				continue;
3793869fb78SDag-Erling Smørgrav 			}
3803869fb78SDag-Erling Smørgrav 			buf[rlen] = '\0';
3813869fb78SDag-Erling Smørgrav 			(void)pam_prompt(pamh, pfd[i].fd == chout[0] ?
3823869fb78SDag-Erling Smørgrav 			    PAM_TEXT_INFO : PAM_ERROR_MSG, &resp, "%s", buf);
3833869fb78SDag-Erling Smørgrav 		}
384bb3ba83eSDag-Erling Smørgrav 		/* is the stdin pipe ready for writing? */
385bb3ba83eSDag-Erling Smørgrav 		if (options->expose_authtok && authtok_size > 0 &&
386bb3ba83eSDag-Erling Smørgrav 			(pfd[nfds - 1].revents & POLLOUT) != 0) {
387bb3ba83eSDag-Erling Smørgrav 			if ((wlen = write(chin[1], authtok, authtok_size)) < 0) {
388bb3ba83eSDag-Erling Smørgrav 				if (errno == EAGAIN)
389bb3ba83eSDag-Erling Smørgrav 					continue;
390bb3ba83eSDag-Erling Smørgrav 				openpam_log(PAM_LOG_ERROR, "%s: write(): %m",
391bb3ba83eSDag-Erling Smørgrav 				    func);
392bb3ba83eSDag-Erling Smørgrav 				OUT(PAM_SYSTEM_ERR);
393bb3ba83eSDag-Erling Smørgrav 			} else {
394bb3ba83eSDag-Erling Smørgrav 				authtok += wlen;
395bb3ba83eSDag-Erling Smørgrav 				authtok_size -= wlen;
396bb3ba83eSDag-Erling Smørgrav 				if (authtok_size == 0) {
397bb3ba83eSDag-Erling Smørgrav 					/* finished writing; close and forget the pipe */
398bb3ba83eSDag-Erling Smørgrav 					close(chin[1]);
399bb3ba83eSDag-Erling Smørgrav 					chin[1] = -1;
400bb3ba83eSDag-Erling Smørgrav 					nfds--;
401bb3ba83eSDag-Erling Smørgrav 				}
402bb3ba83eSDag-Erling Smørgrav 			}
403bb3ba83eSDag-Erling Smørgrav 		}
4043869fb78SDag-Erling Smørgrav 	} while (pfd[0].revents == 0);
4053869fb78SDag-Erling Smørgrav 
4063869fb78SDag-Erling Smørgrav 	/* the child process has exited */
4077e3d5c1fSJean-Sébastien Pédron 	while (waitpid(pid, &status, 0) == -1) {
4087e3d5c1fSJean-Sébastien Pédron 		if (errno == EINTR)
4097e3d5c1fSJean-Sébastien Pédron 			continue;
4107e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s: waitpid(): %m", func);
4113869fb78SDag-Erling Smørgrav 		OUT(PAM_SYSTEM_ERR);
412f65b2180SDag-Erling Smørgrav 	}
4133869fb78SDag-Erling Smørgrav 
4143869fb78SDag-Erling Smørgrav 	/* check exit code */
415f65b2180SDag-Erling Smørgrav 	if (WIFSIGNALED(status)) {
4167e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s: %s caught signal %d%s",
4177e3d5c1fSJean-Sébastien Pédron 		    func, argv[0], WTERMSIG(status),
418f65b2180SDag-Erling Smørgrav 		    WCOREDUMP(status) ? " (core dumped)" : "");
4193869fb78SDag-Erling Smørgrav 		OUT(PAM_SERVICE_ERR);
420f65b2180SDag-Erling Smørgrav 	}
421f65b2180SDag-Erling Smørgrav 	if (!WIFEXITED(status)) {
4227e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s: unknown status 0x%x",
4237e3d5c1fSJean-Sébastien Pédron 		    func, status);
4243869fb78SDag-Erling Smørgrav 		OUT(PAM_SERVICE_ERR);
425f65b2180SDag-Erling Smørgrav 	}
4267e3d5c1fSJean-Sébastien Pédron 
4273902d8a9SJean-Sébastien Pédron 	if (options->return_prog_exit_status) {
4287e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_DEBUG,
4297e3d5c1fSJean-Sébastien Pédron 		    "%s: Use program exit status as return value: %d",
4307e3d5c1fSJean-Sébastien Pédron 		    func, WEXITSTATUS(status));
4313869fb78SDag-Erling Smørgrav 		OUT(WEXITSTATUS(status));
4327e3d5c1fSJean-Sébastien Pédron 	} else {
4333869fb78SDag-Erling Smørgrav 		OUT(WEXITSTATUS(status) == 0 ? PAM_SUCCESS : PAM_PERM_DENIED);
434f65b2180SDag-Erling Smørgrav 	}
4353869fb78SDag-Erling Smørgrav 	/* unreachable */
4363869fb78SDag-Erling Smørgrav out:
4373869fb78SDag-Erling Smørgrav 	serrno = errno;
4383869fb78SDag-Erling Smørgrav 	if (pd >= 0)
4393869fb78SDag-Erling Smørgrav 		close(pd);
440bb3ba83eSDag-Erling Smørgrav 	if (chin[0] >= 0)
441bb3ba83eSDag-Erling Smørgrav 		close(chin[0]);
442bb3ba83eSDag-Erling Smørgrav 	if (chin[1] >= 0)
443bb3ba83eSDag-Erling Smørgrav 		close(chin[1]);
4443869fb78SDag-Erling Smørgrav 	if (chout[0] >= 0)
4453869fb78SDag-Erling Smørgrav 		close(chout[0]);
4463869fb78SDag-Erling Smørgrav 	if (chout[1] >= 0)
4473869fb78SDag-Erling Smørgrav 		close(chout[1]);
4483869fb78SDag-Erling Smørgrav 	if (cherr[0] >= 0)
4493869fb78SDag-Erling Smørgrav 		close(cherr[0]);
4503869fb78SDag-Erling Smørgrav 	if (cherr[0] >= 0)
4513869fb78SDag-Erling Smørgrav 		close(cherr[1]);
4523869fb78SDag-Erling Smørgrav 	if (envlist != NULL)
4533869fb78SDag-Erling Smørgrav 		openpam_free_envlist(envlist);
4543869fb78SDag-Erling Smørgrav 	errno = serrno;
4553869fb78SDag-Erling Smørgrav 	return (pam_err);
456f65b2180SDag-Erling Smørgrav }
457f65b2180SDag-Erling Smørgrav 
458f65b2180SDag-Erling Smørgrav PAM_EXTERN int
459f65b2180SDag-Erling Smørgrav pam_sm_authenticate(pam_handle_t *pamh, int flags,
460f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
461f65b2180SDag-Erling Smørgrav {
4627e3d5c1fSJean-Sébastien Pédron 	int ret;
4633902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
464f65b2180SDag-Erling Smørgrav 
4653902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
4663902d8a9SJean-Sébastien Pédron 	if (ret != 0)
4673902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
4683902d8a9SJean-Sébastien Pédron 
4693902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
4707e3d5c1fSJean-Sébastien Pédron 
4717e3d5c1fSJean-Sébastien Pédron 	/*
4727e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
4737e3d5c1fSJean-Sébastien Pédron 	 * function.
4747e3d5c1fSJean-Sébastien Pédron 	 */
4757e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
4767e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
4777e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
4787e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTHINFO_UNAVAIL:
4797e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTH_ERR:
4807e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
4817e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
4827e3d5c1fSJean-Sébastien Pédron 	case PAM_CRED_INSUFFICIENT:
4837e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
4847e3d5c1fSJean-Sébastien Pédron 	case PAM_MAXTRIES:
4857e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
4867e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
4877e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
4887e3d5c1fSJean-Sébastien Pédron 	case PAM_USER_UNKNOWN:
4897e3d5c1fSJean-Sébastien Pédron 		break;
4907e3d5c1fSJean-Sébastien Pédron 	default:
4917e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
4927e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
4937e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
4947e3d5c1fSJean-Sébastien Pédron 	}
4957e3d5c1fSJean-Sébastien Pédron 
4967e3d5c1fSJean-Sébastien Pédron 	return (ret);
497f65b2180SDag-Erling Smørgrav }
498f65b2180SDag-Erling Smørgrav 
499f65b2180SDag-Erling Smørgrav PAM_EXTERN int
500f65b2180SDag-Erling Smørgrav pam_sm_setcred(pam_handle_t *pamh, int flags,
501f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
502f65b2180SDag-Erling Smørgrav {
5037e3d5c1fSJean-Sébastien Pédron 	int ret;
5043902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
505f65b2180SDag-Erling Smørgrav 
5063902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
5073902d8a9SJean-Sébastien Pédron 	if (ret != 0)
5083902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
5093902d8a9SJean-Sébastien Pédron 
5103902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
5117e3d5c1fSJean-Sébastien Pédron 
5127e3d5c1fSJean-Sébastien Pédron 	/*
5137e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
5147e3d5c1fSJean-Sébastien Pédron 	 * function.
5157e3d5c1fSJean-Sébastien Pédron 	 */
5167e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
5177e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
5187e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
5197e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
5207e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
5217e3d5c1fSJean-Sébastien Pédron 	case PAM_CRED_ERR:
5227e3d5c1fSJean-Sébastien Pédron 	case PAM_CRED_EXPIRED:
5237e3d5c1fSJean-Sébastien Pédron 	case PAM_CRED_UNAVAIL:
5247e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
5257e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
5267e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
5277e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
5287e3d5c1fSJean-Sébastien Pédron 	case PAM_USER_UNKNOWN:
5297e3d5c1fSJean-Sébastien Pédron 		break;
5307e3d5c1fSJean-Sébastien Pédron 	default:
5317e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
5327e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
5337e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
5347e3d5c1fSJean-Sébastien Pédron 	}
5357e3d5c1fSJean-Sébastien Pédron 
5367e3d5c1fSJean-Sébastien Pédron 	return (ret);
537f65b2180SDag-Erling Smørgrav }
538f65b2180SDag-Erling Smørgrav 
539f65b2180SDag-Erling Smørgrav PAM_EXTERN int
540f65b2180SDag-Erling Smørgrav pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
541f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
542f65b2180SDag-Erling Smørgrav {
5437e3d5c1fSJean-Sébastien Pédron 	int ret;
5443902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
545f65b2180SDag-Erling Smørgrav 
5463902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
5473902d8a9SJean-Sébastien Pédron 	if (ret != 0)
5483902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
5493902d8a9SJean-Sébastien Pédron 
5503902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
5517e3d5c1fSJean-Sébastien Pédron 
5527e3d5c1fSJean-Sébastien Pédron 	/*
5537e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
5547e3d5c1fSJean-Sébastien Pédron 	 * function.
5557e3d5c1fSJean-Sébastien Pédron 	 */
5567e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
5577e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
5587e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
5597e3d5c1fSJean-Sébastien Pédron 	case PAM_ACCT_EXPIRED:
5607e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTH_ERR:
5617e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
5627e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
5637e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
5647e3d5c1fSJean-Sébastien Pédron 	case PAM_NEW_AUTHTOK_REQD:
5657e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
5667e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
5677e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
5687e3d5c1fSJean-Sébastien Pédron 	case PAM_USER_UNKNOWN:
5697e3d5c1fSJean-Sébastien Pédron 		break;
5707e3d5c1fSJean-Sébastien Pédron 	default:
5717e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
5727e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
5737e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
5747e3d5c1fSJean-Sébastien Pédron 	}
5757e3d5c1fSJean-Sébastien Pédron 
5767e3d5c1fSJean-Sébastien Pédron 	return (ret);
577f65b2180SDag-Erling Smørgrav }
578f65b2180SDag-Erling Smørgrav 
579f65b2180SDag-Erling Smørgrav PAM_EXTERN int
580f65b2180SDag-Erling Smørgrav pam_sm_open_session(pam_handle_t *pamh, int flags,
581f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
582f65b2180SDag-Erling Smørgrav {
5837e3d5c1fSJean-Sébastien Pédron 	int ret;
5843902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
585f65b2180SDag-Erling Smørgrav 
5863902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
5873902d8a9SJean-Sébastien Pédron 	if (ret != 0)
5883902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
5893902d8a9SJean-Sébastien Pédron 
5903902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
5917e3d5c1fSJean-Sébastien Pédron 
5927e3d5c1fSJean-Sébastien Pédron 	/*
5937e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
5947e3d5c1fSJean-Sébastien Pédron 	 * function.
5957e3d5c1fSJean-Sébastien Pédron 	 */
5967e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
5977e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
5987e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
5997e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
6007e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
6017e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
6027e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
6037e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
6047e3d5c1fSJean-Sébastien Pédron 	case PAM_SESSION_ERR:
6057e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
6067e3d5c1fSJean-Sébastien Pédron 		break;
6077e3d5c1fSJean-Sébastien Pédron 	default:
6087e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
6097e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
6107e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
6117e3d5c1fSJean-Sébastien Pédron 	}
6127e3d5c1fSJean-Sébastien Pédron 
6137e3d5c1fSJean-Sébastien Pédron 	return (ret);
614f65b2180SDag-Erling Smørgrav }
615f65b2180SDag-Erling Smørgrav 
616f65b2180SDag-Erling Smørgrav PAM_EXTERN int
617f65b2180SDag-Erling Smørgrav pam_sm_close_session(pam_handle_t *pamh, int flags,
618f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
619f65b2180SDag-Erling Smørgrav {
6207e3d5c1fSJean-Sébastien Pédron 	int ret;
6213902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
622f65b2180SDag-Erling Smørgrav 
6233902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
6243902d8a9SJean-Sébastien Pédron 	if (ret != 0)
6253902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
6263902d8a9SJean-Sébastien Pédron 
6273902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
6287e3d5c1fSJean-Sébastien Pédron 
6297e3d5c1fSJean-Sébastien Pédron 	/*
6307e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
6317e3d5c1fSJean-Sébastien Pédron 	 * function.
6327e3d5c1fSJean-Sébastien Pédron 	 */
6337e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
6347e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
6357e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
6367e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
6377e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
6387e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
6397e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
6407e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
6417e3d5c1fSJean-Sébastien Pédron 	case PAM_SESSION_ERR:
6427e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
6437e3d5c1fSJean-Sébastien Pédron 		break;
6447e3d5c1fSJean-Sébastien Pédron 	default:
6457e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
6467e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
6477e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
6487e3d5c1fSJean-Sébastien Pédron 	}
6497e3d5c1fSJean-Sébastien Pédron 
6507e3d5c1fSJean-Sébastien Pédron 	return (ret);
651f65b2180SDag-Erling Smørgrav }
652f65b2180SDag-Erling Smørgrav 
653f65b2180SDag-Erling Smørgrav PAM_EXTERN int
654f65b2180SDag-Erling Smørgrav pam_sm_chauthtok(pam_handle_t *pamh, int flags,
655f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
656f65b2180SDag-Erling Smørgrav {
6577e3d5c1fSJean-Sébastien Pédron 	int ret;
6583902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
659f65b2180SDag-Erling Smørgrav 
6603902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
6613902d8a9SJean-Sébastien Pédron 	if (ret != 0)
6623902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
6633902d8a9SJean-Sébastien Pédron 
6643902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
6657e3d5c1fSJean-Sébastien Pédron 
6667e3d5c1fSJean-Sébastien Pédron 	/*
6677e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
6687e3d5c1fSJean-Sébastien Pédron 	 * function.
6697e3d5c1fSJean-Sébastien Pédron 	 */
6707e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
6717e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
6727e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
6737e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTHTOK_DISABLE_AGING:
6747e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTHTOK_ERR:
6757e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTHTOK_LOCK_BUSY:
6767e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTHTOK_RECOVERY_ERR:
6777e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
6787e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
6797e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
6807e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
6817e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
6827e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
6837e3d5c1fSJean-Sébastien Pédron 	case PAM_TRY_AGAIN:
6847e3d5c1fSJean-Sébastien Pédron 		break;
6857e3d5c1fSJean-Sébastien Pédron 	default:
6867e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
6877e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
6887e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
6897e3d5c1fSJean-Sébastien Pédron 	}
6907e3d5c1fSJean-Sébastien Pédron 
6917e3d5c1fSJean-Sébastien Pédron 	return (ret);
692f65b2180SDag-Erling Smørgrav }
693f65b2180SDag-Erling Smørgrav 
694f65b2180SDag-Erling Smørgrav PAM_MODULE_ENTRY("pam_exec");
695