1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 2001,2003 Networks Associates Technology, Inc. 5 * Copyright (c) 2017 Dag-Erling Smørgrav 6 * Copyright (c) 2018 Thomas Munro 7 * All rights reserved. 8 * 9 * This software was developed for the FreeBSD Project by ThinkSec AS and 10 * NAI Labs, the Security Research Division of Network Associates, Inc. 11 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 12 * DARPA CHATS research program. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. The name of the author may not be used to endorse or promote 23 * products derived from this software without specific prior written 24 * permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __FBSDID("$FreeBSD$"); 41 42 #include <sys/types.h> 43 #include <sys/poll.h> 44 #include <sys/procdesc.h> 45 #include <sys/wait.h> 46 47 #include <errno.h> 48 #include <fcntl.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <unistd.h> 53 54 #include <security/pam_appl.h> 55 #include <security/pam_modules.h> 56 #include <security/openpam.h> 57 58 #define PAM_ITEM_ENV(n) { (n), #n } 59 static struct { 60 int item; 61 const char *name; 62 } pam_item_env[] = { 63 PAM_ITEM_ENV(PAM_SERVICE), 64 PAM_ITEM_ENV(PAM_USER), 65 PAM_ITEM_ENV(PAM_TTY), 66 PAM_ITEM_ENV(PAM_RHOST), 67 PAM_ITEM_ENV(PAM_RUSER), 68 }; 69 #define NUM_PAM_ITEM_ENV (sizeof(pam_item_env) / sizeof(pam_item_env[0])) 70 71 #define PAM_ERR_ENV_X(str, num) str "=" #num 72 #define PAM_ERR_ENV(pam_err) PAM_ERR_ENV_X(#pam_err, pam_err) 73 static const char *pam_err_env[] = { 74 PAM_ERR_ENV(PAM_SUCCESS), 75 PAM_ERR_ENV(PAM_OPEN_ERR), 76 PAM_ERR_ENV(PAM_SYMBOL_ERR), 77 PAM_ERR_ENV(PAM_SERVICE_ERR), 78 PAM_ERR_ENV(PAM_SYSTEM_ERR), 79 PAM_ERR_ENV(PAM_BUF_ERR), 80 PAM_ERR_ENV(PAM_CONV_ERR), 81 PAM_ERR_ENV(PAM_PERM_DENIED), 82 PAM_ERR_ENV(PAM_MAXTRIES), 83 PAM_ERR_ENV(PAM_AUTH_ERR), 84 PAM_ERR_ENV(PAM_NEW_AUTHTOK_REQD), 85 PAM_ERR_ENV(PAM_CRED_INSUFFICIENT), 86 PAM_ERR_ENV(PAM_AUTHINFO_UNAVAIL), 87 PAM_ERR_ENV(PAM_USER_UNKNOWN), 88 PAM_ERR_ENV(PAM_CRED_UNAVAIL), 89 PAM_ERR_ENV(PAM_CRED_EXPIRED), 90 PAM_ERR_ENV(PAM_CRED_ERR), 91 PAM_ERR_ENV(PAM_ACCT_EXPIRED), 92 PAM_ERR_ENV(PAM_AUTHTOK_EXPIRED), 93 PAM_ERR_ENV(PAM_SESSION_ERR), 94 PAM_ERR_ENV(PAM_AUTHTOK_ERR), 95 PAM_ERR_ENV(PAM_AUTHTOK_RECOVERY_ERR), 96 PAM_ERR_ENV(PAM_AUTHTOK_LOCK_BUSY), 97 PAM_ERR_ENV(PAM_AUTHTOK_DISABLE_AGING), 98 PAM_ERR_ENV(PAM_NO_MODULE_DATA), 99 PAM_ERR_ENV(PAM_IGNORE), 100 PAM_ERR_ENV(PAM_ABORT), 101 PAM_ERR_ENV(PAM_TRY_AGAIN), 102 PAM_ERR_ENV(PAM_MODULE_UNKNOWN), 103 PAM_ERR_ENV(PAM_DOMAIN_UNKNOWN), 104 PAM_ERR_ENV(PAM_NUM_ERR), 105 }; 106 #define NUM_PAM_ERR_ENV (sizeof(pam_err_env) / sizeof(pam_err_env[0])) 107 108 struct pe_opts { 109 int return_prog_exit_status; 110 int capture_stdout; 111 int capture_stderr; 112 int expose_authtok; 113 }; 114 115 static int 116 parse_options(const char *func, int *argc, const char **argv[], 117 struct pe_opts *options) 118 { 119 int i; 120 121 /* 122 * Parse options: 123 * return_prog_exit_status: 124 * use the program exit status as the return code of pam_exec 125 * --: 126 * stop options parsing; what follows is the command to execute 127 */ 128 memset(options, 0, sizeof(*options)); 129 130 for (i = 0; i < *argc; ++i) { 131 if (strcmp((*argv)[i], "debug") == 0 || 132 strcmp((*argv)[i], "no_warn") == 0) { 133 /* ignore */ 134 } else if (strcmp((*argv)[i], "capture_stdout") == 0) { 135 options->capture_stdout = 1; 136 } else if (strcmp((*argv)[i], "capture_stderr") == 0) { 137 options->capture_stderr = 1; 138 } else if (strcmp((*argv)[i], "return_prog_exit_status") == 0) { 139 options->return_prog_exit_status = 1; 140 } else if (strcmp((*argv)[i], "expose_authtok") == 0) { 141 options->expose_authtok = 1; 142 } else { 143 if (strcmp((*argv)[i], "--") == 0) { 144 (*argc)--; 145 (*argv)++; 146 } 147 break; 148 } 149 openpam_log(PAM_LOG_DEBUG, "%s: option \"%s\" enabled", 150 func, (*argv)[i]); 151 } 152 153 (*argc) -= i; 154 (*argv) += i; 155 156 return (0); 157 } 158 159 static int 160 _pam_exec(pam_handle_t *pamh, 161 const char *func, int flags __unused, int argc, const char *argv[], 162 struct pe_opts *options) 163 { 164 char buf[PAM_MAX_MSG_SIZE]; 165 struct pollfd pfd[4]; 166 const void *item; 167 char **envlist, *envstr, *resp, **tmp; 168 ssize_t rlen, wlen; 169 int envlen, extralen, i; 170 int pam_err, serrno, status; 171 int chin[2], chout[2], cherr[2], pd; 172 nfds_t nfds, nreadfds; 173 pid_t pid; 174 const char *authtok; 175 size_t authtok_size; 176 int rc; 177 178 pd = -1; 179 pid = 0; 180 chin[0] = chin[1] = chout[0] = chout[1] = cherr[0] = cherr[1] = -1; 181 envlist = NULL; 182 183 #define OUT(ret) do { pam_err = (ret); goto out; } while (0) 184 185 /* Check there's a program name left after parsing options. */ 186 if (argc < 1) { 187 openpam_log(PAM_LOG_ERROR, "%s: No program specified: aborting", 188 func); 189 OUT(PAM_SERVICE_ERR); 190 } 191 192 /* 193 * Set up the child's environment list. It consists of the PAM 194 * environment, a few hand-picked PAM items, the name of the 195 * service function, and if return_prog_exit_status is set, the 196 * numerical values of all PAM error codes. 197 */ 198 199 /* compute the final size of the environment. */ 200 envlist = pam_getenvlist(pamh); 201 for (envlen = 0; envlist[envlen] != NULL; ++envlen) 202 /* nothing */ ; 203 extralen = NUM_PAM_ITEM_ENV + 1; 204 if (options->return_prog_exit_status) 205 extralen += NUM_PAM_ERR_ENV; 206 tmp = reallocarray(envlist, envlen + extralen + 1, sizeof(*envlist)); 207 openpam_log(PAM_LOG_DEBUG, "envlen = %d extralen = %d tmp = %p", 208 envlen, extralen, tmp); 209 if (tmp == NULL) 210 OUT(PAM_BUF_ERR); 211 envlist = tmp; 212 extralen += envlen; 213 214 /* copy selected PAM items to the environment */ 215 for (i = 0; i < NUM_PAM_ITEM_ENV; ++i) { 216 pam_err = pam_get_item(pamh, pam_item_env[i].item, &item); 217 if (pam_err != PAM_SUCCESS || item == NULL) 218 continue; 219 if (asprintf(&envstr, "%s=%s", pam_item_env[i].name, item) < 0) 220 OUT(PAM_BUF_ERR); 221 envlist[envlen++] = envstr; 222 envlist[envlen] = NULL; 223 openpam_log(PAM_LOG_DEBUG, "setenv %s", envstr); 224 } 225 226 /* add the name of the service function to the environment */ 227 if (asprintf(&envstr, "PAM_SM_FUNC=%s", func) < 0) 228 OUT(PAM_BUF_ERR); 229 envlist[envlen++] = envstr; 230 envlist[envlen] = NULL; 231 232 /* add the PAM error codes to the environment. */ 233 if (options->return_prog_exit_status) { 234 for (i = 0; i < (int)NUM_PAM_ERR_ENV; ++i) { 235 if ((envstr = strdup(pam_err_env[i])) == NULL) 236 OUT(PAM_BUF_ERR); 237 envlist[envlen++] = envstr; 238 envlist[envlen] = NULL; 239 } 240 } 241 242 openpam_log(PAM_LOG_DEBUG, "envlen = %d extralen = %d envlist = %p", 243 envlen, extralen, envlist); 244 245 /* set up pipe and get authtok if requested */ 246 if (options->expose_authtok) { 247 if (pipe(chin) != 0) { 248 openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func); 249 OUT(PAM_SYSTEM_ERR); 250 } 251 if (fcntl(chin[1], F_SETFL, O_NONBLOCK)) { 252 openpam_log(PAM_LOG_ERROR, "%s: fcntl(): %m", func); 253 OUT(PAM_SYSTEM_ERR); 254 } 255 rc = pam_get_authtok(pamh, PAM_AUTHTOK, &authtok, NULL); 256 if (rc == PAM_SUCCESS) { 257 /* We include the trailing NUL-terminator. */ 258 authtok_size = strlen(authtok) + 1; 259 } else { 260 openpam_log(PAM_LOG_ERROR, "%s: pam_get_authtok(): %s", func, 261 pam_strerror(pamh, rc)); 262 OUT(PAM_SYSTEM_ERR); 263 } 264 } 265 /* set up pipes if capture was requested */ 266 if (options->capture_stdout) { 267 if (pipe(chout) != 0) { 268 openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func); 269 OUT(PAM_SYSTEM_ERR); 270 } 271 if (fcntl(chout[0], F_SETFL, O_NONBLOCK) != 0) { 272 openpam_log(PAM_LOG_ERROR, "%s: fcntl(): %m", func); 273 OUT(PAM_SYSTEM_ERR); 274 } 275 } else { 276 if ((chout[1] = open("/dev/null", O_RDWR)) < 0) { 277 openpam_log(PAM_LOG_ERROR, "%s: /dev/null: %m", func); 278 OUT(PAM_SYSTEM_ERR); 279 } 280 } 281 if (options->capture_stderr) { 282 if (pipe(cherr) != 0) { 283 openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func); 284 OUT(PAM_SYSTEM_ERR); 285 } 286 if (fcntl(cherr[0], F_SETFL, O_NONBLOCK) != 0) { 287 openpam_log(PAM_LOG_ERROR, "%s: fcntl(): %m", func); 288 OUT(PAM_SYSTEM_ERR); 289 } 290 } else { 291 if ((cherr[1] = open("/dev/null", O_RDWR)) < 0) { 292 openpam_log(PAM_LOG_ERROR, "%s: /dev/null: %m", func); 293 OUT(PAM_SYSTEM_ERR); 294 } 295 } 296 297 if ((pid = pdfork(&pd, 0)) == 0) { 298 /* child */ 299 if ((chin[1] >= 0 && close(chin[1]) != 0) || 300 (chout[0] >= 0 && close(chout[0]) != 0) || 301 (cherr[0] >= 0 && close(cherr[0]) != 0)) { 302 openpam_log(PAM_LOG_ERROR, "%s: close(): %m", func); 303 } else if (chin[0] >= 0 && 304 dup2(chin[0], STDIN_FILENO) != STDIN_FILENO) { 305 openpam_log(PAM_LOG_ERROR, "%s: dup2(): %m", func); 306 } else if (dup2(chout[1], STDOUT_FILENO) != STDOUT_FILENO || 307 dup2(cherr[1], STDERR_FILENO) != STDERR_FILENO) { 308 openpam_log(PAM_LOG_ERROR, "%s: dup2(): %m", func); 309 } else { 310 execve(argv[0], (char * const *)argv, 311 (char * const *)envlist); 312 openpam_log(PAM_LOG_ERROR, "%s: execve(%s): %m", 313 func, argv[0]); 314 } 315 _exit(1); 316 } 317 /* parent */ 318 if (pid == -1) { 319 openpam_log(PAM_LOG_ERROR, "%s: pdfork(): %m", func); 320 OUT(PAM_SYSTEM_ERR); 321 } 322 /* use poll() to watch the process and stdin / stdout / stderr */ 323 if (chin[0] >= 0) 324 close(chin[0]); 325 if (chout[1] >= 0) 326 close(chout[1]); 327 if (cherr[1] >= 0) 328 close(cherr[1]); 329 memset(pfd, 0, sizeof pfd); 330 pfd[0].fd = pd; 331 pfd[0].events = POLLHUP; 332 nfds = 1; 333 nreadfds = 0; 334 if (options->capture_stdout) { 335 pfd[nfds].fd = chout[0]; 336 pfd[nfds].events = POLLIN|POLLERR|POLLHUP; 337 nfds++; 338 nreadfds++; 339 } 340 if (options->capture_stderr) { 341 pfd[nfds].fd = cherr[0]; 342 pfd[nfds].events = POLLIN|POLLERR|POLLHUP; 343 nfds++; 344 nreadfds++; 345 } 346 if (options->expose_authtok) { 347 pfd[nfds].fd = chin[1]; 348 pfd[nfds].events = POLLOUT|POLLERR|POLLHUP; 349 nfds++; 350 } 351 352 /* loop until the process exits */ 353 do { 354 if (poll(pfd, nfds, INFTIM) < 0) { 355 openpam_log(PAM_LOG_ERROR, "%s: poll(): %m", func); 356 OUT(PAM_SYSTEM_ERR); 357 } 358 /* are the stderr / stdout pipes ready for reading? */ 359 for (i = 1; i < 1 + nreadfds; ++i) { 360 if ((pfd[i].revents & POLLIN) == 0) 361 continue; 362 if ((rlen = read(pfd[i].fd, buf, sizeof(buf) - 1)) < 0) { 363 openpam_log(PAM_LOG_ERROR, "%s: read(): %m", 364 func); 365 OUT(PAM_SYSTEM_ERR); 366 } else if (rlen == 0) { 367 continue; 368 } 369 buf[rlen] = '\0'; 370 (void)pam_prompt(pamh, pfd[i].fd == chout[0] ? 371 PAM_TEXT_INFO : PAM_ERROR_MSG, &resp, "%s", buf); 372 } 373 /* is the stdin pipe ready for writing? */ 374 if (options->expose_authtok && authtok_size > 0 && 375 (pfd[nfds - 1].revents & POLLOUT) != 0) { 376 if ((wlen = write(chin[1], authtok, authtok_size)) < 0) { 377 if (errno == EAGAIN) 378 continue; 379 openpam_log(PAM_LOG_ERROR, "%s: write(): %m", 380 func); 381 OUT(PAM_SYSTEM_ERR); 382 } else { 383 authtok += wlen; 384 authtok_size -= wlen; 385 if (authtok_size == 0) { 386 /* finished writing; close and forget the pipe */ 387 close(chin[1]); 388 chin[1] = -1; 389 nfds--; 390 } 391 } 392 } 393 } while (pfd[0].revents == 0); 394 395 /* the child process has exited */ 396 while (waitpid(pid, &status, 0) == -1) { 397 if (errno == EINTR) 398 continue; 399 openpam_log(PAM_LOG_ERROR, "%s: waitpid(): %m", func); 400 OUT(PAM_SYSTEM_ERR); 401 } 402 403 /* check exit code */ 404 if (WIFSIGNALED(status)) { 405 openpam_log(PAM_LOG_ERROR, "%s: %s caught signal %d%s", 406 func, argv[0], WTERMSIG(status), 407 WCOREDUMP(status) ? " (core dumped)" : ""); 408 OUT(PAM_SERVICE_ERR); 409 } 410 if (!WIFEXITED(status)) { 411 openpam_log(PAM_LOG_ERROR, "%s: unknown status 0x%x", 412 func, status); 413 OUT(PAM_SERVICE_ERR); 414 } 415 416 if (options->return_prog_exit_status) { 417 openpam_log(PAM_LOG_DEBUG, 418 "%s: Use program exit status as return value: %d", 419 func, WEXITSTATUS(status)); 420 OUT(WEXITSTATUS(status)); 421 } else { 422 OUT(WEXITSTATUS(status) == 0 ? PAM_SUCCESS : PAM_PERM_DENIED); 423 } 424 /* unreachable */ 425 out: 426 serrno = errno; 427 if (pd >= 0) 428 close(pd); 429 if (chin[0] >= 0) 430 close(chin[0]); 431 if (chin[1] >= 0) 432 close(chin[1]); 433 if (chout[0] >= 0) 434 close(chout[0]); 435 if (chout[1] >= 0) 436 close(chout[1]); 437 if (cherr[0] >= 0) 438 close(cherr[0]); 439 if (cherr[0] >= 0) 440 close(cherr[1]); 441 if (envlist != NULL) 442 openpam_free_envlist(envlist); 443 errno = serrno; 444 return (pam_err); 445 } 446 447 PAM_EXTERN int 448 pam_sm_authenticate(pam_handle_t *pamh, int flags, 449 int argc, const char *argv[]) 450 { 451 int ret; 452 struct pe_opts options; 453 454 ret = parse_options(__func__, &argc, &argv, &options); 455 if (ret != 0) 456 return (PAM_SERVICE_ERR); 457 458 ret = _pam_exec(pamh, __func__, flags, argc, argv, &options); 459 460 /* 461 * We must check that the program returned a valid code for this 462 * function. 463 */ 464 switch (ret) { 465 case PAM_SUCCESS: 466 case PAM_ABORT: 467 case PAM_AUTHINFO_UNAVAIL: 468 case PAM_AUTH_ERR: 469 case PAM_BUF_ERR: 470 case PAM_CONV_ERR: 471 case PAM_CRED_INSUFFICIENT: 472 case PAM_IGNORE: 473 case PAM_MAXTRIES: 474 case PAM_PERM_DENIED: 475 case PAM_SERVICE_ERR: 476 case PAM_SYSTEM_ERR: 477 case PAM_USER_UNKNOWN: 478 break; 479 default: 480 openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d", 481 argv[0], ret); 482 ret = PAM_SERVICE_ERR; 483 } 484 485 return (ret); 486 } 487 488 PAM_EXTERN int 489 pam_sm_setcred(pam_handle_t *pamh, int flags, 490 int argc, const char *argv[]) 491 { 492 int ret; 493 struct pe_opts options; 494 495 ret = parse_options(__func__, &argc, &argv, &options); 496 if (ret != 0) 497 return (PAM_SERVICE_ERR); 498 499 ret = _pam_exec(pamh, __func__, flags, argc, argv, &options); 500 501 /* 502 * We must check that the program returned a valid code for this 503 * function. 504 */ 505 switch (ret) { 506 case PAM_SUCCESS: 507 case PAM_ABORT: 508 case PAM_BUF_ERR: 509 case PAM_CONV_ERR: 510 case PAM_CRED_ERR: 511 case PAM_CRED_EXPIRED: 512 case PAM_CRED_UNAVAIL: 513 case PAM_IGNORE: 514 case PAM_PERM_DENIED: 515 case PAM_SERVICE_ERR: 516 case PAM_SYSTEM_ERR: 517 case PAM_USER_UNKNOWN: 518 break; 519 default: 520 openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d", 521 argv[0], ret); 522 ret = PAM_SERVICE_ERR; 523 } 524 525 return (ret); 526 } 527 528 PAM_EXTERN int 529 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, 530 int argc, const char *argv[]) 531 { 532 int ret; 533 struct pe_opts options; 534 535 ret = parse_options(__func__, &argc, &argv, &options); 536 if (ret != 0) 537 return (PAM_SERVICE_ERR); 538 539 ret = _pam_exec(pamh, __func__, flags, argc, argv, &options); 540 541 /* 542 * We must check that the program returned a valid code for this 543 * function. 544 */ 545 switch (ret) { 546 case PAM_SUCCESS: 547 case PAM_ABORT: 548 case PAM_ACCT_EXPIRED: 549 case PAM_AUTH_ERR: 550 case PAM_BUF_ERR: 551 case PAM_CONV_ERR: 552 case PAM_IGNORE: 553 case PAM_NEW_AUTHTOK_REQD: 554 case PAM_PERM_DENIED: 555 case PAM_SERVICE_ERR: 556 case PAM_SYSTEM_ERR: 557 case PAM_USER_UNKNOWN: 558 break; 559 default: 560 openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d", 561 argv[0], ret); 562 ret = PAM_SERVICE_ERR; 563 } 564 565 return (ret); 566 } 567 568 PAM_EXTERN int 569 pam_sm_open_session(pam_handle_t *pamh, int flags, 570 int argc, const char *argv[]) 571 { 572 int ret; 573 struct pe_opts options; 574 575 ret = parse_options(__func__, &argc, &argv, &options); 576 if (ret != 0) 577 return (PAM_SERVICE_ERR); 578 579 ret = _pam_exec(pamh, __func__, flags, argc, argv, &options); 580 581 /* 582 * We must check that the program returned a valid code for this 583 * function. 584 */ 585 switch (ret) { 586 case PAM_SUCCESS: 587 case PAM_ABORT: 588 case PAM_BUF_ERR: 589 case PAM_CONV_ERR: 590 case PAM_IGNORE: 591 case PAM_PERM_DENIED: 592 case PAM_SERVICE_ERR: 593 case PAM_SESSION_ERR: 594 case PAM_SYSTEM_ERR: 595 break; 596 default: 597 openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d", 598 argv[0], ret); 599 ret = PAM_SERVICE_ERR; 600 } 601 602 return (ret); 603 } 604 605 PAM_EXTERN int 606 pam_sm_close_session(pam_handle_t *pamh, int flags, 607 int argc, const char *argv[]) 608 { 609 int ret; 610 struct pe_opts options; 611 612 ret = parse_options(__func__, &argc, &argv, &options); 613 if (ret != 0) 614 return (PAM_SERVICE_ERR); 615 616 ret = _pam_exec(pamh, __func__, flags, argc, argv, &options); 617 618 /* 619 * We must check that the program returned a valid code for this 620 * function. 621 */ 622 switch (ret) { 623 case PAM_SUCCESS: 624 case PAM_ABORT: 625 case PAM_BUF_ERR: 626 case PAM_CONV_ERR: 627 case PAM_IGNORE: 628 case PAM_PERM_DENIED: 629 case PAM_SERVICE_ERR: 630 case PAM_SESSION_ERR: 631 case PAM_SYSTEM_ERR: 632 break; 633 default: 634 openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d", 635 argv[0], ret); 636 ret = PAM_SERVICE_ERR; 637 } 638 639 return (ret); 640 } 641 642 PAM_EXTERN int 643 pam_sm_chauthtok(pam_handle_t *pamh, int flags, 644 int argc, const char *argv[]) 645 { 646 int ret; 647 struct pe_opts options; 648 649 ret = parse_options(__func__, &argc, &argv, &options); 650 if (ret != 0) 651 return (PAM_SERVICE_ERR); 652 653 ret = _pam_exec(pamh, __func__, flags, argc, argv, &options); 654 655 /* 656 * We must check that the program returned a valid code for this 657 * function. 658 */ 659 switch (ret) { 660 case PAM_SUCCESS: 661 case PAM_ABORT: 662 case PAM_AUTHTOK_DISABLE_AGING: 663 case PAM_AUTHTOK_ERR: 664 case PAM_AUTHTOK_LOCK_BUSY: 665 case PAM_AUTHTOK_RECOVERY_ERR: 666 case PAM_BUF_ERR: 667 case PAM_CONV_ERR: 668 case PAM_IGNORE: 669 case PAM_PERM_DENIED: 670 case PAM_SERVICE_ERR: 671 case PAM_SYSTEM_ERR: 672 case PAM_TRY_AGAIN: 673 break; 674 default: 675 openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d", 676 argv[0], ret); 677 ret = PAM_SERVICE_ERR; 678 } 679 680 return (ret); 681 } 682 683 PAM_MODULE_ENTRY("pam_exec"); 684