xref: /freebsd/lib/libpam/modules/pam_exec/pam_exec.c (revision a2f733abcff64628b7771a47089628b7327a88bd)
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/types.h>
403869fb78SDag-Erling Smørgrav #include <sys/poll.h>
413869fb78SDag-Erling Smørgrav #include <sys/procdesc.h>
42f65b2180SDag-Erling Smørgrav #include <sys/wait.h>
43f65b2180SDag-Erling Smørgrav 
44f65b2180SDag-Erling Smørgrav #include <errno.h>
453869fb78SDag-Erling Smørgrav #include <fcntl.h>
468bdb099aSEd Schouten #include <stdio.h>
47f65b2180SDag-Erling Smørgrav #include <stdlib.h>
48f65b2180SDag-Erling Smørgrav #include <string.h>
49f65b2180SDag-Erling Smørgrav #include <unistd.h>
50f65b2180SDag-Erling Smørgrav 
51f65b2180SDag-Erling Smørgrav #include <security/pam_appl.h>
52f65b2180SDag-Erling Smørgrav #include <security/pam_modules.h>
53f65b2180SDag-Erling Smørgrav #include <security/openpam.h>
54f65b2180SDag-Erling Smørgrav 
553869fb78SDag-Erling Smørgrav #define PAM_ITEM_ENV(n) { (n), #n }
569d97c7eeSDag-Erling Smørgrav static struct {
579d97c7eeSDag-Erling Smørgrav 	int item;
589d97c7eeSDag-Erling Smørgrav 	const char *name;
593869fb78SDag-Erling Smørgrav } pam_item_env[] = {
603869fb78SDag-Erling Smørgrav 	PAM_ITEM_ENV(PAM_SERVICE),
613869fb78SDag-Erling Smørgrav 	PAM_ITEM_ENV(PAM_USER),
623869fb78SDag-Erling Smørgrav 	PAM_ITEM_ENV(PAM_TTY),
633869fb78SDag-Erling Smørgrav 	PAM_ITEM_ENV(PAM_RHOST),
643869fb78SDag-Erling Smørgrav 	PAM_ITEM_ENV(PAM_RUSER),
659d97c7eeSDag-Erling Smørgrav };
663869fb78SDag-Erling Smørgrav #define NUM_PAM_ITEM_ENV (sizeof(pam_item_env) / sizeof(pam_item_env[0]))
673869fb78SDag-Erling Smørgrav 
683869fb78SDag-Erling Smørgrav #define PAM_ERR_ENV_X(str, num) str "=" #num
693869fb78SDag-Erling Smørgrav #define PAM_ERR_ENV(pam_err) PAM_ERR_ENV_X(#pam_err, pam_err)
703869fb78SDag-Erling Smørgrav static const char *pam_err_env[] = {
713869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_SUCCESS),
723869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_OPEN_ERR),
733869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_SYMBOL_ERR),
743869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_SERVICE_ERR),
753869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_SYSTEM_ERR),
763869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_BUF_ERR),
773869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_CONV_ERR),
783869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_PERM_DENIED),
793869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_MAXTRIES),
803869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_AUTH_ERR),
813869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_NEW_AUTHTOK_REQD),
823869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_CRED_INSUFFICIENT),
833869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_AUTHINFO_UNAVAIL),
843869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_USER_UNKNOWN),
853869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_CRED_UNAVAIL),
863869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_CRED_EXPIRED),
873869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_CRED_ERR),
883869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_ACCT_EXPIRED),
893869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_AUTHTOK_EXPIRED),
903869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_SESSION_ERR),
913869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_AUTHTOK_ERR),
923869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_AUTHTOK_RECOVERY_ERR),
933869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_AUTHTOK_LOCK_BUSY),
943869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_AUTHTOK_DISABLE_AGING),
953869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_NO_MODULE_DATA),
963869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_IGNORE),
973869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_ABORT),
983869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_TRY_AGAIN),
993869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_MODULE_UNKNOWN),
1003869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_DOMAIN_UNKNOWN),
1013869fb78SDag-Erling Smørgrav 	PAM_ERR_ENV(PAM_NUM_ERR),
1023869fb78SDag-Erling Smørgrav };
1033869fb78SDag-Erling Smørgrav #define NUM_PAM_ERR_ENV (sizeof(pam_err_env) / sizeof(pam_err_env[0]))
1049d97c7eeSDag-Erling Smørgrav 
1053902d8a9SJean-Sébastien Pédron struct pe_opts {
1063902d8a9SJean-Sébastien Pédron 	int	return_prog_exit_status;
1073869fb78SDag-Erling Smørgrav 	int	capture_stdout;
1083869fb78SDag-Erling Smørgrav 	int	capture_stderr;
109bb3ba83eSDag-Erling Smørgrav 	int	expose_authtok;
1104d34b914SDag-Erling Smørgrav 	int	use_first_pass;
1113902d8a9SJean-Sébastien Pédron };
1123902d8a9SJean-Sébastien Pédron 
113f65b2180SDag-Erling Smørgrav static int
parse_options(const char * func,int * argc,const char ** argv[],struct pe_opts * options)1143902d8a9SJean-Sébastien Pédron parse_options(const char *func, int *argc, const char **argv[],
1153902d8a9SJean-Sébastien Pédron     struct pe_opts *options)
116f65b2180SDag-Erling Smørgrav {
1173902d8a9SJean-Sébastien Pédron 	int i;
1189d97c7eeSDag-Erling Smørgrav 
1199d97c7eeSDag-Erling Smørgrav 	/*
1207e3d5c1fSJean-Sébastien Pédron 	 * Parse options:
1217e3d5c1fSJean-Sébastien Pédron 	 *   return_prog_exit_status:
1227e3d5c1fSJean-Sébastien Pédron 	 *     use the program exit status as the return code of pam_exec
1237e3d5c1fSJean-Sébastien Pédron 	 *   --:
1247e3d5c1fSJean-Sébastien Pédron 	 *     stop options parsing; what follows is the command to execute
1257e3d5c1fSJean-Sébastien Pédron 	 */
1263869fb78SDag-Erling Smørgrav 	memset(options, 0, sizeof(*options));
1273902d8a9SJean-Sébastien Pédron 
1283902d8a9SJean-Sébastien Pédron 	for (i = 0; i < *argc; ++i) {
1293869fb78SDag-Erling Smørgrav 		if (strcmp((*argv)[i], "debug") == 0 ||
1303869fb78SDag-Erling Smørgrav 		    strcmp((*argv)[i], "no_warn") == 0) {
1313869fb78SDag-Erling Smørgrav 			/* ignore */
1323869fb78SDag-Erling Smørgrav 		} else if (strcmp((*argv)[i], "capture_stdout") == 0) {
1333869fb78SDag-Erling Smørgrav 			options->capture_stdout = 1;
1343869fb78SDag-Erling Smørgrav 		} else if (strcmp((*argv)[i], "capture_stderr") == 0) {
1353869fb78SDag-Erling Smørgrav 			options->capture_stderr = 1;
1363869fb78SDag-Erling Smørgrav 		} else if (strcmp((*argv)[i], "return_prog_exit_status") == 0) {
1373902d8a9SJean-Sébastien Pédron 			options->return_prog_exit_status = 1;
138bb3ba83eSDag-Erling Smørgrav 		} else if (strcmp((*argv)[i], "expose_authtok") == 0) {
139bb3ba83eSDag-Erling Smørgrav 			options->expose_authtok = 1;
1404d34b914SDag-Erling Smørgrav 		} else if (strcmp((*argv)[i], "use_first_pass") == 0) {
1414d34b914SDag-Erling Smørgrav 			options->use_first_pass = 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
_pam_exec(pam_handle_t * pamh,const char * func,int flags __unused,int argc,const char * argv[],struct pe_opts * options)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;
21922800593SDimitry Andric 		if (asprintf(&envstr, "%s=%s", pam_item_env[i].name,
22022800593SDimitry Andric 		    (const char *)item) < 0)
2213869fb78SDag-Erling Smørgrav 			OUT(PAM_BUF_ERR);
2229d97c7eeSDag-Erling Smørgrav 		envlist[envlen++] = envstr;
2239d97c7eeSDag-Erling Smørgrav 		envlist[envlen] = NULL;
2243869fb78SDag-Erling Smørgrav 		openpam_log(PAM_LOG_DEBUG, "setenv %s", envstr);
2259d97c7eeSDag-Erling Smørgrav 	}
2269d97c7eeSDag-Erling Smørgrav 
2273869fb78SDag-Erling Smørgrav 	/* add the name of the service function to the environment */
2283869fb78SDag-Erling Smørgrav 	if (asprintf(&envstr, "PAM_SM_FUNC=%s", func) < 0)
2293869fb78SDag-Erling Smørgrav 		OUT(PAM_BUF_ERR);
2307e3d5c1fSJean-Sébastien Pédron 	envlist[envlen++] = envstr;
2313869fb78SDag-Erling Smørgrav 	envlist[envlen] = NULL;
2327e3d5c1fSJean-Sébastien Pédron 
2333869fb78SDag-Erling Smørgrav 	/* add the PAM error codes to the environment. */
2343902d8a9SJean-Sébastien Pédron 	if (options->return_prog_exit_status) {
2353869fb78SDag-Erling Smørgrav 		for (i = 0; i < (int)NUM_PAM_ERR_ENV; ++i) {
2363869fb78SDag-Erling Smørgrav 			if ((envstr = strdup(pam_err_env[i])) == NULL)
2373869fb78SDag-Erling Smørgrav 				OUT(PAM_BUF_ERR);
2383869fb78SDag-Erling Smørgrav 			envlist[envlen++] = envstr;
2393869fb78SDag-Erling Smørgrav 			envlist[envlen] = NULL;
2403869fb78SDag-Erling Smørgrav 		}
2417e3d5c1fSJean-Sébastien Pédron 	}
2427e3d5c1fSJean-Sébastien Pédron 
2433869fb78SDag-Erling Smørgrav 	openpam_log(PAM_LOG_DEBUG, "envlen = %d extralen = %d envlist = %p",
2443869fb78SDag-Erling Smørgrav 	    envlen, extralen, envlist);
2457e3d5c1fSJean-Sébastien Pédron 
246bb3ba83eSDag-Erling Smørgrav 	/* set up pipe and get authtok if requested */
247bb3ba83eSDag-Erling Smørgrav 	if (options->expose_authtok) {
248bb3ba83eSDag-Erling Smørgrav 		if (pipe(chin) != 0) {
249bb3ba83eSDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func);
250bb3ba83eSDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
251bb3ba83eSDag-Erling Smørgrav 		}
252bb3ba83eSDag-Erling Smørgrav 		if (fcntl(chin[1], F_SETFL, O_NONBLOCK)) {
253bb3ba83eSDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: fcntl(): %m", func);
254bb3ba83eSDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
255bb3ba83eSDag-Erling Smørgrav 		}
2564d34b914SDag-Erling Smørgrav 		if (options->use_first_pass ||
2574d34b914SDag-Erling Smørgrav 		    strcmp(func, "pam_sm_setcred") == 0) {
2584d34b914SDag-Erling Smørgrav 			/* don't prompt, only expose existing token */
2594d34b914SDag-Erling Smørgrav 			rc = pam_get_item(pamh, PAM_AUTHTOK, &item);
2604d34b914SDag-Erling Smørgrav 			authtok = item;
261*b75e0eedSYan Ka Chiu 			if (authtok == NULL && rc == PAM_SUCCESS) {
262*b75e0eedSYan Ka Chiu 				openpam_log(PAM_LOG_ERROR,
263*b75e0eedSYan Ka Chiu 				    "%s: pam_get_authtok(): %s",
264*b75e0eedSYan Ka Chiu 				    func, "authentication token not available");
265*b75e0eedSYan Ka Chiu 				OUT(PAM_SYSTEM_ERR);
266*b75e0eedSYan Ka Chiu 			}
267*b75e0eedSYan Ka Chiu 
2684d34b914SDag-Erling Smørgrav 		} else {
269bb3ba83eSDag-Erling Smørgrav 			rc = pam_get_authtok(pamh, PAM_AUTHTOK, &authtok, NULL);
2704d34b914SDag-Erling Smørgrav 		}
271bb3ba83eSDag-Erling Smørgrav 		if (rc == PAM_SUCCESS) {
2724d34b914SDag-Erling Smørgrav 			/* We include the trailing null terminator. */
273e165d7bcSDag-Erling Smørgrav 			authtok_size = strlen(authtok) + 1;
274bb3ba83eSDag-Erling Smørgrav 		} else {
2754d34b914SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: pam_get_authtok(): %s",
2764d34b914SDag-Erling Smørgrav 			    func, pam_strerror(pamh, rc));
277bb3ba83eSDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
278bb3ba83eSDag-Erling Smørgrav 		}
279bb3ba83eSDag-Erling Smørgrav 	}
2803869fb78SDag-Erling Smørgrav 	/* set up pipes if capture was requested */
2813869fb78SDag-Erling Smørgrav 	if (options->capture_stdout) {
2823869fb78SDag-Erling Smørgrav 		if (pipe(chout) != 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(chout[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 ((chout[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 	if (options->capture_stderr) {
2973869fb78SDag-Erling Smørgrav 		if (pipe(cherr) != 0) {
2983869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func);
2993869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
3003869fb78SDag-Erling Smørgrav 		}
3013869fb78SDag-Erling Smørgrav 		if (fcntl(cherr[0], F_SETFL, O_NONBLOCK) != 0) {
3023869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: fcntl(): %m", func);
3033869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
3043869fb78SDag-Erling Smørgrav 		}
3053869fb78SDag-Erling Smørgrav 	} else {
3063869fb78SDag-Erling Smørgrav 		if ((cherr[1] = open("/dev/null", O_RDWR)) < 0) {
3073869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: /dev/null: %m", func);
3083869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
3093869fb78SDag-Erling Smørgrav 		}
3103869fb78SDag-Erling Smørgrav 	}
3113869fb78SDag-Erling Smørgrav 
3123869fb78SDag-Erling Smørgrav 	if ((pid = pdfork(&pd, 0)) == 0) {
3133869fb78SDag-Erling Smørgrav 		/* child */
314bb3ba83eSDag-Erling Smørgrav 		if ((chin[1] >= 0 && close(chin[1]) != 0) ||
315bb3ba83eSDag-Erling Smørgrav 			(chout[0] >= 0 && close(chout[0]) != 0) ||
3163869fb78SDag-Erling Smørgrav 		    (cherr[0] >= 0 && close(cherr[0]) != 0)) {
3173869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: close(): %m", func);
318bb3ba83eSDag-Erling Smørgrav 		} else if (chin[0] >= 0 &&
319bb3ba83eSDag-Erling Smørgrav 			dup2(chin[0], STDIN_FILENO) != STDIN_FILENO) {
320bb3ba83eSDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: dup2(): %m", func);
3213869fb78SDag-Erling Smørgrav 		} else if (dup2(chout[1], STDOUT_FILENO) != STDOUT_FILENO ||
3223869fb78SDag-Erling Smørgrav 		    dup2(cherr[1], STDERR_FILENO) != STDERR_FILENO) {
3233869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: dup2(): %m", func);
3243869fb78SDag-Erling Smørgrav 		} else {
3253869fb78SDag-Erling Smørgrav 			execve(argv[0], (char * const *)argv,
3263869fb78SDag-Erling Smørgrav 			    (char * const *)envlist);
3273869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: execve(%s): %m",
3283869fb78SDag-Erling Smørgrav 			    func, argv[0]);
3293869fb78SDag-Erling Smørgrav 		}
330f65b2180SDag-Erling Smørgrav 		_exit(1);
331a76a4d44SDag-Erling Smørgrav 	}
3323869fb78SDag-Erling Smørgrav 	/* parent */
333a76a4d44SDag-Erling Smørgrav 	if (pid == -1) {
3343869fb78SDag-Erling Smørgrav 		openpam_log(PAM_LOG_ERROR, "%s: pdfork(): %m", func);
3353869fb78SDag-Erling Smørgrav 		OUT(PAM_SYSTEM_ERR);
336f65b2180SDag-Erling Smørgrav 	}
337bb3ba83eSDag-Erling Smørgrav 	/* use poll() to watch the process and stdin / stdout / stderr */
338bb3ba83eSDag-Erling Smørgrav 	if (chin[0] >= 0)
339bb3ba83eSDag-Erling Smørgrav 		close(chin[0]);
3403869fb78SDag-Erling Smørgrav 	if (chout[1] >= 0)
3413869fb78SDag-Erling Smørgrav 		close(chout[1]);
3423869fb78SDag-Erling Smørgrav 	if (cherr[1] >= 0)
3433869fb78SDag-Erling Smørgrav 		close(cherr[1]);
3443869fb78SDag-Erling Smørgrav 	memset(pfd, 0, sizeof pfd);
3453869fb78SDag-Erling Smørgrav 	pfd[0].fd = pd;
3463869fb78SDag-Erling Smørgrav 	pfd[0].events = POLLHUP;
3473869fb78SDag-Erling Smørgrav 	nfds = 1;
348bb3ba83eSDag-Erling Smørgrav 	nreadfds = 0;
3493869fb78SDag-Erling Smørgrav 	if (options->capture_stdout) {
3503869fb78SDag-Erling Smørgrav 		pfd[nfds].fd = chout[0];
3513869fb78SDag-Erling Smørgrav 		pfd[nfds].events = POLLIN|POLLERR|POLLHUP;
3523869fb78SDag-Erling Smørgrav 		nfds++;
353bb3ba83eSDag-Erling Smørgrav 		nreadfds++;
3543869fb78SDag-Erling Smørgrav 	}
3553869fb78SDag-Erling Smørgrav 	if (options->capture_stderr) {
3563869fb78SDag-Erling Smørgrav 		pfd[nfds].fd = cherr[0];
3573869fb78SDag-Erling Smørgrav 		pfd[nfds].events = POLLIN|POLLERR|POLLHUP;
3583869fb78SDag-Erling Smørgrav 		nfds++;
359bb3ba83eSDag-Erling Smørgrav 		nreadfds++;
360bb3ba83eSDag-Erling Smørgrav 	}
361bb3ba83eSDag-Erling Smørgrav 	if (options->expose_authtok) {
362bb3ba83eSDag-Erling Smørgrav 		pfd[nfds].fd = chin[1];
363bb3ba83eSDag-Erling Smørgrav 		pfd[nfds].events = POLLOUT|POLLERR|POLLHUP;
364bb3ba83eSDag-Erling Smørgrav 		nfds++;
3653869fb78SDag-Erling Smørgrav 	}
3663869fb78SDag-Erling Smørgrav 
3673869fb78SDag-Erling Smørgrav 	/* loop until the process exits */
3683869fb78SDag-Erling Smørgrav 	do {
3693869fb78SDag-Erling Smørgrav 		if (poll(pfd, nfds, INFTIM) < 0) {
3703869fb78SDag-Erling Smørgrav 			openpam_log(PAM_LOG_ERROR, "%s: poll(): %m", func);
3713869fb78SDag-Erling Smørgrav 			OUT(PAM_SYSTEM_ERR);
3723869fb78SDag-Erling Smørgrav 		}
373bb3ba83eSDag-Erling Smørgrav 		/* are the stderr / stdout pipes ready for reading? */
374bb3ba83eSDag-Erling Smørgrav 		for (i = 1; i < 1 + nreadfds; ++i) {
3753869fb78SDag-Erling Smørgrav 			if ((pfd[i].revents & POLLIN) == 0)
3763869fb78SDag-Erling Smørgrav 				continue;
3773869fb78SDag-Erling Smørgrav 			if ((rlen = read(pfd[i].fd, buf, sizeof(buf) - 1)) < 0) {
3783869fb78SDag-Erling Smørgrav 				openpam_log(PAM_LOG_ERROR, "%s: read(): %m",
3793869fb78SDag-Erling Smørgrav 				    func);
3803869fb78SDag-Erling Smørgrav 				OUT(PAM_SYSTEM_ERR);
3813869fb78SDag-Erling Smørgrav 			} else if (rlen == 0) {
3823869fb78SDag-Erling Smørgrav 				continue;
3833869fb78SDag-Erling Smørgrav 			}
3843869fb78SDag-Erling Smørgrav 			buf[rlen] = '\0';
3853869fb78SDag-Erling Smørgrav 			(void)pam_prompt(pamh, pfd[i].fd == chout[0] ?
3863869fb78SDag-Erling Smørgrav 			    PAM_TEXT_INFO : PAM_ERROR_MSG, &resp, "%s", buf);
3873869fb78SDag-Erling Smørgrav 		}
388bb3ba83eSDag-Erling Smørgrav 		/* is the stdin pipe ready for writing? */
389bb3ba83eSDag-Erling Smørgrav 		if (options->expose_authtok && authtok_size > 0 &&
390bb3ba83eSDag-Erling Smørgrav 			(pfd[nfds - 1].revents & POLLOUT) != 0) {
391bb3ba83eSDag-Erling Smørgrav 			if ((wlen = write(chin[1], authtok, authtok_size)) < 0) {
392bb3ba83eSDag-Erling Smørgrav 				if (errno == EAGAIN)
393bb3ba83eSDag-Erling Smørgrav 					continue;
394bb3ba83eSDag-Erling Smørgrav 				openpam_log(PAM_LOG_ERROR, "%s: write(): %m",
395bb3ba83eSDag-Erling Smørgrav 				    func);
396bb3ba83eSDag-Erling Smørgrav 				OUT(PAM_SYSTEM_ERR);
397bb3ba83eSDag-Erling Smørgrav 			} else {
398bb3ba83eSDag-Erling Smørgrav 				authtok += wlen;
399bb3ba83eSDag-Erling Smørgrav 				authtok_size -= wlen;
400bb3ba83eSDag-Erling Smørgrav 				if (authtok_size == 0) {
401bb3ba83eSDag-Erling Smørgrav 					/* finished writing; close and forget the pipe */
402bb3ba83eSDag-Erling Smørgrav 					close(chin[1]);
403bb3ba83eSDag-Erling Smørgrav 					chin[1] = -1;
404bb3ba83eSDag-Erling Smørgrav 					nfds--;
405bb3ba83eSDag-Erling Smørgrav 				}
406bb3ba83eSDag-Erling Smørgrav 			}
407bb3ba83eSDag-Erling Smørgrav 		}
4083869fb78SDag-Erling Smørgrav 	} while (pfd[0].revents == 0);
4093869fb78SDag-Erling Smørgrav 
4103869fb78SDag-Erling Smørgrav 	/* the child process has exited */
4117e3d5c1fSJean-Sébastien Pédron 	while (waitpid(pid, &status, 0) == -1) {
4127e3d5c1fSJean-Sébastien Pédron 		if (errno == EINTR)
4137e3d5c1fSJean-Sébastien Pédron 			continue;
4147e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s: waitpid(): %m", func);
4153869fb78SDag-Erling Smørgrav 		OUT(PAM_SYSTEM_ERR);
416f65b2180SDag-Erling Smørgrav 	}
4173869fb78SDag-Erling Smørgrav 
4183869fb78SDag-Erling Smørgrav 	/* check exit code */
419f65b2180SDag-Erling Smørgrav 	if (WIFSIGNALED(status)) {
4207e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s: %s caught signal %d%s",
4217e3d5c1fSJean-Sébastien Pédron 		    func, argv[0], WTERMSIG(status),
422f65b2180SDag-Erling Smørgrav 		    WCOREDUMP(status) ? " (core dumped)" : "");
4233869fb78SDag-Erling Smørgrav 		OUT(PAM_SERVICE_ERR);
424f65b2180SDag-Erling Smørgrav 	}
425f65b2180SDag-Erling Smørgrav 	if (!WIFEXITED(status)) {
4267e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s: unknown status 0x%x",
4277e3d5c1fSJean-Sébastien Pédron 		    func, status);
4283869fb78SDag-Erling Smørgrav 		OUT(PAM_SERVICE_ERR);
429f65b2180SDag-Erling Smørgrav 	}
4307e3d5c1fSJean-Sébastien Pédron 
4313902d8a9SJean-Sébastien Pédron 	if (options->return_prog_exit_status) {
4327e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_DEBUG,
4337e3d5c1fSJean-Sébastien Pédron 		    "%s: Use program exit status as return value: %d",
4347e3d5c1fSJean-Sébastien Pédron 		    func, WEXITSTATUS(status));
4353869fb78SDag-Erling Smørgrav 		OUT(WEXITSTATUS(status));
4367e3d5c1fSJean-Sébastien Pédron 	} else {
4373869fb78SDag-Erling Smørgrav 		OUT(WEXITSTATUS(status) == 0 ? PAM_SUCCESS : PAM_PERM_DENIED);
438f65b2180SDag-Erling Smørgrav 	}
4393869fb78SDag-Erling Smørgrav 	/* unreachable */
4403869fb78SDag-Erling Smørgrav out:
4413869fb78SDag-Erling Smørgrav 	serrno = errno;
4423869fb78SDag-Erling Smørgrav 	if (pd >= 0)
4433869fb78SDag-Erling Smørgrav 		close(pd);
444bb3ba83eSDag-Erling Smørgrav 	if (chin[0] >= 0)
445bb3ba83eSDag-Erling Smørgrav 		close(chin[0]);
446bb3ba83eSDag-Erling Smørgrav 	if (chin[1] >= 0)
447bb3ba83eSDag-Erling Smørgrav 		close(chin[1]);
4483869fb78SDag-Erling Smørgrav 	if (chout[0] >= 0)
4493869fb78SDag-Erling Smørgrav 		close(chout[0]);
4503869fb78SDag-Erling Smørgrav 	if (chout[1] >= 0)
4513869fb78SDag-Erling Smørgrav 		close(chout[1]);
4523869fb78SDag-Erling Smørgrav 	if (cherr[0] >= 0)
4533869fb78SDag-Erling Smørgrav 		close(cherr[0]);
4543869fb78SDag-Erling Smørgrav 	if (cherr[0] >= 0)
4553869fb78SDag-Erling Smørgrav 		close(cherr[1]);
4563869fb78SDag-Erling Smørgrav 	if (envlist != NULL)
4573869fb78SDag-Erling Smørgrav 		openpam_free_envlist(envlist);
4583869fb78SDag-Erling Smørgrav 	errno = serrno;
4593869fb78SDag-Erling Smørgrav 	return (pam_err);
460f65b2180SDag-Erling Smørgrav }
461f65b2180SDag-Erling Smørgrav 
462f65b2180SDag-Erling Smørgrav PAM_EXTERN int
pam_sm_authenticate(pam_handle_t * pamh,int flags,int argc,const char * argv[])463f65b2180SDag-Erling Smørgrav pam_sm_authenticate(pam_handle_t *pamh, int flags,
464f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
465f65b2180SDag-Erling Smørgrav {
4667e3d5c1fSJean-Sébastien Pédron 	int ret;
4673902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
468f65b2180SDag-Erling Smørgrav 
4693902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
4703902d8a9SJean-Sébastien Pédron 	if (ret != 0)
4713902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
4723902d8a9SJean-Sébastien Pédron 
4733902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
4747e3d5c1fSJean-Sébastien Pédron 
4757e3d5c1fSJean-Sébastien Pédron 	/*
4767e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
4777e3d5c1fSJean-Sébastien Pédron 	 * function.
4787e3d5c1fSJean-Sébastien Pédron 	 */
4797e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
4807e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
4817e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
4827e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTHINFO_UNAVAIL:
4837e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTH_ERR:
4847e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
4857e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
4867e3d5c1fSJean-Sébastien Pédron 	case PAM_CRED_INSUFFICIENT:
4877e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
4887e3d5c1fSJean-Sébastien Pédron 	case PAM_MAXTRIES:
4897e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
4907e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
4917e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
4927e3d5c1fSJean-Sébastien Pédron 	case PAM_USER_UNKNOWN:
4937e3d5c1fSJean-Sébastien Pédron 		break;
4947e3d5c1fSJean-Sébastien Pédron 	default:
4957e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
4967e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
4977e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
4987e3d5c1fSJean-Sébastien Pédron 	}
4997e3d5c1fSJean-Sébastien Pédron 
5007e3d5c1fSJean-Sébastien Pédron 	return (ret);
501f65b2180SDag-Erling Smørgrav }
502f65b2180SDag-Erling Smørgrav 
503f65b2180SDag-Erling Smørgrav PAM_EXTERN int
pam_sm_setcred(pam_handle_t * pamh,int flags,int argc,const char * argv[])504f65b2180SDag-Erling Smørgrav pam_sm_setcred(pam_handle_t *pamh, int flags,
505f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
506f65b2180SDag-Erling Smørgrav {
5077e3d5c1fSJean-Sébastien Pédron 	int ret;
5083902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
509f65b2180SDag-Erling Smørgrav 
5103902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
5113902d8a9SJean-Sébastien Pédron 	if (ret != 0)
5123902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
5133902d8a9SJean-Sébastien Pédron 
5143902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
5157e3d5c1fSJean-Sébastien Pédron 
5167e3d5c1fSJean-Sébastien Pédron 	/*
5177e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
5187e3d5c1fSJean-Sébastien Pédron 	 * function.
5197e3d5c1fSJean-Sébastien Pédron 	 */
5207e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
5217e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
5227e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
5237e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
5247e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
5257e3d5c1fSJean-Sébastien Pédron 	case PAM_CRED_ERR:
5267e3d5c1fSJean-Sébastien Pédron 	case PAM_CRED_EXPIRED:
5277e3d5c1fSJean-Sébastien Pédron 	case PAM_CRED_UNAVAIL:
5287e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
5297e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
5307e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
5317e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
5327e3d5c1fSJean-Sébastien Pédron 	case PAM_USER_UNKNOWN:
5337e3d5c1fSJean-Sébastien Pédron 		break;
5347e3d5c1fSJean-Sébastien Pédron 	default:
5357e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
5367e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
5377e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
5387e3d5c1fSJean-Sébastien Pédron 	}
5397e3d5c1fSJean-Sébastien Pédron 
5407e3d5c1fSJean-Sébastien Pédron 	return (ret);
541f65b2180SDag-Erling Smørgrav }
542f65b2180SDag-Erling Smørgrav 
543f65b2180SDag-Erling Smørgrav PAM_EXTERN int
pam_sm_acct_mgmt(pam_handle_t * pamh,int flags,int argc,const char * argv[])544f65b2180SDag-Erling Smørgrav pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
545f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
546f65b2180SDag-Erling Smørgrav {
5477e3d5c1fSJean-Sébastien Pédron 	int ret;
5483902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
549f65b2180SDag-Erling Smørgrav 
5503902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
5513902d8a9SJean-Sébastien Pédron 	if (ret != 0)
5523902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
5533902d8a9SJean-Sébastien Pédron 
5543902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
5557e3d5c1fSJean-Sébastien Pédron 
5567e3d5c1fSJean-Sébastien Pédron 	/*
5577e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
5587e3d5c1fSJean-Sébastien Pédron 	 * function.
5597e3d5c1fSJean-Sébastien Pédron 	 */
5607e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
5617e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
5627e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
5637e3d5c1fSJean-Sébastien Pédron 	case PAM_ACCT_EXPIRED:
5647e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTH_ERR:
5657e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
5667e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
5677e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
5687e3d5c1fSJean-Sébastien Pédron 	case PAM_NEW_AUTHTOK_REQD:
5697e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
5707e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
5717e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
5727e3d5c1fSJean-Sébastien Pédron 	case PAM_USER_UNKNOWN:
5737e3d5c1fSJean-Sébastien Pédron 		break;
5747e3d5c1fSJean-Sébastien Pédron 	default:
5757e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
5767e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
5777e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
5787e3d5c1fSJean-Sébastien Pédron 	}
5797e3d5c1fSJean-Sébastien Pédron 
5807e3d5c1fSJean-Sébastien Pédron 	return (ret);
581f65b2180SDag-Erling Smørgrav }
582f65b2180SDag-Erling Smørgrav 
583f65b2180SDag-Erling Smørgrav PAM_EXTERN int
pam_sm_open_session(pam_handle_t * pamh,int flags,int argc,const char * argv[])584f65b2180SDag-Erling Smørgrav pam_sm_open_session(pam_handle_t *pamh, int flags,
585f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
586f65b2180SDag-Erling Smørgrav {
5877e3d5c1fSJean-Sébastien Pédron 	int ret;
5883902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
589f65b2180SDag-Erling Smørgrav 
5903902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
5913902d8a9SJean-Sébastien Pédron 	if (ret != 0)
5923902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
5933902d8a9SJean-Sébastien Pédron 
5943902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
5957e3d5c1fSJean-Sébastien Pédron 
5967e3d5c1fSJean-Sébastien Pédron 	/*
5977e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
5987e3d5c1fSJean-Sébastien Pédron 	 * function.
5997e3d5c1fSJean-Sébastien Pédron 	 */
6007e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
6017e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
6027e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
6037e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
6047e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
6057e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
6067e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
6077e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
6087e3d5c1fSJean-Sébastien Pédron 	case PAM_SESSION_ERR:
6097e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
6107e3d5c1fSJean-Sébastien Pédron 		break;
6117e3d5c1fSJean-Sébastien Pédron 	default:
6127e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
6137e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
6147e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
6157e3d5c1fSJean-Sébastien Pédron 	}
6167e3d5c1fSJean-Sébastien Pédron 
6177e3d5c1fSJean-Sébastien Pédron 	return (ret);
618f65b2180SDag-Erling Smørgrav }
619f65b2180SDag-Erling Smørgrav 
620f65b2180SDag-Erling Smørgrav PAM_EXTERN int
pam_sm_close_session(pam_handle_t * pamh,int flags,int argc,const char * argv[])621f65b2180SDag-Erling Smørgrav pam_sm_close_session(pam_handle_t *pamh, int flags,
622f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
623f65b2180SDag-Erling Smørgrav {
6247e3d5c1fSJean-Sébastien Pédron 	int ret;
6253902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
626f65b2180SDag-Erling Smørgrav 
6273902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
6283902d8a9SJean-Sébastien Pédron 	if (ret != 0)
6293902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
6303902d8a9SJean-Sébastien Pédron 
6313902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
6327e3d5c1fSJean-Sébastien Pédron 
6337e3d5c1fSJean-Sébastien Pédron 	/*
6347e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
6357e3d5c1fSJean-Sébastien Pédron 	 * function.
6367e3d5c1fSJean-Sébastien Pédron 	 */
6377e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
6387e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
6397e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
6407e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
6417e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
6427e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
6437e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
6447e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
6457e3d5c1fSJean-Sébastien Pédron 	case PAM_SESSION_ERR:
6467e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
6477e3d5c1fSJean-Sébastien Pédron 		break;
6487e3d5c1fSJean-Sébastien Pédron 	default:
6497e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
6507e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
6517e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
6527e3d5c1fSJean-Sébastien Pédron 	}
6537e3d5c1fSJean-Sébastien Pédron 
6547e3d5c1fSJean-Sébastien Pédron 	return (ret);
655f65b2180SDag-Erling Smørgrav }
656f65b2180SDag-Erling Smørgrav 
657f65b2180SDag-Erling Smørgrav PAM_EXTERN int
pam_sm_chauthtok(pam_handle_t * pamh,int flags,int argc,const char * argv[])658f65b2180SDag-Erling Smørgrav pam_sm_chauthtok(pam_handle_t *pamh, int flags,
659f65b2180SDag-Erling Smørgrav     int argc, const char *argv[])
660f65b2180SDag-Erling Smørgrav {
6617e3d5c1fSJean-Sébastien Pédron 	int ret;
6623902d8a9SJean-Sébastien Pédron 	struct pe_opts options;
663f65b2180SDag-Erling Smørgrav 
6643902d8a9SJean-Sébastien Pédron 	ret = parse_options(__func__, &argc, &argv, &options);
6653902d8a9SJean-Sébastien Pédron 	if (ret != 0)
6663902d8a9SJean-Sébastien Pédron 		return (PAM_SERVICE_ERR);
6673902d8a9SJean-Sébastien Pédron 
6683902d8a9SJean-Sébastien Pédron 	ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
6697e3d5c1fSJean-Sébastien Pédron 
6707e3d5c1fSJean-Sébastien Pédron 	/*
6717e3d5c1fSJean-Sébastien Pédron 	 * We must check that the program returned a valid code for this
6727e3d5c1fSJean-Sébastien Pédron 	 * function.
6737e3d5c1fSJean-Sébastien Pédron 	 */
6747e3d5c1fSJean-Sébastien Pédron 	switch (ret) {
6757e3d5c1fSJean-Sébastien Pédron 	case PAM_SUCCESS:
6767e3d5c1fSJean-Sébastien Pédron 	case PAM_ABORT:
6777e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTHTOK_DISABLE_AGING:
6787e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTHTOK_ERR:
6797e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTHTOK_LOCK_BUSY:
6807e3d5c1fSJean-Sébastien Pédron 	case PAM_AUTHTOK_RECOVERY_ERR:
6817e3d5c1fSJean-Sébastien Pédron 	case PAM_BUF_ERR:
6827e3d5c1fSJean-Sébastien Pédron 	case PAM_CONV_ERR:
6837e3d5c1fSJean-Sébastien Pédron 	case PAM_IGNORE:
6847e3d5c1fSJean-Sébastien Pédron 	case PAM_PERM_DENIED:
6857e3d5c1fSJean-Sébastien Pédron 	case PAM_SERVICE_ERR:
6867e3d5c1fSJean-Sébastien Pédron 	case PAM_SYSTEM_ERR:
6877e3d5c1fSJean-Sébastien Pédron 	case PAM_TRY_AGAIN:
6887e3d5c1fSJean-Sébastien Pédron 		break;
6897e3d5c1fSJean-Sébastien Pédron 	default:
6907e3d5c1fSJean-Sébastien Pédron 		openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
6917e3d5c1fSJean-Sébastien Pédron 		    argv[0], ret);
6927e3d5c1fSJean-Sébastien Pédron 		ret = PAM_SERVICE_ERR;
6937e3d5c1fSJean-Sébastien Pédron 	}
6947e3d5c1fSJean-Sébastien Pédron 
6957e3d5c1fSJean-Sébastien Pédron 	return (ret);
696f65b2180SDag-Erling Smørgrav }
697f65b2180SDag-Erling Smørgrav 
698f65b2180SDag-Erling Smørgrav PAM_MODULE_ENTRY("pam_exec");
699