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