197182Sdes/*- 2110448Sdes * Copyright (c) 2001,2003 Networks Associates Technology, Inc. 397182Sdes * All rights reserved. 497182Sdes * 597182Sdes * This software was developed for the FreeBSD Project by ThinkSec AS and 697182Sdes * NAI Labs, the Security Research Division of Network Associates, Inc. 797182Sdes * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 897182Sdes * DARPA CHATS research program. 997182Sdes * 1097182Sdes * Redistribution and use in source and binary forms, with or without 1197182Sdes * modification, are permitted provided that the following conditions 1297182Sdes * are met: 1397182Sdes * 1. Redistributions of source code must retain the above copyright 1497182Sdes * notice, this list of conditions and the following disclaimer. 1597182Sdes * 2. Redistributions in binary form must reproduce the above copyright 1697182Sdes * notice, this list of conditions and the following disclaimer in the 1797182Sdes * documentation and/or other materials provided with the distribution. 1897182Sdes * 3. The name of the author may not be used to endorse or promote 1997182Sdes * products derived from this software without specific prior written 2097182Sdes * permission. 2197182Sdes * 2297182Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2397182Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2497182Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2597182Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2697182Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2797182Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2897182Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2997182Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3097182Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3197182Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3297182Sdes * SUCH DAMAGE. 3397182Sdes */ 3497182Sdes 3597182Sdes#include <sys/cdefs.h> 3697182Sdes__FBSDID("$FreeBSD$"); 3797182Sdes 3897182Sdes#include <sys/types.h> 3997182Sdes#include <sys/wait.h> 4097182Sdes 4197182Sdes#include <errno.h> 42194188Sed#include <stdio.h> 4397182Sdes#include <stdlib.h> 4497182Sdes#include <string.h> 4597182Sdes#include <unistd.h> 4697182Sdes 4797182Sdes#include <security/pam_appl.h> 4897182Sdes#include <security/pam_modules.h> 4997182Sdes#include <security/openpam.h> 5097182Sdes 51141102Sdes#define ENV_ITEM(n) { (n), #n } 52141102Sdesstatic struct { 53141102Sdes int item; 54141102Sdes const char *name; 55141102Sdes} env_items[] = { 56141102Sdes ENV_ITEM(PAM_SERVICE), 57141102Sdes ENV_ITEM(PAM_USER), 58141102Sdes ENV_ITEM(PAM_TTY), 59141102Sdes ENV_ITEM(PAM_RHOST), 60141102Sdes ENV_ITEM(PAM_RUSER), 61141102Sdes}; 62141102Sdes 63234184Sdumbbellstruct pe_opts { 64234184Sdumbbell int return_prog_exit_status; 65234184Sdumbbell}; 66234184Sdumbbell 67233507Sdumbbell#define PAM_RV_COUNT 24 68233507Sdumbbell 6997182Sdesstatic int 70234184Sdumbbellparse_options(const char *func, int *argc, const char **argv[], 71234184Sdumbbell struct pe_opts *options) 7297182Sdes{ 73234184Sdumbbell int i; 7497182Sdes 7597182Sdes /* 76233507Sdumbbell * Parse options: 77233507Sdumbbell * return_prog_exit_status: 78233507Sdumbbell * use the program exit status as the return code of pam_exec 79233507Sdumbbell * --: 80233507Sdumbbell * stop options parsing; what follows is the command to execute 81141102Sdes */ 82234184Sdumbbell options->return_prog_exit_status = 0; 83234184Sdumbbell 84234184Sdumbbell for (i = 0; i < *argc; ++i) { 85234184Sdumbbell if (strcmp((*argv)[i], "return_prog_exit_status") == 0) { 86233507Sdumbbell openpam_log(PAM_LOG_DEBUG, 87233507Sdumbbell "%s: Option \"return_prog_exit_status\" enabled", 88233507Sdumbbell func); 89234184Sdumbbell options->return_prog_exit_status = 1; 90233507Sdumbbell } else { 91234184Sdumbbell if (strcmp((*argv)[i], "--") == 0) { 92234184Sdumbbell (*argc)--; 93234184Sdumbbell (*argv)++; 94233507Sdumbbell } 95233507Sdumbbell 96233507Sdumbbell break; 97233507Sdumbbell } 98233507Sdumbbell } 99233507Sdumbbell 100234184Sdumbbell (*argc) -= i; 101234184Sdumbbell (*argv) += i; 102233507Sdumbbell 103234184Sdumbbell return (0); 104234184Sdumbbell} 105234184Sdumbbell 106234184Sdumbbellstatic int 107234184Sdumbbell_pam_exec(pam_handle_t *pamh __unused, 108234184Sdumbbell const char *func, int flags __unused, int argc, const char *argv[], 109234184Sdumbbell struct pe_opts *options) 110234184Sdumbbell{ 111234184Sdumbbell int envlen, i, nitems, pam_err, status; 112234184Sdumbbell int nitems_rv; 113234184Sdumbbell char **envlist, **tmp, *envstr; 114234184Sdumbbell volatile int childerr; 115234184Sdumbbell pid_t pid; 116234184Sdumbbell 117234184Sdumbbell /* 118234184Sdumbbell * XXX For additional credit, divert child's stdin/stdout/stderr 119234184Sdumbbell * to the conversation function. 120234184Sdumbbell */ 121234184Sdumbbell 122233507Sdumbbell /* Check there's a program name left after parsing options. */ 123233507Sdumbbell if (argc < 1) { 124233507Sdumbbell openpam_log(PAM_LOG_ERROR, "%s: No program specified: aborting", 125233507Sdumbbell func); 126233507Sdumbbell return (PAM_SERVICE_ERR); 127233507Sdumbbell } 128233507Sdumbbell 129233507Sdumbbell /* 130233507Sdumbbell * Set up the child's environment list. It consists of the PAM 131233507Sdumbbell * environment, plus a few hand-picked PAM items, the pam_sm_* 132233507Sdumbbell * function name calling it and, if return_prog_exit_status is 133233507Sdumbbell * set, the valid return codes numerical values. 134233507Sdumbbell */ 135110446Sdes envlist = pam_getenvlist(pamh); 136141102Sdes for (envlen = 0; envlist[envlen] != NULL; ++envlen) 137141102Sdes /* nothing */ ; 138141102Sdes nitems = sizeof(env_items) / sizeof(*env_items); 139233507Sdumbbell /* Count PAM return values put in the environment. */ 140234184Sdumbbell nitems_rv = options->return_prog_exit_status ? PAM_RV_COUNT : 0; 141233507Sdumbbell tmp = realloc(envlist, (envlen + nitems + 1 + nitems_rv + 1) * 142233507Sdumbbell sizeof(*envlist)); 143141102Sdes if (tmp == NULL) { 144141102Sdes openpam_free_envlist(envlist); 145141102Sdes return (PAM_BUF_ERR); 146141102Sdes } 147141102Sdes envlist = tmp; 148141102Sdes for (i = 0; i < nitems; ++i) { 149141102Sdes const void *item; 150141102Sdes 151141102Sdes pam_err = pam_get_item(pamh, env_items[i].item, &item); 152141102Sdes if (pam_err != PAM_SUCCESS || item == NULL) 153141102Sdes continue; 154234184Sdumbbell asprintf(&envstr, "%s=%s", env_items[i].name, 155234184Sdumbbell (const char *)item); 156141102Sdes if (envstr == NULL) { 157141102Sdes openpam_free_envlist(envlist); 158141102Sdes return (PAM_BUF_ERR); 159141102Sdes } 160141102Sdes envlist[envlen++] = envstr; 161141102Sdes envlist[envlen] = NULL; 162141102Sdes } 163141102Sdes 164233507Sdumbbell /* Add the pam_sm_* function name to the environment. */ 165233507Sdumbbell asprintf(&envstr, "PAM_SM_FUNC=%s", func); 166233507Sdumbbell if (envstr == NULL) { 167233507Sdumbbell openpam_free_envlist(envlist); 168233507Sdumbbell return (PAM_BUF_ERR); 169233507Sdumbbell } 170233507Sdumbbell envlist[envlen++] = envstr; 171233507Sdumbbell 172233507Sdumbbell /* Add the PAM return values to the environment. */ 173234184Sdumbbell if (options->return_prog_exit_status) { 174233507Sdumbbell#define ADD_PAM_RV_TO_ENV(name) \ 175233507Sdumbbell asprintf(&envstr, #name "=%d", name); \ 176233507Sdumbbell if (envstr == NULL) { \ 177233507Sdumbbell openpam_free_envlist(envlist); \ 178233507Sdumbbell return (PAM_BUF_ERR); \ 179233507Sdumbbell } \ 180233507Sdumbbell envlist[envlen++] = envstr 181233507Sdumbbell /* 182233507Sdumbbell * CAUTION: When adding/removing an item in the list 183233507Sdumbbell * below, be sure to update the value of PAM_RV_COUNT. 184233507Sdumbbell */ 185233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_ABORT); 186233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_ACCT_EXPIRED); 187233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_AUTHINFO_UNAVAIL); 188233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_AUTHTOK_DISABLE_AGING); 189233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_AUTHTOK_ERR); 190233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_AUTHTOK_LOCK_BUSY); 191233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_AUTHTOK_RECOVERY_ERR); 192233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_AUTH_ERR); 193233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_BUF_ERR); 194233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_CONV_ERR); 195233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_CRED_ERR); 196233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_CRED_EXPIRED); 197233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_CRED_INSUFFICIENT); 198233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_CRED_UNAVAIL); 199233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_IGNORE); 200233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_MAXTRIES); 201233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_NEW_AUTHTOK_REQD); 202233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_PERM_DENIED); 203233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_SERVICE_ERR); 204233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_SESSION_ERR); 205233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_SUCCESS); 206233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_SYSTEM_ERR); 207233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_TRY_AGAIN); 208233507Sdumbbell ADD_PAM_RV_TO_ENV(PAM_USER_UNKNOWN); 209233507Sdumbbell } 210233507Sdumbbell 211233507Sdumbbell envlist[envlen] = NULL; 212233507Sdumbbell 213141102Sdes /* 214141102Sdes * Fork and run the command. By using vfork() instead of fork(), 215141102Sdes * we can distinguish between an execve() failure and a non-zero 216233507Sdumbbell * exit status from the command. 217141102Sdes */ 21897182Sdes childerr = 0; 21997182Sdes if ((pid = vfork()) == 0) { 220141102Sdes execve(argv[0], (char * const *)argv, (char * const *)envlist); 22197182Sdes childerr = errno; 22297182Sdes _exit(1); 223110446Sdes } 224141102Sdes openpam_free_envlist(envlist); 225110446Sdes if (pid == -1) { 226233507Sdumbbell openpam_log(PAM_LOG_ERROR, "%s: vfork(): %m", func); 22797182Sdes return (PAM_SYSTEM_ERR); 22897182Sdes } 229233507Sdumbbell while (waitpid(pid, &status, 0) == -1) { 230233507Sdumbbell if (errno == EINTR) 231233507Sdumbbell continue; 232233507Sdumbbell openpam_log(PAM_LOG_ERROR, "%s: waitpid(): %m", func); 23397182Sdes return (PAM_SYSTEM_ERR); 23497182Sdes } 23597182Sdes if (childerr != 0) { 236233507Sdumbbell openpam_log(PAM_LOG_ERROR, "%s: execve(): %m", func); 23797182Sdes return (PAM_SYSTEM_ERR); 23897182Sdes } 23997182Sdes if (WIFSIGNALED(status)) { 240233507Sdumbbell openpam_log(PAM_LOG_ERROR, "%s: %s caught signal %d%s", 241233507Sdumbbell func, argv[0], WTERMSIG(status), 24297182Sdes WCOREDUMP(status) ? " (core dumped)" : ""); 243233507Sdumbbell return (PAM_SERVICE_ERR); 24497182Sdes } 24597182Sdes if (!WIFEXITED(status)) { 246233507Sdumbbell openpam_log(PAM_LOG_ERROR, "%s: unknown status 0x%x", 247233507Sdumbbell func, status); 248233507Sdumbbell return (PAM_SERVICE_ERR); 24997182Sdes } 250233507Sdumbbell 251234184Sdumbbell if (options->return_prog_exit_status) { 252233507Sdumbbell openpam_log(PAM_LOG_DEBUG, 253233507Sdumbbell "%s: Use program exit status as return value: %d", 254233507Sdumbbell func, WEXITSTATUS(status)); 255233507Sdumbbell return (WEXITSTATUS(status)); 256233507Sdumbbell } else { 257233507Sdumbbell return (WEXITSTATUS(status) == 0 ? 258233507Sdumbbell PAM_SUCCESS : PAM_PERM_DENIED); 25997182Sdes } 26097182Sdes} 26197182Sdes 26297182SdesPAM_EXTERN int 26397182Sdespam_sm_authenticate(pam_handle_t *pamh, int flags, 26497182Sdes int argc, const char *argv[]) 26597182Sdes{ 266233507Sdumbbell int ret; 267234184Sdumbbell struct pe_opts options; 26897182Sdes 269234184Sdumbbell ret = parse_options(__func__, &argc, &argv, &options); 270234184Sdumbbell if (ret != 0) 271234184Sdumbbell return (PAM_SERVICE_ERR); 272233507Sdumbbell 273234184Sdumbbell ret = _pam_exec(pamh, __func__, flags, argc, argv, &options); 274234184Sdumbbell 275233507Sdumbbell /* 276233507Sdumbbell * We must check that the program returned a valid code for this 277233507Sdumbbell * function. 278233507Sdumbbell */ 279233507Sdumbbell switch (ret) { 280233507Sdumbbell case PAM_SUCCESS: 281233507Sdumbbell case PAM_ABORT: 282233507Sdumbbell case PAM_AUTHINFO_UNAVAIL: 283233507Sdumbbell case PAM_AUTH_ERR: 284233507Sdumbbell case PAM_BUF_ERR: 285233507Sdumbbell case PAM_CONV_ERR: 286233507Sdumbbell case PAM_CRED_INSUFFICIENT: 287233507Sdumbbell case PAM_IGNORE: 288233507Sdumbbell case PAM_MAXTRIES: 289233507Sdumbbell case PAM_PERM_DENIED: 290233507Sdumbbell case PAM_SERVICE_ERR: 291233507Sdumbbell case PAM_SYSTEM_ERR: 292233507Sdumbbell case PAM_USER_UNKNOWN: 293233507Sdumbbell break; 294233507Sdumbbell default: 295233507Sdumbbell openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d", 296233507Sdumbbell argv[0], ret); 297233507Sdumbbell ret = PAM_SERVICE_ERR; 298233507Sdumbbell } 299233507Sdumbbell 300233507Sdumbbell return (ret); 30197182Sdes} 30297182Sdes 30397182SdesPAM_EXTERN int 30497182Sdespam_sm_setcred(pam_handle_t *pamh, int flags, 30597182Sdes int argc, const char *argv[]) 30697182Sdes{ 307233507Sdumbbell int ret; 308234184Sdumbbell struct pe_opts options; 30997182Sdes 310234184Sdumbbell ret = parse_options(__func__, &argc, &argv, &options); 311234184Sdumbbell if (ret != 0) 312234184Sdumbbell return (PAM_SERVICE_ERR); 313233507Sdumbbell 314234184Sdumbbell ret = _pam_exec(pamh, __func__, flags, argc, argv, &options); 315234184Sdumbbell 316233507Sdumbbell /* 317233507Sdumbbell * We must check that the program returned a valid code for this 318233507Sdumbbell * function. 319233507Sdumbbell */ 320233507Sdumbbell switch (ret) { 321233507Sdumbbell case PAM_SUCCESS: 322233507Sdumbbell case PAM_ABORT: 323233507Sdumbbell case PAM_BUF_ERR: 324233507Sdumbbell case PAM_CONV_ERR: 325233507Sdumbbell case PAM_CRED_ERR: 326233507Sdumbbell case PAM_CRED_EXPIRED: 327233507Sdumbbell case PAM_CRED_UNAVAIL: 328233507Sdumbbell case PAM_IGNORE: 329233507Sdumbbell case PAM_PERM_DENIED: 330233507Sdumbbell case PAM_SERVICE_ERR: 331233507Sdumbbell case PAM_SYSTEM_ERR: 332233507Sdumbbell case PAM_USER_UNKNOWN: 333233507Sdumbbell break; 334233507Sdumbbell default: 335233507Sdumbbell openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d", 336233507Sdumbbell argv[0], ret); 337233507Sdumbbell ret = PAM_SERVICE_ERR; 338233507Sdumbbell } 339233507Sdumbbell 340233507Sdumbbell return (ret); 34197182Sdes} 34297182Sdes 34397182SdesPAM_EXTERN int 34497182Sdespam_sm_acct_mgmt(pam_handle_t *pamh, int flags, 34597182Sdes int argc, const char *argv[]) 34697182Sdes{ 347233507Sdumbbell int ret; 348234184Sdumbbell struct pe_opts options; 34997182Sdes 350234184Sdumbbell ret = parse_options(__func__, &argc, &argv, &options); 351234184Sdumbbell if (ret != 0) 352234184Sdumbbell return (PAM_SERVICE_ERR); 353233507Sdumbbell 354234184Sdumbbell ret = _pam_exec(pamh, __func__, flags, argc, argv, &options); 355234184Sdumbbell 356233507Sdumbbell /* 357233507Sdumbbell * We must check that the program returned a valid code for this 358233507Sdumbbell * function. 359233507Sdumbbell */ 360233507Sdumbbell switch (ret) { 361233507Sdumbbell case PAM_SUCCESS: 362233507Sdumbbell case PAM_ABORT: 363233507Sdumbbell case PAM_ACCT_EXPIRED: 364233507Sdumbbell case PAM_AUTH_ERR: 365233507Sdumbbell case PAM_BUF_ERR: 366233507Sdumbbell case PAM_CONV_ERR: 367233507Sdumbbell case PAM_IGNORE: 368233507Sdumbbell case PAM_NEW_AUTHTOK_REQD: 369233507Sdumbbell case PAM_PERM_DENIED: 370233507Sdumbbell case PAM_SERVICE_ERR: 371233507Sdumbbell case PAM_SYSTEM_ERR: 372233507Sdumbbell case PAM_USER_UNKNOWN: 373233507Sdumbbell break; 374233507Sdumbbell default: 375233507Sdumbbell openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d", 376233507Sdumbbell argv[0], ret); 377233507Sdumbbell ret = PAM_SERVICE_ERR; 378233507Sdumbbell } 379233507Sdumbbell 380233507Sdumbbell return (ret); 38197182Sdes} 38297182Sdes 38397182SdesPAM_EXTERN int 38497182Sdespam_sm_open_session(pam_handle_t *pamh, int flags, 38597182Sdes int argc, const char *argv[]) 38697182Sdes{ 387233507Sdumbbell int ret; 388234184Sdumbbell struct pe_opts options; 38997182Sdes 390234184Sdumbbell ret = parse_options(__func__, &argc, &argv, &options); 391234184Sdumbbell if (ret != 0) 392234184Sdumbbell return (PAM_SERVICE_ERR); 393233507Sdumbbell 394234184Sdumbbell ret = _pam_exec(pamh, __func__, flags, argc, argv, &options); 395234184Sdumbbell 396233507Sdumbbell /* 397233507Sdumbbell * We must check that the program returned a valid code for this 398233507Sdumbbell * function. 399233507Sdumbbell */ 400233507Sdumbbell switch (ret) { 401233507Sdumbbell case PAM_SUCCESS: 402233507Sdumbbell case PAM_ABORT: 403233507Sdumbbell case PAM_BUF_ERR: 404233507Sdumbbell case PAM_CONV_ERR: 405233507Sdumbbell case PAM_IGNORE: 406233507Sdumbbell case PAM_PERM_DENIED: 407233507Sdumbbell case PAM_SERVICE_ERR: 408233507Sdumbbell case PAM_SESSION_ERR: 409233507Sdumbbell case PAM_SYSTEM_ERR: 410233507Sdumbbell break; 411233507Sdumbbell default: 412233507Sdumbbell openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d", 413233507Sdumbbell argv[0], ret); 414233507Sdumbbell ret = PAM_SERVICE_ERR; 415233507Sdumbbell } 416233507Sdumbbell 417233507Sdumbbell return (ret); 41897182Sdes} 41997182Sdes 42097182SdesPAM_EXTERN int 42197182Sdespam_sm_close_session(pam_handle_t *pamh, int flags, 42297182Sdes int argc, const char *argv[]) 42397182Sdes{ 424233507Sdumbbell int ret; 425234184Sdumbbell struct pe_opts options; 42697182Sdes 427234184Sdumbbell ret = parse_options(__func__, &argc, &argv, &options); 428234184Sdumbbell if (ret != 0) 429234184Sdumbbell return (PAM_SERVICE_ERR); 430233507Sdumbbell 431234184Sdumbbell ret = _pam_exec(pamh, __func__, flags, argc, argv, &options); 432234184Sdumbbell 433233507Sdumbbell /* 434233507Sdumbbell * We must check that the program returned a valid code for this 435233507Sdumbbell * function. 436233507Sdumbbell */ 437233507Sdumbbell switch (ret) { 438233507Sdumbbell case PAM_SUCCESS: 439233507Sdumbbell case PAM_ABORT: 440233507Sdumbbell case PAM_BUF_ERR: 441233507Sdumbbell case PAM_CONV_ERR: 442233507Sdumbbell case PAM_IGNORE: 443233507Sdumbbell case PAM_PERM_DENIED: 444233507Sdumbbell case PAM_SERVICE_ERR: 445233507Sdumbbell case PAM_SESSION_ERR: 446233507Sdumbbell case PAM_SYSTEM_ERR: 447233507Sdumbbell break; 448233507Sdumbbell default: 449233507Sdumbbell openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d", 450233507Sdumbbell argv[0], ret); 451233507Sdumbbell ret = PAM_SERVICE_ERR; 452233507Sdumbbell } 453233507Sdumbbell 454233507Sdumbbell return (ret); 45597182Sdes} 45697182Sdes 45797182SdesPAM_EXTERN int 45897182Sdespam_sm_chauthtok(pam_handle_t *pamh, int flags, 45997182Sdes int argc, const char *argv[]) 46097182Sdes{ 461233507Sdumbbell int ret; 462234184Sdumbbell struct pe_opts options; 46397182Sdes 464234184Sdumbbell ret = parse_options(__func__, &argc, &argv, &options); 465234184Sdumbbell if (ret != 0) 466234184Sdumbbell return (PAM_SERVICE_ERR); 467233507Sdumbbell 468234184Sdumbbell ret = _pam_exec(pamh, __func__, flags, argc, argv, &options); 469234184Sdumbbell 470233507Sdumbbell /* 471233507Sdumbbell * We must check that the program returned a valid code for this 472233507Sdumbbell * function. 473233507Sdumbbell */ 474233507Sdumbbell switch (ret) { 475233507Sdumbbell case PAM_SUCCESS: 476233507Sdumbbell case PAM_ABORT: 477233507Sdumbbell case PAM_AUTHTOK_DISABLE_AGING: 478233507Sdumbbell case PAM_AUTHTOK_ERR: 479233507Sdumbbell case PAM_AUTHTOK_LOCK_BUSY: 480233507Sdumbbell case PAM_AUTHTOK_RECOVERY_ERR: 481233507Sdumbbell case PAM_BUF_ERR: 482233507Sdumbbell case PAM_CONV_ERR: 483233507Sdumbbell case PAM_IGNORE: 484233507Sdumbbell case PAM_PERM_DENIED: 485233507Sdumbbell case PAM_SERVICE_ERR: 486233507Sdumbbell case PAM_SYSTEM_ERR: 487233507Sdumbbell case PAM_TRY_AGAIN: 488233507Sdumbbell break; 489233507Sdumbbell default: 490233507Sdumbbell openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d", 491233507Sdumbbell argv[0], ret); 492233507Sdumbbell ret = PAM_SERVICE_ERR; 493233507Sdumbbell } 494233507Sdumbbell 495233507Sdumbbell return (ret); 49697182Sdes} 49797182Sdes 49897182SdesPAM_MODULE_ENTRY("pam_exec"); 499