1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 2001,2003 Networks Associates Technology, Inc.
5 * Copyright (c) 2017-2019 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/types.h>
40 #include <sys/poll.h>
41 #include <sys/procdesc.h>
42 #include <sys/wait.h>
43
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50
51 #include <security/pam_appl.h>
52 #include <security/pam_modules.h>
53 #include <security/openpam.h>
54
55 #define PAM_ITEM_ENV(n) { (n), #n }
56 static struct {
57 int item;
58 const char *name;
59 } pam_item_env[] = {
60 PAM_ITEM_ENV(PAM_SERVICE),
61 PAM_ITEM_ENV(PAM_USER),
62 PAM_ITEM_ENV(PAM_TTY),
63 PAM_ITEM_ENV(PAM_RHOST),
64 PAM_ITEM_ENV(PAM_RUSER),
65 };
66 #define NUM_PAM_ITEM_ENV (sizeof(pam_item_env) / sizeof(pam_item_env[0]))
67
68 #define PAM_ERR_ENV_X(str, num) str "=" #num
69 #define PAM_ERR_ENV(pam_err) PAM_ERR_ENV_X(#pam_err, pam_err)
70 static const char *pam_err_env[] = {
71 PAM_ERR_ENV(PAM_SUCCESS),
72 PAM_ERR_ENV(PAM_OPEN_ERR),
73 PAM_ERR_ENV(PAM_SYMBOL_ERR),
74 PAM_ERR_ENV(PAM_SERVICE_ERR),
75 PAM_ERR_ENV(PAM_SYSTEM_ERR),
76 PAM_ERR_ENV(PAM_BUF_ERR),
77 PAM_ERR_ENV(PAM_CONV_ERR),
78 PAM_ERR_ENV(PAM_PERM_DENIED),
79 PAM_ERR_ENV(PAM_MAXTRIES),
80 PAM_ERR_ENV(PAM_AUTH_ERR),
81 PAM_ERR_ENV(PAM_NEW_AUTHTOK_REQD),
82 PAM_ERR_ENV(PAM_CRED_INSUFFICIENT),
83 PAM_ERR_ENV(PAM_AUTHINFO_UNAVAIL),
84 PAM_ERR_ENV(PAM_USER_UNKNOWN),
85 PAM_ERR_ENV(PAM_CRED_UNAVAIL),
86 PAM_ERR_ENV(PAM_CRED_EXPIRED),
87 PAM_ERR_ENV(PAM_CRED_ERR),
88 PAM_ERR_ENV(PAM_ACCT_EXPIRED),
89 PAM_ERR_ENV(PAM_AUTHTOK_EXPIRED),
90 PAM_ERR_ENV(PAM_SESSION_ERR),
91 PAM_ERR_ENV(PAM_AUTHTOK_ERR),
92 PAM_ERR_ENV(PAM_AUTHTOK_RECOVERY_ERR),
93 PAM_ERR_ENV(PAM_AUTHTOK_LOCK_BUSY),
94 PAM_ERR_ENV(PAM_AUTHTOK_DISABLE_AGING),
95 PAM_ERR_ENV(PAM_NO_MODULE_DATA),
96 PAM_ERR_ENV(PAM_IGNORE),
97 PAM_ERR_ENV(PAM_ABORT),
98 PAM_ERR_ENV(PAM_TRY_AGAIN),
99 PAM_ERR_ENV(PAM_MODULE_UNKNOWN),
100 PAM_ERR_ENV(PAM_DOMAIN_UNKNOWN),
101 PAM_ERR_ENV(PAM_NUM_ERR),
102 };
103 #define NUM_PAM_ERR_ENV (sizeof(pam_err_env) / sizeof(pam_err_env[0]))
104
105 struct pe_opts {
106 int return_prog_exit_status;
107 int capture_stdout;
108 int capture_stderr;
109 int expose_authtok;
110 int use_first_pass;
111 };
112
113 static int
parse_options(const char * func,int * argc,const char ** argv[],struct pe_opts * options)114 parse_options(const char *func, int *argc, const char **argv[],
115 struct pe_opts *options)
116 {
117 int i;
118
119 /*
120 * Parse options:
121 * return_prog_exit_status:
122 * use the program exit status as the return code of pam_exec
123 * --:
124 * stop options parsing; what follows is the command to execute
125 */
126 memset(options, 0, sizeof(*options));
127
128 for (i = 0; i < *argc; ++i) {
129 if (strcmp((*argv)[i], "debug") == 0 ||
130 strcmp((*argv)[i], "no_warn") == 0) {
131 /* ignore */
132 } else if (strcmp((*argv)[i], "capture_stdout") == 0) {
133 options->capture_stdout = 1;
134 } else if (strcmp((*argv)[i], "capture_stderr") == 0) {
135 options->capture_stderr = 1;
136 } else if (strcmp((*argv)[i], "return_prog_exit_status") == 0) {
137 options->return_prog_exit_status = 1;
138 } else if (strcmp((*argv)[i], "expose_authtok") == 0) {
139 options->expose_authtok = 1;
140 } else if (strcmp((*argv)[i], "use_first_pass") == 0) {
141 options->use_first_pass = 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
_pam_exec(pam_handle_t * pamh,const char * func,int flags __unused,int argc,const char * argv[],struct pe_opts * options)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,
220 (const char *)item) < 0)
221 OUT(PAM_BUF_ERR);
222 envlist[envlen++] = envstr;
223 envlist[envlen] = NULL;
224 openpam_log(PAM_LOG_DEBUG, "setenv %s", envstr);
225 }
226
227 /* add the name of the service function to the environment */
228 if (asprintf(&envstr, "PAM_SM_FUNC=%s", func) < 0)
229 OUT(PAM_BUF_ERR);
230 envlist[envlen++] = envstr;
231 envlist[envlen] = NULL;
232
233 /* add the PAM error codes to the environment. */
234 if (options->return_prog_exit_status) {
235 for (i = 0; i < (int)NUM_PAM_ERR_ENV; ++i) {
236 if ((envstr = strdup(pam_err_env[i])) == NULL)
237 OUT(PAM_BUF_ERR);
238 envlist[envlen++] = envstr;
239 envlist[envlen] = NULL;
240 }
241 }
242
243 openpam_log(PAM_LOG_DEBUG, "envlen = %d extralen = %d envlist = %p",
244 envlen, extralen, envlist);
245
246 /* set up pipe and get authtok if requested */
247 if (options->expose_authtok) {
248 if (pipe(chin) != 0) {
249 openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func);
250 OUT(PAM_SYSTEM_ERR);
251 }
252 if (fcntl(chin[1], F_SETFL, O_NONBLOCK)) {
253 openpam_log(PAM_LOG_ERROR, "%s: fcntl(): %m", func);
254 OUT(PAM_SYSTEM_ERR);
255 }
256 if (options->use_first_pass ||
257 strcmp(func, "pam_sm_setcred") == 0) {
258 /* don't prompt, only expose existing token */
259 rc = pam_get_item(pamh, PAM_AUTHTOK, &item);
260 authtok = item;
261 if (authtok == NULL && rc == PAM_SUCCESS) {
262 openpam_log(PAM_LOG_ERROR,
263 "%s: pam_get_authtok(): %s",
264 func, "authentication token not available");
265 OUT(PAM_SYSTEM_ERR);
266 }
267
268 } else {
269 rc = pam_get_authtok(pamh, PAM_AUTHTOK, &authtok, NULL);
270 }
271 if (rc == PAM_SUCCESS) {
272 /* We include the trailing null terminator. */
273 authtok_size = strlen(authtok) + 1;
274 } else {
275 openpam_log(PAM_LOG_ERROR, "%s: pam_get_authtok(): %s",
276 func, pam_strerror(pamh, rc));
277 OUT(PAM_SYSTEM_ERR);
278 }
279 }
280 /* set up pipes if capture was requested */
281 if (options->capture_stdout) {
282 if (pipe(chout) != 0) {
283 openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func);
284 OUT(PAM_SYSTEM_ERR);
285 }
286 if (fcntl(chout[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 ((chout[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 if (options->capture_stderr) {
297 if (pipe(cherr) != 0) {
298 openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func);
299 OUT(PAM_SYSTEM_ERR);
300 }
301 if (fcntl(cherr[0], F_SETFL, O_NONBLOCK) != 0) {
302 openpam_log(PAM_LOG_ERROR, "%s: fcntl(): %m", func);
303 OUT(PAM_SYSTEM_ERR);
304 }
305 } else {
306 if ((cherr[1] = open("/dev/null", O_RDWR)) < 0) {
307 openpam_log(PAM_LOG_ERROR, "%s: /dev/null: %m", func);
308 OUT(PAM_SYSTEM_ERR);
309 }
310 }
311
312 if ((pid = pdfork(&pd, 0)) == 0) {
313 /* child */
314 if ((chin[1] >= 0 && close(chin[1]) != 0) ||
315 (chout[0] >= 0 && close(chout[0]) != 0) ||
316 (cherr[0] >= 0 && close(cherr[0]) != 0)) {
317 openpam_log(PAM_LOG_ERROR, "%s: close(): %m", func);
318 } else if (chin[0] >= 0 &&
319 dup2(chin[0], STDIN_FILENO) != STDIN_FILENO) {
320 openpam_log(PAM_LOG_ERROR, "%s: dup2(): %m", func);
321 } else if (dup2(chout[1], STDOUT_FILENO) != STDOUT_FILENO ||
322 dup2(cherr[1], STDERR_FILENO) != STDERR_FILENO) {
323 openpam_log(PAM_LOG_ERROR, "%s: dup2(): %m", func);
324 } else {
325 execve(argv[0], (char * const *)argv,
326 (char * const *)envlist);
327 openpam_log(PAM_LOG_ERROR, "%s: execve(%s): %m",
328 func, argv[0]);
329 }
330 _exit(1);
331 }
332 /* parent */
333 if (pid == -1) {
334 openpam_log(PAM_LOG_ERROR, "%s: pdfork(): %m", func);
335 OUT(PAM_SYSTEM_ERR);
336 }
337 /* use poll() to watch the process and stdin / stdout / stderr */
338 if (chin[0] >= 0)
339 close(chin[0]);
340 if (chout[1] >= 0)
341 close(chout[1]);
342 if (cherr[1] >= 0)
343 close(cherr[1]);
344 memset(pfd, 0, sizeof pfd);
345 pfd[0].fd = pd;
346 pfd[0].events = POLLHUP;
347 nfds = 1;
348 nreadfds = 0;
349 if (options->capture_stdout) {
350 pfd[nfds].fd = chout[0];
351 pfd[nfds].events = POLLIN|POLLERR|POLLHUP;
352 nfds++;
353 nreadfds++;
354 }
355 if (options->capture_stderr) {
356 pfd[nfds].fd = cherr[0];
357 pfd[nfds].events = POLLIN|POLLERR|POLLHUP;
358 nfds++;
359 nreadfds++;
360 }
361 if (options->expose_authtok) {
362 pfd[nfds].fd = chin[1];
363 pfd[nfds].events = POLLOUT|POLLERR|POLLHUP;
364 nfds++;
365 }
366
367 /* loop until the process exits */
368 do {
369 if (poll(pfd, nfds, INFTIM) < 0) {
370 openpam_log(PAM_LOG_ERROR, "%s: poll(): %m", func);
371 OUT(PAM_SYSTEM_ERR);
372 }
373 /* are the stderr / stdout pipes ready for reading? */
374 for (i = 1; i < 1 + nreadfds; ++i) {
375 if ((pfd[i].revents & POLLIN) == 0)
376 continue;
377 if ((rlen = read(pfd[i].fd, buf, sizeof(buf) - 1)) < 0) {
378 openpam_log(PAM_LOG_ERROR, "%s: read(): %m",
379 func);
380 OUT(PAM_SYSTEM_ERR);
381 } else if (rlen == 0) {
382 continue;
383 }
384 buf[rlen] = '\0';
385 (void)pam_prompt(pamh, pfd[i].fd == chout[0] ?
386 PAM_TEXT_INFO : PAM_ERROR_MSG, &resp, "%s", buf);
387 }
388 /* is the stdin pipe ready for writing? */
389 if (options->expose_authtok && authtok_size > 0 &&
390 (pfd[nfds - 1].revents & POLLOUT) != 0) {
391 if ((wlen = write(chin[1], authtok, authtok_size)) < 0) {
392 if (errno == EAGAIN)
393 continue;
394 openpam_log(PAM_LOG_ERROR, "%s: write(): %m",
395 func);
396 OUT(PAM_SYSTEM_ERR);
397 } else {
398 authtok += wlen;
399 authtok_size -= wlen;
400 if (authtok_size == 0) {
401 /* finished writing; close and forget the pipe */
402 close(chin[1]);
403 chin[1] = -1;
404 nfds--;
405 }
406 }
407 }
408 } while (pfd[0].revents == 0);
409
410 /* the child process has exited */
411 while (waitpid(pid, &status, 0) == -1) {
412 if (errno == EINTR)
413 continue;
414 openpam_log(PAM_LOG_ERROR, "%s: waitpid(): %m", func);
415 OUT(PAM_SYSTEM_ERR);
416 }
417
418 /* check exit code */
419 if (WIFSIGNALED(status)) {
420 openpam_log(PAM_LOG_ERROR, "%s: %s caught signal %d%s",
421 func, argv[0], WTERMSIG(status),
422 WCOREDUMP(status) ? " (core dumped)" : "");
423 OUT(PAM_SERVICE_ERR);
424 }
425 if (!WIFEXITED(status)) {
426 openpam_log(PAM_LOG_ERROR, "%s: unknown status 0x%x",
427 func, status);
428 OUT(PAM_SERVICE_ERR);
429 }
430
431 if (options->return_prog_exit_status) {
432 openpam_log(PAM_LOG_DEBUG,
433 "%s: Use program exit status as return value: %d",
434 func, WEXITSTATUS(status));
435 OUT(WEXITSTATUS(status));
436 } else {
437 OUT(WEXITSTATUS(status) == 0 ? PAM_SUCCESS : PAM_PERM_DENIED);
438 }
439 /* unreachable */
440 out:
441 serrno = errno;
442 if (pd >= 0)
443 close(pd);
444 if (chin[0] >= 0)
445 close(chin[0]);
446 if (chin[1] >= 0)
447 close(chin[1]);
448 if (chout[0] >= 0)
449 close(chout[0]);
450 if (chout[1] >= 0)
451 close(chout[1]);
452 if (cherr[0] >= 0)
453 close(cherr[0]);
454 if (cherr[0] >= 0)
455 close(cherr[1]);
456 if (envlist != NULL)
457 openpam_free_envlist(envlist);
458 errno = serrno;
459 return (pam_err);
460 }
461
462 PAM_EXTERN int
pam_sm_authenticate(pam_handle_t * pamh,int flags,int argc,const char * argv[])463 pam_sm_authenticate(pam_handle_t *pamh, int flags,
464 int argc, const char *argv[])
465 {
466 int ret;
467 struct pe_opts options;
468
469 ret = parse_options(__func__, &argc, &argv, &options);
470 if (ret != 0)
471 return (PAM_SERVICE_ERR);
472
473 ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
474
475 /*
476 * We must check that the program returned a valid code for this
477 * function.
478 */
479 switch (ret) {
480 case PAM_SUCCESS:
481 case PAM_ABORT:
482 case PAM_AUTHINFO_UNAVAIL:
483 case PAM_AUTH_ERR:
484 case PAM_BUF_ERR:
485 case PAM_CONV_ERR:
486 case PAM_CRED_INSUFFICIENT:
487 case PAM_IGNORE:
488 case PAM_MAXTRIES:
489 case PAM_PERM_DENIED:
490 case PAM_SERVICE_ERR:
491 case PAM_SYSTEM_ERR:
492 case PAM_USER_UNKNOWN:
493 break;
494 default:
495 openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
496 argv[0], ret);
497 ret = PAM_SERVICE_ERR;
498 }
499
500 return (ret);
501 }
502
503 PAM_EXTERN int
pam_sm_setcred(pam_handle_t * pamh,int flags,int argc,const char * argv[])504 pam_sm_setcred(pam_handle_t *pamh, int flags,
505 int argc, const char *argv[])
506 {
507 int ret;
508 struct pe_opts options;
509
510 ret = parse_options(__func__, &argc, &argv, &options);
511 if (ret != 0)
512 return (PAM_SERVICE_ERR);
513
514 ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
515
516 /*
517 * We must check that the program returned a valid code for this
518 * function.
519 */
520 switch (ret) {
521 case PAM_SUCCESS:
522 case PAM_ABORT:
523 case PAM_BUF_ERR:
524 case PAM_CONV_ERR:
525 case PAM_CRED_ERR:
526 case PAM_CRED_EXPIRED:
527 case PAM_CRED_UNAVAIL:
528 case PAM_IGNORE:
529 case PAM_PERM_DENIED:
530 case PAM_SERVICE_ERR:
531 case PAM_SYSTEM_ERR:
532 case PAM_USER_UNKNOWN:
533 break;
534 default:
535 openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
536 argv[0], ret);
537 ret = PAM_SERVICE_ERR;
538 }
539
540 return (ret);
541 }
542
543 PAM_EXTERN int
pam_sm_acct_mgmt(pam_handle_t * pamh,int flags,int argc,const char * argv[])544 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
545 int argc, const char *argv[])
546 {
547 int ret;
548 struct pe_opts options;
549
550 ret = parse_options(__func__, &argc, &argv, &options);
551 if (ret != 0)
552 return (PAM_SERVICE_ERR);
553
554 ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
555
556 /*
557 * We must check that the program returned a valid code for this
558 * function.
559 */
560 switch (ret) {
561 case PAM_SUCCESS:
562 case PAM_ABORT:
563 case PAM_ACCT_EXPIRED:
564 case PAM_AUTH_ERR:
565 case PAM_BUF_ERR:
566 case PAM_CONV_ERR:
567 case PAM_IGNORE:
568 case PAM_NEW_AUTHTOK_REQD:
569 case PAM_PERM_DENIED:
570 case PAM_SERVICE_ERR:
571 case PAM_SYSTEM_ERR:
572 case PAM_USER_UNKNOWN:
573 break;
574 default:
575 openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
576 argv[0], ret);
577 ret = PAM_SERVICE_ERR;
578 }
579
580 return (ret);
581 }
582
583 PAM_EXTERN int
pam_sm_open_session(pam_handle_t * pamh,int flags,int argc,const char * argv[])584 pam_sm_open_session(pam_handle_t *pamh, int flags,
585 int argc, const char *argv[])
586 {
587 int ret;
588 struct pe_opts options;
589
590 ret = parse_options(__func__, &argc, &argv, &options);
591 if (ret != 0)
592 return (PAM_SERVICE_ERR);
593
594 ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
595
596 /*
597 * We must check that the program returned a valid code for this
598 * function.
599 */
600 switch (ret) {
601 case PAM_SUCCESS:
602 case PAM_ABORT:
603 case PAM_BUF_ERR:
604 case PAM_CONV_ERR:
605 case PAM_IGNORE:
606 case PAM_PERM_DENIED:
607 case PAM_SERVICE_ERR:
608 case PAM_SESSION_ERR:
609 case PAM_SYSTEM_ERR:
610 break;
611 default:
612 openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
613 argv[0], ret);
614 ret = PAM_SERVICE_ERR;
615 }
616
617 return (ret);
618 }
619
620 PAM_EXTERN int
pam_sm_close_session(pam_handle_t * pamh,int flags,int argc,const char * argv[])621 pam_sm_close_session(pam_handle_t *pamh, int flags,
622 int argc, const char *argv[])
623 {
624 int ret;
625 struct pe_opts options;
626
627 ret = parse_options(__func__, &argc, &argv, &options);
628 if (ret != 0)
629 return (PAM_SERVICE_ERR);
630
631 ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
632
633 /*
634 * We must check that the program returned a valid code for this
635 * function.
636 */
637 switch (ret) {
638 case PAM_SUCCESS:
639 case PAM_ABORT:
640 case PAM_BUF_ERR:
641 case PAM_CONV_ERR:
642 case PAM_IGNORE:
643 case PAM_PERM_DENIED:
644 case PAM_SERVICE_ERR:
645 case PAM_SESSION_ERR:
646 case PAM_SYSTEM_ERR:
647 break;
648 default:
649 openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
650 argv[0], ret);
651 ret = PAM_SERVICE_ERR;
652 }
653
654 return (ret);
655 }
656
657 PAM_EXTERN int
pam_sm_chauthtok(pam_handle_t * pamh,int flags,int argc,const char * argv[])658 pam_sm_chauthtok(pam_handle_t *pamh, int flags,
659 int argc, const char *argv[])
660 {
661 int ret;
662 struct pe_opts options;
663
664 ret = parse_options(__func__, &argc, &argv, &options);
665 if (ret != 0)
666 return (PAM_SERVICE_ERR);
667
668 ret = _pam_exec(pamh, __func__, flags, argc, argv, &options);
669
670 /*
671 * We must check that the program returned a valid code for this
672 * function.
673 */
674 switch (ret) {
675 case PAM_SUCCESS:
676 case PAM_ABORT:
677 case PAM_AUTHTOK_DISABLE_AGING:
678 case PAM_AUTHTOK_ERR:
679 case PAM_AUTHTOK_LOCK_BUSY:
680 case PAM_AUTHTOK_RECOVERY_ERR:
681 case PAM_BUF_ERR:
682 case PAM_CONV_ERR:
683 case PAM_IGNORE:
684 case PAM_PERM_DENIED:
685 case PAM_SERVICE_ERR:
686 case PAM_SYSTEM_ERR:
687 case PAM_TRY_AGAIN:
688 break;
689 default:
690 openpam_log(PAM_LOG_ERROR, "%s returned invalid code %d",
691 argv[0], ret);
692 ret = PAM_SERVICE_ERR;
693 }
694
695 return (ret);
696 }
697
698 PAM_MODULE_ENTRY("pam_exec");
699