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