xref: /freebsd/lib/libpam/modules/pam_exec/pam_exec.c (revision e165d7bc3934136f4e22d417d7f429fa4cdd87d2)
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.
53869fb78SDag-Erling Smørgrav  * Copyright (c) 2017 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;
1133902d8a9SJean-Sébastien Pédron };
1143902d8a9SJean-Sébastien Pédron 
115f65b2180SDag-Erling Smørgrav static int
1163902d8a9SJean-Sébastien Pédron parse_options(const char *func, int *argc, const char **argv[],
1173902d8a9SJean-Sébastien Pédron     struct pe_opts *options)
118f65b2180SDag-Erling Smørgrav {
1193902d8a9SJean-Sébastien Pédron 	int i;
1209d97c7eeSDag-Erling Smørgrav 
1219d97c7eeSDag-Erling Smørgrav 	/*
1227e3d5c1fSJean-Sébastien Pédron 	 * Parse options:
1237e3d5c1fSJean-Sébastien Pédron 	 *   return_prog_exit_status:
1247e3d5c1fSJean-Sébastien Pédron 	 *     use the program exit status as the return code of pam_exec
1257e3d5c1fSJean-Sébastien Pédron 	 *   --:
1267e3d5c1fSJean-Sébastien Pédron 	 *     stop options parsing; what follows is the command to execute
1277e3d5c1fSJean-Sébastien Pédron 	 */
1283869fb78SDag-Erling Smørgrav 	memset(options, 0, sizeof(*options));
1293902d8a9SJean-Sébastien Pédron 
1303902d8a9SJean-Sébastien Pédron 	for (i = 0; i < *argc; ++i) {
1313869fb78SDag-Erling Smørgrav 		if (strcmp((*argv)[i], "debug") == 0 ||
1323869fb78SDag-Erling Smørgrav 		    strcmp((*argv)[i], "no_warn") == 0) {
1333869fb78SDag-Erling Smørgrav 			/* ignore */
1343869fb78SDag-Erling Smørgrav 		} else if (strcmp((*argv)[i], "capture_stdout") == 0) {
1353869fb78SDag-Erling Smørgrav 			options->capture_stdout = 1;
1363869fb78SDag-Erling Smørgrav 		} else if (strcmp((*argv)[i], "capture_stderr") == 0) {
1373869fb78SDag-Erling Smørgrav 			options->capture_stderr = 1;
1383869fb78SDag-Erling Smørgrav 		} else if (strcmp((*argv)[i], "return_prog_exit_status") == 0) {
1393902d8a9SJean-Sébastien Pédron 			options->return_prog_exit_status = 1;
140bb3ba83eSDag-Erling Smørgrav 		} else if (strcmp((*argv)[i], "expose_authtok") == 0) {
141bb3ba83eSDag-Erling Smørgrav 			options->expose_authtok = 1;
1427e3d5c1fSJean-Sébastien Pédron 		} else {
1433902d8a9SJean-Sébastien Pédron 			if (strcmp((*argv)[i], "--") == 0) {
1443902d8a9SJean-Sébastien Pédron 				(*argc)--;
1453902d8a9SJean-Sébastien Pédron 				(*argv)++;
1467e3d5c1fSJean-Sébastien Pédron 			}
1477e3d5c1fSJean-Sébastien Pédron 			break;
1487e3d5c1fSJean-Sébastien Pédron 		}
1493869fb78SDag-Erling Smørgrav 		openpam_log(PAM_LOG_DEBUG, "%s: option \"%s\" enabled",
1503869fb78SDag-Erling Smørgrav 		    func, (*argv)[i]);
1517e3d5c1fSJean-Sébastien Pédron 	}
1527e3d5c1fSJean-Sébastien Pédron 
1533902d8a9SJean-Sébastien Pédron 	(*argc) -= i;
1543902d8a9SJean-Sébastien Pédron 	(*argv) += i;
1553902d8a9SJean-Sébastien Pédron 
1563902d8a9SJean-Sébastien Pédron 	return (0);
1573902d8a9SJean-Sébastien Pédron }
1583902d8a9SJean-Sébastien Pédron 
1593902d8a9SJean-Sébastien Pédron static int
1603869fb78SDag-Erling Smørgrav _pam_exec(pam_handle_t *pamh,
1613902d8a9SJean-Sébastien Pédron     const char *func, int flags __unused, int argc, const char *argv[],
1623902d8a9SJean-Sébastien Pédron     struct pe_opts *options)
1633902d8a9SJean-Sébastien Pédron {
1643869fb78SDag-Erling Smørgrav 	char buf[PAM_MAX_MSG_SIZE];
165bb3ba83eSDag-Erling Smørgrav 	struct pollfd pfd[4];
1663869fb78SDag-Erling Smørgrav 	const void *item;
1673869fb78SDag-Erling Smørgrav 	char **envlist, *envstr, *resp, **tmp;
168bb3ba83eSDag-Erling Smørgrav 	ssize_t rlen, wlen;
1693869fb78SDag-Erling Smørgrav 	int envlen, extralen, i;
1703869fb78SDag-Erling Smørgrav 	int pam_err, serrno, status;
171bb3ba83eSDag-Erling Smørgrav 	int chin[2], chout[2], cherr[2], pd;
172bb3ba83eSDag-Erling Smørgrav 	nfds_t nfds, nreadfds;
1733902d8a9SJean-Sébastien Pédron 	pid_t pid;
174bb3ba83eSDag-Erling Smørgrav 	const char *authtok;
175bb3ba83eSDag-Erling Smørgrav 	size_t authtok_size;
176bb3ba83eSDag-Erling Smørgrav 	int rc;
1773902d8a9SJean-Sébastien Pédron 
1783869fb78SDag-Erling Smørgrav 	pd = -1;
1793869fb78SDag-Erling Smørgrav 	pid = 0;
180bb3ba83eSDag-Erling Smørgrav 	chin[0] = chin[1] = chout[0] = chout[1] = cherr[0] = cherr[1] = -1;
1813869fb78SDag-Erling Smørgrav 	envlist = NULL;
1823869fb78SDag-Erling Smørgrav 
1833869fb78SDag-Erling Smørgrav #define OUT(ret) do { pam_err = (ret); goto out; } while (0)
1847e3d5c1fSJean-Sébastien Pédron 
1857e3d5c1fSJean-Sébastien Pédron 	/* Check there's a program name left after parsing options. */
1867e3d5c1fSJean-Sébastien Pédron 	if (argc < 1) {
1877e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s: No program specified: aborting",
1887e3d5c1fSJean-Sébastien Pédron 		    func);
1893869fb78SDag-Erling Smørgrav 		OUT(PAM_SERVICE_ERR);
1907e3d5c1fSJean-Sébastien Pédron 	}
1917e3d5c1fSJean-Sébastien Pédron 
1927e3d5c1fSJean-Sébastien Pédron 	/*
1939d97c7eeSDag-Erling Smørgrav 	 * Set up the child's environment list.  It consists of the PAM
1943869fb78SDag-Erling Smørgrav 	 * environment, a few hand-picked PAM items, the name of the
1953869fb78SDag-Erling Smørgrav 	 * service function, and if return_prog_exit_status is set, the
1963869fb78SDag-Erling Smørgrav 	 * numerical values of all PAM error codes.
1979d97c7eeSDag-Erling Smørgrav 	 */
1983869fb78SDag-Erling Smørgrav 
1993869fb78SDag-Erling Smørgrav 	/* compute the final size of the environment. */
200a76a4d44SDag-Erling Smørgrav 	envlist = pam_getenvlist(pamh);
2019d97c7eeSDag-Erling Smørgrav 	for (envlen = 0; envlist[envlen] != NULL; ++envlen)
2029d97c7eeSDag-Erling Smørgrav 		/* nothing */ ;
2033869fb78SDag-Erling Smørgrav 	extralen = NUM_PAM_ITEM_ENV + 1;
2043869fb78SDag-Erling Smørgrav 	if (options->return_prog_exit_status)
2053869fb78SDag-Erling Smørgrav 		extralen += NUM_PAM_ERR_ENV;
2063869fb78SDag-Erling Smørgrav 	tmp = reallocarray(envlist, envlen + extralen + 1, sizeof(*envlist));
2073869fb78SDag-Erling Smørgrav 	openpam_log(PAM_LOG_DEBUG, "envlen = %d extralen = %d tmp = %p",
2083869fb78SDag-Erling Smørgrav 	    envlen, extralen, tmp);
2093869fb78SDag-Erling Smørgrav 	if (tmp == NULL)
2103869fb78SDag-Erling Smørgrav 		OUT(PAM_BUF_ERR);
2119d97c7eeSDag-Erling Smørgrav 	envlist = tmp;
2123869fb78SDag-Erling Smørgrav 	extralen += envlen;
2139d97c7eeSDag-Erling Smørgrav 
2143869fb78SDag-Erling Smørgrav 	/* copy selected PAM items to the environment */
2153869fb78SDag-Erling Smørgrav 	for (i = 0; i < NUM_PAM_ITEM_ENV; ++i) {
2163869fb78SDag-Erling Smørgrav 		pam_err = pam_get_item(pamh, pam_item_env[i].item, &item);
2179d97c7eeSDag-Erling Smørgrav 		if (pam_err != PAM_SUCCESS || item == NULL)
2189d97c7eeSDag-Erling Smørgrav 			continue;
2193869fb78SDag-Erling Smørgrav 		if (asprintf(&envstr, "%s=%s", pam_item_env[i].name, item) < 0)
2203869fb78SDag-Erling Smørgrav 			OUT(PAM_BUF_ERR);
2219d97c7eeSDag-Erling Smørgrav 		envlist[envlen++] = envstr;
2229d97c7eeSDag-Erling Smørgrav 		envlist[envlen] = NULL;
2233869fb78SDag-Erling Smørgrav 		openpam_log(PAM_LOG_DEBUG, "setenv %s", envstr);
2249d97c7eeSDag-Erling Smørgrav 	}
2259d97c7eeSDag-Erling Smørgrav 
2263869fb78SDag-Erling Smørgrav 	/* add the name of the service function to the environment */
2273869fb78SDag-Erling Smørgrav 	if (asprintf(&envstr, "PAM_SM_FUNC=%s", func) < 0)
2283869fb78SDag-Erling Smørgrav 		OUT(PAM_BUF_ERR);
2297e3d5c1fSJean-Sébastien Pédron 	envlist[envlen++] = envstr;
2303869fb78SDag-Erling Smørgrav 	envlist[envlen] = NULL;
2317e3d5c1fSJean-Sébastien Pédron 
2323869fb78SDag-Erling Smørgrav 	/* add the PAM error codes to the environment. */
2333902d8a9SJean-Sébastien Pédron 	if (options->return_prog_exit_status) {
2343869fb78SDag-Erling Smørgrav 		for (i = 0; i < (int)NUM_PAM_ERR_ENV; ++i) {
2353869fb78SDag-Erling Smørgrav 			if ((envstr = strdup(pam_err_env[i])) == NULL)
2363869fb78SDag-Erling Smørgrav 				OUT(PAM_BUF_ERR);
2373869fb78SDag-Erling Smørgrav 			envlist[envlen++] = envstr;
2383869fb78SDag-Erling Smørgrav 			envlist[envlen] = NULL;
2393869fb78SDag-Erling Smørgrav 		}
2407e3d5c1fSJean-Sébastien Pédron 	}
2417e3d5c1fSJean-Sébastien Pédron 
2423869fb78SDag-Erling Smørgrav 	openpam_log(PAM_LOG_DEBUG, "envlen = %d extralen = %d envlist = %p",
2433869fb78SDag-Erling Smørgrav 	    envlen, extralen, envlist);
2447e3d5c1fSJean-Sébastien Pédron 
245bb3ba83eSDag-Erling Smørgrav 	/* set up pipe and get authtok if requested */
246bb3ba83eSDag-Erling Smørgrav 	if (options->expose_authtok) {
247bb3ba83eSDag-Erling Smørgrav 		if (pipe(chin) != 0) {
248bb3ba83eSDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func);
249bb3ba83eSDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
250bb3ba83eSDag-Erling Smørgrav 		}
251bb3ba83eSDag-Erling Smørgrav 		if (fcntl(chin[1], F_SETFL, O_NONBLOCK)) {
252bb3ba83eSDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: fcntl(): %m", func);
253bb3ba83eSDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
254bb3ba83eSDag-Erling Smørgrav 		}
255bb3ba83eSDag-Erling Smørgrav 		rc = pam_get_authtok(pamh, PAM_AUTHTOK, &authtok, NULL);
256bb3ba83eSDag-Erling Smørgrav 		if (rc == PAM_SUCCESS) {
257*e165d7bcSDag-Erling Smørgrav 			/* We include the trailing NUL-terminator. */
258*e165d7bcSDag-Erling Smørgrav 			authtok_size = strlen(authtok) + 1;
259bb3ba83eSDag-Erling Smørgrav 		} else {
260bb3ba83eSDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: pam_get_authtok(): %s", func,
261bb3ba83eSDag-Erling Smørgrav 						pam_strerror(pamh, rc));
262bb3ba83eSDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
263bb3ba83eSDag-Erling Smørgrav 		}
264bb3ba83eSDag-Erling Smørgrav 	}
2653869fb78SDag-Erling Smørgrav 	/* set up pipes if capture was requested */
2663869fb78SDag-Erling Smørgrav 	if (options->capture_stdout) {
2673869fb78SDag-Erling Smørgrav 		if (pipe(chout) != 0) {
2683869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func);
2693869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
2703869fb78SDag-Erling Smørgrav 		}
2713869fb78SDag-Erling Smørgrav 		if (fcntl(chout[0], F_SETFL, O_NONBLOCK) != 0) {
2723869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: fcntl(): %m", func);
2733869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
2743869fb78SDag-Erling Smørgrav 		}
2753869fb78SDag-Erling Smørgrav 	} else {
2763869fb78SDag-Erling Smørgrav 		if ((chout[1] = open("/dev/null", O_RDWR)) < 0) {
2773869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: /dev/null: %m", func);
2783869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
2793869fb78SDag-Erling Smørgrav 		}
2803869fb78SDag-Erling Smørgrav 	}
2813869fb78SDag-Erling Smørgrav 	if (options->capture_stderr) {
2823869fb78SDag-Erling Smørgrav 		if (pipe(cherr) != 0) {
2833869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func);
2843869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
2853869fb78SDag-Erling Smørgrav 		}
2863869fb78SDag-Erling Smørgrav 		if (fcntl(cherr[0], F_SETFL, O_NONBLOCK) != 0) {
2873869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: fcntl(): %m", func);
2883869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
2893869fb78SDag-Erling Smørgrav 		}
2903869fb78SDag-Erling Smørgrav 	} else {
2913869fb78SDag-Erling Smørgrav 		if ((cherr[1] = open("/dev/null", O_RDWR)) < 0) {
2923869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: /dev/null: %m", func);
2933869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
2943869fb78SDag-Erling Smørgrav 		}
2953869fb78SDag-Erling Smørgrav 	}
2963869fb78SDag-Erling Smørgrav 
2973869fb78SDag-Erling Smørgrav 	if ((pid = pdfork(&pd, 0)) == 0) {
2983869fb78SDag-Erling Smørgrav 		/* child */
299bb3ba83eSDag-Erling Smørgrav 		if ((chin[1] >= 0 && close(chin[1]) != 0) ||
300bb3ba83eSDag-Erling Smørgrav 			(chout[0] >= 0 && close(chout[0]) != 0) ||
3013869fb78SDag-Erling Smørgrav 		    (cherr[0] >= 0 && close(cherr[0]) != 0)) {
3023869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: close(): %m", func);
303bb3ba83eSDag-Erling Smørgrav 		} else if (chin[0] >= 0 &&
304bb3ba83eSDag-Erling Smørgrav 			dup2(chin[0], STDIN_FILENO) != STDIN_FILENO) {
305bb3ba83eSDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: dup2(): %m", func);
3063869fb78SDag-Erling Smørgrav 		} else if (dup2(chout[1], STDOUT_FILENO) != STDOUT_FILENO ||
3073869fb78SDag-Erling Smørgrav 		    dup2(cherr[1], STDERR_FILENO) != STDERR_FILENO) {
3083869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: dup2(): %m", func);
3093869fb78SDag-Erling Smørgrav 		} else {
3103869fb78SDag-Erling Smørgrav 			execve(argv[0], (char * const *)argv,
3113869fb78SDag-Erling Smørgrav 			    (char * const *)envlist);
3123869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: execve(%s): %m",
3133869fb78SDag-Erling Smørgrav 			    func, argv[0]);
3143869fb78SDag-Erling Smørgrav 		}
315f65b2180SDag-Erling Smørgrav 		_exit(1);
316a76a4d44SDag-Erling Smørgrav 	}
3173869fb78SDag-Erling Smørgrav 	/* parent */
318a76a4d44SDag-Erling Smørgrav 	if (pid == -1) {
3193869fb78SDag-Erling Smørgrav 		openpam_log(PAM_LOG_ERROR, "%s: pdfork(): %m", func);
3203869fb78SDag-Erling Smørgrav 		OUT(PAM_SYSTEM_ERR);
321f65b2180SDag-Erling Smørgrav 	}
322bb3ba83eSDag-Erling Smørgrav 	/* use poll() to watch the process and stdin / stdout / stderr */
323bb3ba83eSDag-Erling Smørgrav 	if (chin[0] >= 0)
324bb3ba83eSDag-Erling Smørgrav 		close(chin[0]);
3253869fb78SDag-Erling Smørgrav 	if (chout[1] >= 0)
3263869fb78SDag-Erling Smørgrav 		close(chout[1]);
3273869fb78SDag-Erling Smørgrav 	if (cherr[1] >= 0)
3283869fb78SDag-Erling Smørgrav 		close(cherr[1]);
3293869fb78SDag-Erling Smørgrav 	memset(pfd, 0, sizeof pfd);
3303869fb78SDag-Erling Smørgrav 	pfd[0].fd = pd;
3313869fb78SDag-Erling Smørgrav 	pfd[0].events = POLLHUP;
3323869fb78SDag-Erling Smørgrav 	nfds = 1;
333bb3ba83eSDag-Erling Smørgrav 	nreadfds = 0;
3343869fb78SDag-Erling Smørgrav 	if (options->capture_stdout) {
3353869fb78SDag-Erling Smørgrav 		pfd[nfds].fd = chout[0];
3363869fb78SDag-Erling Smørgrav 		pfd[nfds].events = POLLIN|POLLERR|POLLHUP;
3373869fb78SDag-Erling Smørgrav 		nfds++;
338bb3ba83eSDag-Erling Smørgrav 		nreadfds++;
3393869fb78SDag-Erling Smørgrav 	}
3403869fb78SDag-Erling Smørgrav 	if (options->capture_stderr) {
3413869fb78SDag-Erling Smørgrav 		pfd[nfds].fd = cherr[0];
3423869fb78SDag-Erling Smørgrav 		pfd[nfds].events = POLLIN|POLLERR|POLLHUP;
3433869fb78SDag-Erling Smørgrav 		nfds++;
344bb3ba83eSDag-Erling Smørgrav 		nreadfds++;
345bb3ba83eSDag-Erling Smørgrav 	}
346bb3ba83eSDag-Erling Smørgrav 	if (options->expose_authtok) {
347bb3ba83eSDag-Erling Smørgrav 		pfd[nfds].fd = chin[1];
348bb3ba83eSDag-Erling Smørgrav 		pfd[nfds].events = POLLOUT|POLLERR|POLLHUP;
349bb3ba83eSDag-Erling Smørgrav 		nfds++;
3503869fb78SDag-Erling Smørgrav 	}
3513869fb78SDag-Erling Smørgrav 
3523869fb78SDag-Erling Smørgrav 	/* loop until the process exits */
3533869fb78SDag-Erling Smørgrav 	do {
3543869fb78SDag-Erling Smørgrav 		if (poll(pfd, nfds, INFTIM) < 0) {
3553869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: poll(): %m", func);
3563869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
3573869fb78SDag-Erling Smørgrav 		}
358bb3ba83eSDag-Erling Smørgrav 		/* are the stderr / stdout pipes ready for reading? */
359bb3ba83eSDag-Erling Smørgrav 		for (i = 1; i < 1 + nreadfds; ++i) {
3603869fb78SDag-Erling Smørgrav 			if ((pfd[i].revents & POLLIN) == 0)
3613869fb78SDag-Erling Smørgrav 				continue;
3623869fb78SDag-Erling Smørgrav 			if ((rlen = read(pfd[i].fd, buf, sizeof(buf) - 1)) < 0) {
3633869fb78SDag-Erling Smørgrav 				openpam_log(PAM_LOG_ERROR, "%s: read(): %m",
3643869fb78SDag-Erling Smørgrav 				    func);
3653869fb78SDag-Erling Smørgrav 				OUT(PAM_SYSTEM_ERR);
3663869fb78SDag-Erling Smørgrav 			} else if (rlen == 0) {
3673869fb78SDag-Erling Smørgrav 				continue;
3683869fb78SDag-Erling Smørgrav 			}
3693869fb78SDag-Erling Smørgrav 			buf[rlen] = '\0';
3703869fb78SDag-Erling Smørgrav 			(void)pam_prompt(pamh, pfd[i].fd == chout[0] ?
3713869fb78SDag-Erling Smørgrav 			    PAM_TEXT_INFO : PAM_ERROR_MSG, &resp, "%s", buf);
3723869fb78SDag-Erling Smørgrav 		}
373bb3ba83eSDag-Erling Smørgrav 		/* is the stdin pipe ready for writing? */
374bb3ba83eSDag-Erling Smørgrav 		if (options->expose_authtok && authtok_size > 0 &&
375bb3ba83eSDag-Erling Smørgrav 			(pfd[nfds - 1].revents & POLLOUT) != 0) {
376bb3ba83eSDag-Erling Smørgrav 			if ((wlen = write(chin[1], authtok, authtok_size)) < 0) {
377bb3ba83eSDag-Erling Smørgrav 				if (errno == EAGAIN)
378bb3ba83eSDag-Erling Smørgrav 					continue;
379bb3ba83eSDag-Erling Smørgrav 				openpam_log(PAM_LOG_ERROR, "%s: write(): %m",
380bb3ba83eSDag-Erling Smørgrav 				    func);
381bb3ba83eSDag-Erling Smørgrav 				OUT(PAM_SYSTEM_ERR);
382bb3ba83eSDag-Erling Smørgrav 			} else {
383bb3ba83eSDag-Erling Smørgrav 				authtok += wlen;
384bb3ba83eSDag-Erling Smørgrav 				authtok_size -= wlen;
385bb3ba83eSDag-Erling Smørgrav 				if (authtok_size == 0) {
386bb3ba83eSDag-Erling Smørgrav 					/* finished writing; close and forget the pipe */
387bb3ba83eSDag-Erling Smørgrav 					close(chin[1]);
388bb3ba83eSDag-Erling Smørgrav 					chin[1] = -1;
389bb3ba83eSDag-Erling Smørgrav 					nfds--;
390bb3ba83eSDag-Erling Smørgrav 				}
391bb3ba83eSDag-Erling Smørgrav 			}
392bb3ba83eSDag-Erling Smørgrav 		}
3933869fb78SDag-Erling Smørgrav 	} while (pfd[0].revents == 0);
3943869fb78SDag-Erling Smørgrav 
3953869fb78SDag-Erling Smørgrav 	/* the child process has exited */
3967e3d5c1fSJean-Sébastien Pédron 	while (waitpid(pid, &status, 0) == -1) {
3977e3d5c1fSJean-Sébastien Pédron 		if (errno == EINTR)
3987e3d5c1fSJean-Sébastien Pédron 			continue;
3997e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s: waitpid(): %m", func);
4003869fb78SDag-Erling Smørgrav 		OUT(PAM_SYSTEM_ERR);
401f65b2180SDag-Erling Smørgrav 	}
4023869fb78SDag-Erling Smørgrav 
4033869fb78SDag-Erling Smørgrav 	/* check exit code */
404f65b2180SDag-Erling Smørgrav 	if (WIFSIGNALED(status)) {
4057e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s: %s caught signal %d%s",
4067e3d5c1fSJean-Sébastien Pédron 		    func, argv[0], WTERMSIG(status),
407f65b2180SDag-Erling Smørgrav 		    WCOREDUMP(status) ? " (core dumped)" : "");
4083869fb78SDag-Erling Smørgrav 		OUT(PAM_SERVICE_ERR);
409f65b2180SDag-Erling Smørgrav 	}
410f65b2180SDag-Erling Smørgrav 	if (!WIFEXITED(status)) {
4117e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s: unknown status 0x%x",
4127e3d5c1fSJean-Sébastien Pédron 		    func, status);
4133869fb78SDag-Erling Smørgrav 		OUT(PAM_SERVICE_ERR);
414f65b2180SDag-Erling Smørgrav 	}
4157e3d5c1fSJean-Sébastien Pédron 
4163902d8a9SJean-Sébastien Pédron 	if (options->return_prog_exit_status) {
4177e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_DEBUG,
4187e3d5c1fSJean-Sébastien Pédron 		    "%s: Use program exit status as return value: %d",
4197e3d5c1fSJean-Sébastien Pédron 		    func, WEXITSTATUS(status));
4203869fb78SDag-Erling Smørgrav 		OUT(WEXITSTATUS(status));
4217e3d5c1fSJean-Sébastien Pédron 	} else {
4223869fb78SDag-Erling Smørgrav 		OUT(WEXITSTATUS(status) == 0 ? PAM_SUCCESS : PAM_PERM_DENIED);
423f65b2180SDag-Erling Smørgrav 	}
4243869fb78SDag-Erling Smørgrav 	/* unreachable */
4253869fb78SDag-Erling Smørgrav out:
4263869fb78SDag-Erling Smørgrav 	serrno = errno;
4273869fb78SDag-Erling Smørgrav 	if (pd >= 0)
4283869fb78SDag-Erling Smørgrav 		close(pd);
429bb3ba83eSDag-Erling Smørgrav 	if (chin[0] >= 0)
430bb3ba83eSDag-Erling Smørgrav 		close(chin[0]);
431bb3ba83eSDag-Erling Smørgrav 	if (chin[1] >= 0)
432bb3ba83eSDag-Erling Smørgrav 		close(chin[1]);
4333869fb78SDag-Erling Smørgrav 	if (chout[0] >= 0)
4343869fb78SDag-Erling Smørgrav 		close(chout[0]);
4353869fb78SDag-Erling Smørgrav 	if (chout[1] >= 0)
4363869fb78SDag-Erling Smørgrav 		close(chout[1]);
4373869fb78SDag-Erling Smørgrav 	if (cherr[0] >= 0)
4383869fb78SDag-Erling Smørgrav 		close(cherr[0]);
4393869fb78SDag-Erling Smørgrav 	if (cherr[0] >= 0)
4403869fb78SDag-Erling Smørgrav 		close(cherr[1]);
4413869fb78SDag-Erling Smørgrav 	if (envlist != NULL)
4423869fb78SDag-Erling Smørgrav 		openpam_free_envlist(envlist);
4433869fb78SDag-Erling Smørgrav 	errno = serrno;
4443869fb78SDag-Erling Smørgrav 	return (pam_err);
445f65b2180SDag-Erling Smørgrav }
446f65b2180SDag-Erling Smørgrav 
447f65b2180SDag-Erling Smørgrav PAM_EXTERN int
448f65b2180SDag-Erling Smørgrav pam_sm_authenticate(pam_handle_t *pamh, int flags,
449f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
450f65b2180SDag-Erling Smørgrav {
4517e3d5c1fSJean-Sébastien Pédron 	int ret;
4523902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
453f65b2180SDag-Erling Smørgrav 
4543902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
4553902d8a9SJean-Sébastien Pédron 	if (ret != 0)
4563902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
4573902d8a9SJean-Sébastien Pédron 
4583902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
4597e3d5c1fSJean-Sébastien Pédron 
4607e3d5c1fSJean-Sébastien Pédron 	/*
4617e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
4627e3d5c1fSJean-Sébastien Pédron 	 * function.
4637e3d5c1fSJean-Sébastien Pédron 	 */
4647e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
4657e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
4667e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
4677e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTHINFO_UNAVAIL:
4687e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTH_ERR:
4697e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
4707e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
4717e3d5c1fSJean-Sébastien Pédron 	case PAM_CRED_INSUFFICIENT:
4727e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
4737e3d5c1fSJean-Sébastien Pédron 	case PAM_MAXTRIES:
4747e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
4757e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
4767e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
4777e3d5c1fSJean-Sébastien Pédron 	case PAM_USER_UNKNOWN:
4787e3d5c1fSJean-Sébastien Pédron 		break;
4797e3d5c1fSJean-Sébastien Pédron 	default:
4807e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
4817e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
4827e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
4837e3d5c1fSJean-Sébastien Pédron 	}
4847e3d5c1fSJean-Sébastien Pédron 
4857e3d5c1fSJean-Sébastien Pédron 	return (ret);
486f65b2180SDag-Erling Smørgrav }
487f65b2180SDag-Erling Smørgrav 
488f65b2180SDag-Erling Smørgrav PAM_EXTERN int
489f65b2180SDag-Erling Smørgrav pam_sm_setcred(pam_handle_t *pamh, int flags,
490f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
491f65b2180SDag-Erling Smørgrav {
4927e3d5c1fSJean-Sébastien Pédron 	int ret;
4933902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
494f65b2180SDag-Erling Smørgrav 
4953902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
4963902d8a9SJean-Sébastien Pédron 	if (ret != 0)
4973902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
4983902d8a9SJean-Sébastien Pédron 
4993902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
5007e3d5c1fSJean-Sébastien Pédron 
5017e3d5c1fSJean-Sébastien Pédron 	/*
5027e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
5037e3d5c1fSJean-Sébastien Pédron 	 * function.
5047e3d5c1fSJean-Sébastien Pédron 	 */
5057e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
5067e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
5077e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
5087e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
5097e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
5107e3d5c1fSJean-Sébastien Pédron 	case PAM_CRED_ERR:
5117e3d5c1fSJean-Sébastien Pédron 	case PAM_CRED_EXPIRED:
5127e3d5c1fSJean-Sébastien Pédron 	case PAM_CRED_UNAVAIL:
5137e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
5147e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
5157e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
5167e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
5177e3d5c1fSJean-Sébastien Pédron 	case PAM_USER_UNKNOWN:
5187e3d5c1fSJean-Sébastien Pédron 		break;
5197e3d5c1fSJean-Sébastien Pédron 	default:
5207e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
5217e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
5227e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
5237e3d5c1fSJean-Sébastien Pédron 	}
5247e3d5c1fSJean-Sébastien Pédron 
5257e3d5c1fSJean-Sébastien Pédron 	return (ret);
526f65b2180SDag-Erling Smørgrav }
527f65b2180SDag-Erling Smørgrav 
528f65b2180SDag-Erling Smørgrav PAM_EXTERN int
529f65b2180SDag-Erling Smørgrav pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
530f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
531f65b2180SDag-Erling Smørgrav {
5327e3d5c1fSJean-Sébastien Pédron 	int ret;
5333902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
534f65b2180SDag-Erling Smørgrav 
5353902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
5363902d8a9SJean-Sébastien Pédron 	if (ret != 0)
5373902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
5383902d8a9SJean-Sébastien Pédron 
5393902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
5407e3d5c1fSJean-Sébastien Pédron 
5417e3d5c1fSJean-Sébastien Pédron 	/*
5427e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
5437e3d5c1fSJean-Sébastien Pédron 	 * function.
5447e3d5c1fSJean-Sébastien Pédron 	 */
5457e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
5467e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
5477e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
5487e3d5c1fSJean-Sébastien Pédron 	case PAM_ACCT_EXPIRED:
5497e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTH_ERR:
5507e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
5517e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
5527e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
5537e3d5c1fSJean-Sébastien Pédron 	case PAM_NEW_AUTHTOK_REQD:
5547e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
5557e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
5567e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
5577e3d5c1fSJean-Sébastien Pédron 	case PAM_USER_UNKNOWN:
5587e3d5c1fSJean-Sébastien Pédron 		break;
5597e3d5c1fSJean-Sébastien Pédron 	default:
5607e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
5617e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
5627e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
5637e3d5c1fSJean-Sébastien Pédron 	}
5647e3d5c1fSJean-Sébastien Pédron 
5657e3d5c1fSJean-Sébastien Pédron 	return (ret);
566f65b2180SDag-Erling Smørgrav }
567f65b2180SDag-Erling Smørgrav 
568f65b2180SDag-Erling Smørgrav PAM_EXTERN int
569f65b2180SDag-Erling Smørgrav pam_sm_open_session(pam_handle_t *pamh, int flags,
570f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
571f65b2180SDag-Erling Smørgrav {
5727e3d5c1fSJean-Sébastien Pédron 	int ret;
5733902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
574f65b2180SDag-Erling Smørgrav 
5753902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
5763902d8a9SJean-Sébastien Pédron 	if (ret != 0)
5773902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
5783902d8a9SJean-Sébastien Pédron 
5793902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
5807e3d5c1fSJean-Sébastien Pédron 
5817e3d5c1fSJean-Sébastien Pédron 	/*
5827e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
5837e3d5c1fSJean-Sébastien Pédron 	 * function.
5847e3d5c1fSJean-Sébastien Pédron 	 */
5857e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
5867e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
5877e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
5887e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
5897e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
5907e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
5917e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
5927e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
5937e3d5c1fSJean-Sébastien Pédron 	case PAM_SESSION_ERR:
5947e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
5957e3d5c1fSJean-Sébastien Pédron 		break;
5967e3d5c1fSJean-Sébastien Pédron 	default:
5977e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
5987e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
5997e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
6007e3d5c1fSJean-Sébastien Pédron 	}
6017e3d5c1fSJean-Sébastien Pédron 
6027e3d5c1fSJean-Sébastien Pédron 	return (ret);
603f65b2180SDag-Erling Smørgrav }
604f65b2180SDag-Erling Smørgrav 
605f65b2180SDag-Erling Smørgrav PAM_EXTERN int
606f65b2180SDag-Erling Smørgrav pam_sm_close_session(pam_handle_t *pamh, int flags,
607f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
608f65b2180SDag-Erling Smørgrav {
6097e3d5c1fSJean-Sébastien Pédron 	int ret;
6103902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
611f65b2180SDag-Erling Smørgrav 
6123902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
6133902d8a9SJean-Sébastien Pédron 	if (ret != 0)
6143902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
6153902d8a9SJean-Sébastien Pédron 
6163902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
6177e3d5c1fSJean-Sébastien Pédron 
6187e3d5c1fSJean-Sébastien Pédron 	/*
6197e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
6207e3d5c1fSJean-Sébastien Pédron 	 * function.
6217e3d5c1fSJean-Sébastien Pédron 	 */
6227e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
6237e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
6247e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
6257e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
6267e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
6277e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
6287e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
6297e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
6307e3d5c1fSJean-Sébastien Pédron 	case PAM_SESSION_ERR:
6317e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
6327e3d5c1fSJean-Sébastien Pédron 		break;
6337e3d5c1fSJean-Sébastien Pédron 	default:
6347e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
6357e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
6367e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
6377e3d5c1fSJean-Sébastien Pédron 	}
6387e3d5c1fSJean-Sébastien Pédron 
6397e3d5c1fSJean-Sébastien Pédron 	return (ret);
640f65b2180SDag-Erling Smørgrav }
641f65b2180SDag-Erling Smørgrav 
642f65b2180SDag-Erling Smørgrav PAM_EXTERN int
643f65b2180SDag-Erling Smørgrav pam_sm_chauthtok(pam_handle_t *pamh, int flags,
644f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
645f65b2180SDag-Erling Smørgrav {
6467e3d5c1fSJean-Sébastien Pédron 	int ret;
6473902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
648f65b2180SDag-Erling Smørgrav 
6493902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
6503902d8a9SJean-Sébastien Pédron 	if (ret != 0)
6513902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
6523902d8a9SJean-Sébastien Pédron 
6533902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
6547e3d5c1fSJean-Sébastien Pédron 
6557e3d5c1fSJean-Sébastien Pédron 	/*
6567e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
6577e3d5c1fSJean-Sébastien Pédron 	 * function.
6587e3d5c1fSJean-Sébastien Pédron 	 */
6597e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
6607e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
6617e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
6627e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTHTOK_DISABLE_AGING:
6637e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTHTOK_ERR:
6647e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTHTOK_LOCK_BUSY:
6657e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTHTOK_RECOVERY_ERR:
6667e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
6677e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
6687e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
6697e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
6707e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
6717e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
6727e3d5c1fSJean-Sébastien Pédron 	case PAM_TRY_AGAIN:
6737e3d5c1fSJean-Sébastien Pédron 		break;
6747e3d5c1fSJean-Sébastien Pédron 	default:
6757e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
6767e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
6777e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
6787e3d5c1fSJean-Sébastien Pédron 	}
6797e3d5c1fSJean-Sébastien Pédron 
6807e3d5c1fSJean-Sébastien Pédron 	return (ret);
681f65b2180SDag-Erling Smørgrav }
682f65b2180SDag-Erling Smørgrav 
683f65b2180SDag-Erling Smørgrav PAM_MODULE_ENTRY("pam_exec");
684