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