1f7e6344dSDag-Erling Smørgrav /*-
2f7e6344dSDag-Erling Smørgrav * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
3f3b0ac34SDag-Erling Smørgrav * Copyright (c) 2004-2014 Dag-Erling Smørgrav
4f7e6344dSDag-Erling Smørgrav * All rights reserved.
5f7e6344dSDag-Erling Smørgrav *
6f7e6344dSDag-Erling Smørgrav * This software was developed for the FreeBSD Project by ThinkSec AS and
7f7e6344dSDag-Erling Smørgrav * Network Associates Laboratories, the Security Research Division of
8f7e6344dSDag-Erling Smørgrav * Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
9f7e6344dSDag-Erling Smørgrav * ("CBOSS"), as part of the DARPA CHATS research program.
10f7e6344dSDag-Erling Smørgrav *
11f7e6344dSDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without
12f7e6344dSDag-Erling Smørgrav * modification, are permitted provided that the following conditions
13f7e6344dSDag-Erling Smørgrav * are met:
14f7e6344dSDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright
15f7e6344dSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer.
16f7e6344dSDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright
17f7e6344dSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the
18f7e6344dSDag-Erling Smørgrav * documentation and/or other materials provided with the distribution.
19f7e6344dSDag-Erling Smørgrav * 3. The name of the author may not be used to endorse or promote
20f7e6344dSDag-Erling Smørgrav * products derived from this software without specific prior written
21f7e6344dSDag-Erling Smørgrav * permission.
22f7e6344dSDag-Erling Smørgrav *
23f7e6344dSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24f7e6344dSDag-Erling Smørgrav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25f7e6344dSDag-Erling Smørgrav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26f7e6344dSDag-Erling Smørgrav * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27f7e6344dSDag-Erling Smørgrav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28f7e6344dSDag-Erling Smørgrav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29f7e6344dSDag-Erling Smørgrav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30f7e6344dSDag-Erling Smørgrav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31f7e6344dSDag-Erling Smørgrav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32f7e6344dSDag-Erling Smørgrav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33f7e6344dSDag-Erling Smørgrav * SUCH DAMAGE.
34f7e6344dSDag-Erling Smørgrav */
35f7e6344dSDag-Erling Smørgrav
36f7e6344dSDag-Erling Smørgrav #ifdef HAVE_CONFIG_H
37f7e6344dSDag-Erling Smørgrav # include "config.h"
38f7e6344dSDag-Erling Smørgrav #endif
39f7e6344dSDag-Erling Smørgrav
40f7e6344dSDag-Erling Smørgrav #include <sys/types.h>
41ce77a8d6SDag-Erling Smørgrav #include <sys/poll.h>
42ce77a8d6SDag-Erling Smørgrav #include <sys/time.h>
43f7e6344dSDag-Erling Smørgrav
44f7e6344dSDag-Erling Smørgrav #include <errno.h>
45ce77a8d6SDag-Erling Smørgrav #include <fcntl.h>
46f7e6344dSDag-Erling Smørgrav #include <signal.h>
47f7e6344dSDag-Erling Smørgrav #include <stdio.h>
48f7e6344dSDag-Erling Smørgrav #include <stdlib.h>
49f7e6344dSDag-Erling Smørgrav #include <string.h>
50f7e6344dSDag-Erling Smørgrav #include <termios.h>
51f7e6344dSDag-Erling Smørgrav #include <unistd.h>
52f7e6344dSDag-Erling Smørgrav
53f7e6344dSDag-Erling Smørgrav #include <security/pam_appl.h>
54f7e6344dSDag-Erling Smørgrav
55f7e6344dSDag-Erling Smørgrav #include "openpam_impl.h"
56d64f4044SDag-Erling Smørgrav #include "openpam_strlset.h"
57f7e6344dSDag-Erling Smørgrav
58f7e6344dSDag-Erling Smørgrav int openpam_ttyconv_timeout = 0;
59f7e6344dSDag-Erling Smørgrav
60ce77a8d6SDag-Erling Smørgrav static volatile sig_atomic_t caught_signal;
61ce77a8d6SDag-Erling Smørgrav
62ce77a8d6SDag-Erling Smørgrav /*
63ce77a8d6SDag-Erling Smørgrav * Handle incoming signals during tty conversation
64ce77a8d6SDag-Erling Smørgrav */
65f7e6344dSDag-Erling Smørgrav static void
catch_signal(int signo)66ce77a8d6SDag-Erling Smørgrav catch_signal(int signo)
67f7e6344dSDag-Erling Smørgrav {
68f7e6344dSDag-Erling Smørgrav
69ce77a8d6SDag-Erling Smørgrav switch (signo) {
70ce77a8d6SDag-Erling Smørgrav case SIGINT:
71ce77a8d6SDag-Erling Smørgrav case SIGQUIT:
72ce77a8d6SDag-Erling Smørgrav case SIGTERM:
73ce77a8d6SDag-Erling Smørgrav caught_signal = signo;
74ce77a8d6SDag-Erling Smørgrav break;
75ce77a8d6SDag-Erling Smørgrav }
76f7e6344dSDag-Erling Smørgrav }
77f7e6344dSDag-Erling Smørgrav
78ce77a8d6SDag-Erling Smørgrav /*
79ce77a8d6SDag-Erling Smørgrav * Accept a response from the user on a tty
80ce77a8d6SDag-Erling Smørgrav */
81ce77a8d6SDag-Erling Smørgrav static int
prompt_tty(int ifd,int ofd,const char * message,char * response,int echo)82ce77a8d6SDag-Erling Smørgrav prompt_tty(int ifd, int ofd, const char *message, char *response, int echo)
83f7e6344dSDag-Erling Smørgrav {
84ce77a8d6SDag-Erling Smørgrav struct sigaction action;
85ce77a8d6SDag-Erling Smørgrav struct sigaction saction_sigint, saction_sigquit, saction_sigterm;
86ce77a8d6SDag-Erling Smørgrav struct termios tcattr;
87ce77a8d6SDag-Erling Smørgrav struct timeval now, target, remaining;
88ce77a8d6SDag-Erling Smørgrav int remaining_ms;
89ce77a8d6SDag-Erling Smørgrav tcflag_t slflag;
90ce77a8d6SDag-Erling Smørgrav struct pollfd pfd;
91ce77a8d6SDag-Erling Smørgrav int serrno;
92ce77a8d6SDag-Erling Smørgrav int pos, ret;
93f7e6344dSDag-Erling Smørgrav char ch;
94f7e6344dSDag-Erling Smørgrav
95ce77a8d6SDag-Erling Smørgrav /* turn echo off if requested */
96ce77a8d6SDag-Erling Smørgrav slflag = 0; /* prevent bogus uninitialized variable warning */
97ce77a8d6SDag-Erling Smørgrav if (!echo) {
98ce77a8d6SDag-Erling Smørgrav if (tcgetattr(ifd, &tcattr) != 0) {
99ce77a8d6SDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR, "tcgetattr(): %m");
100ce77a8d6SDag-Erling Smørgrav return (-1);
101ce77a8d6SDag-Erling Smørgrav }
102ce77a8d6SDag-Erling Smørgrav slflag = tcattr.c_lflag;
103ce77a8d6SDag-Erling Smørgrav tcattr.c_lflag &= ~ECHO;
104ce77a8d6SDag-Erling Smørgrav if (tcsetattr(ifd, TCSAFLUSH, &tcattr) != 0) {
105ce77a8d6SDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR, "tcsetattr(): %m");
106ce77a8d6SDag-Erling Smørgrav return (-1);
107ce77a8d6SDag-Erling Smørgrav }
108ce77a8d6SDag-Erling Smørgrav }
109ce77a8d6SDag-Erling Smørgrav
110*a90c7d9aSDag-Erling Smørgrav /* write prompt */
111*a90c7d9aSDag-Erling Smørgrav if (write(ofd, message, strlen(message)) < 0) {
112*a90c7d9aSDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR, "write(): %m");
113*a90c7d9aSDag-Erling Smørgrav return (-1);
114*a90c7d9aSDag-Erling Smørgrav }
115*a90c7d9aSDag-Erling Smørgrav
116ce77a8d6SDag-Erling Smørgrav /* install signal handlers */
117ce77a8d6SDag-Erling Smørgrav caught_signal = 0;
118ce77a8d6SDag-Erling Smørgrav action.sa_handler = &catch_signal;
119f7e6344dSDag-Erling Smørgrav action.sa_flags = 0;
120ce77a8d6SDag-Erling Smørgrav sigfillset(&action.sa_mask);
121ce77a8d6SDag-Erling Smørgrav sigaction(SIGINT, &action, &saction_sigint);
122ce77a8d6SDag-Erling Smørgrav sigaction(SIGQUIT, &action, &saction_sigquit);
123ce77a8d6SDag-Erling Smørgrav sigaction(SIGTERM, &action, &saction_sigterm);
124ce77a8d6SDag-Erling Smørgrav
125ce77a8d6SDag-Erling Smørgrav /* compute timeout */
126ce77a8d6SDag-Erling Smørgrav if (openpam_ttyconv_timeout > 0) {
127ce77a8d6SDag-Erling Smørgrav (void)gettimeofday(&now, NULL);
128ce77a8d6SDag-Erling Smørgrav remaining.tv_sec = openpam_ttyconv_timeout;
129ce77a8d6SDag-Erling Smørgrav remaining.tv_usec = 0;
130ce77a8d6SDag-Erling Smørgrav timeradd(&now, &remaining, &target);
131ce77a8d6SDag-Erling Smørgrav } else {
132ce77a8d6SDag-Erling Smørgrav /* prevent bogus uninitialized variable warning */
133ce77a8d6SDag-Erling Smørgrav now.tv_sec = now.tv_usec = 0;
134ce77a8d6SDag-Erling Smørgrav remaining.tv_sec = remaining.tv_usec = 0;
135ce77a8d6SDag-Erling Smørgrav target.tv_sec = target.tv_usec = 0;
136ce77a8d6SDag-Erling Smørgrav }
137ce77a8d6SDag-Erling Smørgrav
138ce77a8d6SDag-Erling Smørgrav /* input loop */
139ce77a8d6SDag-Erling Smørgrav pos = 0;
140ce77a8d6SDag-Erling Smørgrav ret = -1;
141ce77a8d6SDag-Erling Smørgrav serrno = 0;
142ce77a8d6SDag-Erling Smørgrav while (!caught_signal) {
143ce77a8d6SDag-Erling Smørgrav pfd.fd = ifd;
144ce77a8d6SDag-Erling Smørgrav pfd.events = POLLIN;
145ce77a8d6SDag-Erling Smørgrav pfd.revents = 0;
146ce77a8d6SDag-Erling Smørgrav if (openpam_ttyconv_timeout > 0) {
147ce77a8d6SDag-Erling Smørgrav gettimeofday(&now, NULL);
148ce77a8d6SDag-Erling Smørgrav if (timercmp(&now, &target, >))
149ce77a8d6SDag-Erling Smørgrav break;
150ce77a8d6SDag-Erling Smørgrav timersub(&target, &now, &remaining);
151ce77a8d6SDag-Erling Smørgrav remaining_ms = remaining.tv_sec * 1000 +
152ce77a8d6SDag-Erling Smørgrav remaining.tv_usec / 1000;
153ce77a8d6SDag-Erling Smørgrav } else {
154ce77a8d6SDag-Erling Smørgrav remaining_ms = -1;
155ce77a8d6SDag-Erling Smørgrav }
156ce77a8d6SDag-Erling Smørgrav if ((ret = poll(&pfd, 1, remaining_ms)) < 0) {
157ce77a8d6SDag-Erling Smørgrav serrno = errno;
158ce77a8d6SDag-Erling Smørgrav if (errno == EINTR)
159ce77a8d6SDag-Erling Smørgrav continue;
160ce77a8d6SDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR, "poll(): %m");
161ce77a8d6SDag-Erling Smørgrav break;
162ce77a8d6SDag-Erling Smørgrav } else if (ret == 0) {
163ce77a8d6SDag-Erling Smørgrav /* timeout */
164ce77a8d6SDag-Erling Smørgrav write(ofd, " timed out", 10);
165ce77a8d6SDag-Erling Smørgrav openpam_log(PAM_LOG_NOTICE, "timed out");
166ce77a8d6SDag-Erling Smørgrav break;
167ce77a8d6SDag-Erling Smørgrav }
168ce77a8d6SDag-Erling Smørgrav if ((ret = read(ifd, &ch, 1)) < 0) {
169ce77a8d6SDag-Erling Smørgrav serrno = errno;
170ce77a8d6SDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR, "read(): %m");
171ce77a8d6SDag-Erling Smørgrav break;
172ce77a8d6SDag-Erling Smørgrav } else if (ret == 0 || ch == '\n') {
173ce77a8d6SDag-Erling Smørgrav response[pos] = '\0';
174ce77a8d6SDag-Erling Smørgrav ret = pos;
175ce77a8d6SDag-Erling Smørgrav break;
176ce77a8d6SDag-Erling Smørgrav }
177ce77a8d6SDag-Erling Smørgrav if (pos + 1 < PAM_MAX_RESP_SIZE)
178ce77a8d6SDag-Erling Smørgrav response[pos++] = ch;
179ce77a8d6SDag-Erling Smørgrav /* overflow is discarded */
180ce77a8d6SDag-Erling Smørgrav }
181ce77a8d6SDag-Erling Smørgrav
182ce77a8d6SDag-Erling Smørgrav /* restore tty state */
183ce77a8d6SDag-Erling Smørgrav if (!echo) {
184ce77a8d6SDag-Erling Smørgrav tcattr.c_lflag = slflag;
185ce77a8d6SDag-Erling Smørgrav if (tcsetattr(ifd, 0, &tcattr) != 0) {
186ce77a8d6SDag-Erling Smørgrav /* treat as non-fatal, since we have our answer */
187ce77a8d6SDag-Erling Smørgrav openpam_log(PAM_LOG_NOTICE, "tcsetattr(): %m");
188ce77a8d6SDag-Erling Smørgrav }
189ce77a8d6SDag-Erling Smørgrav }
190ce77a8d6SDag-Erling Smørgrav
191ce77a8d6SDag-Erling Smørgrav /* restore signal handlers and re-post caught signal*/
192ce77a8d6SDag-Erling Smørgrav sigaction(SIGINT, &saction_sigint, NULL);
193ce77a8d6SDag-Erling Smørgrav sigaction(SIGQUIT, &saction_sigquit, NULL);
194ce77a8d6SDag-Erling Smørgrav sigaction(SIGTERM, &saction_sigterm, NULL);
195ce77a8d6SDag-Erling Smørgrav if (caught_signal != 0) {
196ce77a8d6SDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR, "caught signal %d",
197ce77a8d6SDag-Erling Smørgrav (int)caught_signal);
198ce77a8d6SDag-Erling Smørgrav raise((int)caught_signal);
199ce77a8d6SDag-Erling Smørgrav /* if raise() had no effect... */
200ce77a8d6SDag-Erling Smørgrav serrno = EINTR;
201ce77a8d6SDag-Erling Smørgrav ret = -1;
202ce77a8d6SDag-Erling Smørgrav }
203ce77a8d6SDag-Erling Smørgrav
204ce77a8d6SDag-Erling Smørgrav /* done */
205ce77a8d6SDag-Erling Smørgrav write(ofd, "\n", 1);
206ce77a8d6SDag-Erling Smørgrav errno = serrno;
207ce77a8d6SDag-Erling Smørgrav return (ret);
208ce77a8d6SDag-Erling Smørgrav }
209ce77a8d6SDag-Erling Smørgrav
210ce77a8d6SDag-Erling Smørgrav /*
211ce77a8d6SDag-Erling Smørgrav * Accept a response from the user on a non-tty stdin.
212ce77a8d6SDag-Erling Smørgrav */
213ce77a8d6SDag-Erling Smørgrav static int
prompt_notty(const char * message,char * response)214ce77a8d6SDag-Erling Smørgrav prompt_notty(const char *message, char *response)
215ce77a8d6SDag-Erling Smørgrav {
216ce77a8d6SDag-Erling Smørgrav struct timeval now, target, remaining;
217ce77a8d6SDag-Erling Smørgrav int remaining_ms;
218ce77a8d6SDag-Erling Smørgrav struct pollfd pfd;
219ce77a8d6SDag-Erling Smørgrav int ch, pos, ret;
220ce77a8d6SDag-Erling Smørgrav
221ce77a8d6SDag-Erling Smørgrav /* show prompt */
222ce77a8d6SDag-Erling Smørgrav fputs(message, stdout);
223ce77a8d6SDag-Erling Smørgrav fflush(stdout);
224ce77a8d6SDag-Erling Smørgrav
225ce77a8d6SDag-Erling Smørgrav /* compute timeout */
226ce77a8d6SDag-Erling Smørgrav if (openpam_ttyconv_timeout > 0) {
227ce77a8d6SDag-Erling Smørgrav (void)gettimeofday(&now, NULL);
228ce77a8d6SDag-Erling Smørgrav remaining.tv_sec = openpam_ttyconv_timeout;
229ce77a8d6SDag-Erling Smørgrav remaining.tv_usec = 0;
230ce77a8d6SDag-Erling Smørgrav timeradd(&now, &remaining, &target);
231ce77a8d6SDag-Erling Smørgrav } else {
232ce77a8d6SDag-Erling Smørgrav /* prevent bogus uninitialized variable warning */
233ce77a8d6SDag-Erling Smørgrav now.tv_sec = now.tv_usec = 0;
234ce77a8d6SDag-Erling Smørgrav remaining.tv_sec = remaining.tv_usec = 0;
235ce77a8d6SDag-Erling Smørgrav target.tv_sec = target.tv_usec = 0;
236ce77a8d6SDag-Erling Smørgrav }
237ce77a8d6SDag-Erling Smørgrav
238ce77a8d6SDag-Erling Smørgrav /* input loop */
239ce77a8d6SDag-Erling Smørgrav pos = 0;
240ce77a8d6SDag-Erling Smørgrav for (;;) {
241ce77a8d6SDag-Erling Smørgrav pfd.fd = STDIN_FILENO;
242ce77a8d6SDag-Erling Smørgrav pfd.events = POLLIN;
243ce77a8d6SDag-Erling Smørgrav pfd.revents = 0;
244ce77a8d6SDag-Erling Smørgrav if (openpam_ttyconv_timeout > 0) {
245ce77a8d6SDag-Erling Smørgrav gettimeofday(&now, NULL);
246ce77a8d6SDag-Erling Smørgrav if (timercmp(&now, &target, >))
247ce77a8d6SDag-Erling Smørgrav break;
248ce77a8d6SDag-Erling Smørgrav timersub(&target, &now, &remaining);
249ce77a8d6SDag-Erling Smørgrav remaining_ms = remaining.tv_sec * 1000 +
250ce77a8d6SDag-Erling Smørgrav remaining.tv_usec / 1000;
251ce77a8d6SDag-Erling Smørgrav } else {
252ce77a8d6SDag-Erling Smørgrav remaining_ms = -1;
253ce77a8d6SDag-Erling Smørgrav }
254ce77a8d6SDag-Erling Smørgrav if ((ret = poll(&pfd, 1, remaining_ms)) < 0) {
255ce77a8d6SDag-Erling Smørgrav /* interrupt is ok, everything else -> bail */
256ce77a8d6SDag-Erling Smørgrav if (errno == EINTR)
257ce77a8d6SDag-Erling Smørgrav continue;
258ce77a8d6SDag-Erling Smørgrav perror("\nopenpam_ttyconv");
259ce77a8d6SDag-Erling Smørgrav return (-1);
260ce77a8d6SDag-Erling Smørgrav } else if (ret == 0) {
261ce77a8d6SDag-Erling Smørgrav /* timeout */
262ce77a8d6SDag-Erling Smørgrav break;
263ce77a8d6SDag-Erling Smørgrav } else {
264ce77a8d6SDag-Erling Smørgrav /* input */
265ce77a8d6SDag-Erling Smørgrav if ((ch = getchar()) == EOF && ferror(stdin)) {
266ce77a8d6SDag-Erling Smørgrav perror("\nopenpam_ttyconv");
267ce77a8d6SDag-Erling Smørgrav return (-1);
268ce77a8d6SDag-Erling Smørgrav }
269ce77a8d6SDag-Erling Smørgrav if (ch == EOF || ch == '\n') {
270ce77a8d6SDag-Erling Smørgrav response[pos] = '\0';
271ce77a8d6SDag-Erling Smørgrav return (pos);
272ce77a8d6SDag-Erling Smørgrav }
273ce77a8d6SDag-Erling Smørgrav if (pos + 1 < PAM_MAX_RESP_SIZE)
274ce77a8d6SDag-Erling Smørgrav response[pos++] = ch;
275ce77a8d6SDag-Erling Smørgrav /* overflow is discarded */
276ce77a8d6SDag-Erling Smørgrav }
277ce77a8d6SDag-Erling Smørgrav }
278ce77a8d6SDag-Erling Smørgrav fputs("\nopenpam_ttyconv: timeout\n", stderr);
279ce77a8d6SDag-Erling Smørgrav return (-1);
280ce77a8d6SDag-Erling Smørgrav }
281ce77a8d6SDag-Erling Smørgrav
282ce77a8d6SDag-Erling Smørgrav /*
283ce77a8d6SDag-Erling Smørgrav * Determine whether stdin is a tty; if not, try to open the tty; in
284ce77a8d6SDag-Erling Smørgrav * either case, call the appropriate method.
285ce77a8d6SDag-Erling Smørgrav */
286ce77a8d6SDag-Erling Smørgrav static int
prompt(const char * message,char * response,int echo)287ce77a8d6SDag-Erling Smørgrav prompt(const char *message, char *response, int echo)
288ce77a8d6SDag-Erling Smørgrav {
289ce77a8d6SDag-Erling Smørgrav int ifd, ofd, ret;
290ce77a8d6SDag-Erling Smørgrav
291ce77a8d6SDag-Erling Smørgrav if (isatty(STDIN_FILENO)) {
292f7e6344dSDag-Erling Smørgrav fflush(stdout);
293f7e6344dSDag-Erling Smørgrav #ifdef HAVE_FPURGE
294f7e6344dSDag-Erling Smørgrav fpurge(stdin);
295f7e6344dSDag-Erling Smørgrav #endif
296ce77a8d6SDag-Erling Smørgrav ifd = STDIN_FILENO;
297ce77a8d6SDag-Erling Smørgrav ofd = STDOUT_FILENO;
298ce77a8d6SDag-Erling Smørgrav } else {
299ce77a8d6SDag-Erling Smørgrav if ((ifd = open("/dev/tty", O_RDWR)) < 0)
300ce77a8d6SDag-Erling Smørgrav /* no way to prevent echo */
301ce77a8d6SDag-Erling Smørgrav return (prompt_notty(message, response));
302ce77a8d6SDag-Erling Smørgrav ofd = ifd;
303f7e6344dSDag-Erling Smørgrav }
304ce77a8d6SDag-Erling Smørgrav ret = prompt_tty(ifd, ofd, message, response, echo);
305ce77a8d6SDag-Erling Smørgrav if (ifd != STDIN_FILENO)
306ce77a8d6SDag-Erling Smørgrav close(ifd);
307f7e6344dSDag-Erling Smørgrav return (ret);
308f7e6344dSDag-Erling Smørgrav }
309f7e6344dSDag-Erling Smørgrav
310f7e6344dSDag-Erling Smørgrav /*
311f7e6344dSDag-Erling Smørgrav * OpenPAM extension
312f7e6344dSDag-Erling Smørgrav *
313f7e6344dSDag-Erling Smørgrav * Simple tty-based conversation function
314f7e6344dSDag-Erling Smørgrav */
315f7e6344dSDag-Erling Smørgrav
316f7e6344dSDag-Erling Smørgrav int
openpam_ttyconv(int n,const struct pam_message ** msg,struct pam_response ** resp,void * data)317f7e6344dSDag-Erling Smørgrav openpam_ttyconv(int n,
318f7e6344dSDag-Erling Smørgrav const struct pam_message **msg,
319f7e6344dSDag-Erling Smørgrav struct pam_response **resp,
320f7e6344dSDag-Erling Smørgrav void *data)
321f7e6344dSDag-Erling Smørgrav {
322ce77a8d6SDag-Erling Smørgrav char respbuf[PAM_MAX_RESP_SIZE];
323f7e6344dSDag-Erling Smørgrav struct pam_response *aresp;
324f7e6344dSDag-Erling Smørgrav int i;
325f7e6344dSDag-Erling Smørgrav
326f7e6344dSDag-Erling Smørgrav ENTER();
327f7e6344dSDag-Erling Smørgrav (void)data;
328f7e6344dSDag-Erling Smørgrav if (n <= 0 || n > PAM_MAX_NUM_MSG)
329f7e6344dSDag-Erling Smørgrav RETURNC(PAM_CONV_ERR);
330f7e6344dSDag-Erling Smørgrav if ((aresp = calloc(n, sizeof *aresp)) == NULL)
331f7e6344dSDag-Erling Smørgrav RETURNC(PAM_BUF_ERR);
332f7e6344dSDag-Erling Smørgrav for (i = 0; i < n; ++i) {
333f7e6344dSDag-Erling Smørgrav aresp[i].resp_retcode = 0;
334f7e6344dSDag-Erling Smørgrav aresp[i].resp = NULL;
335f7e6344dSDag-Erling Smørgrav switch (msg[i]->msg_style) {
336f7e6344dSDag-Erling Smørgrav case PAM_PROMPT_ECHO_OFF:
337ce77a8d6SDag-Erling Smørgrav if (prompt(msg[i]->msg, respbuf, 0) < 0 ||
338ce77a8d6SDag-Erling Smørgrav (aresp[i].resp = strdup(respbuf)) == NULL)
339f7e6344dSDag-Erling Smørgrav goto fail;
340f7e6344dSDag-Erling Smørgrav break;
341f7e6344dSDag-Erling Smørgrav case PAM_PROMPT_ECHO_ON:
342ce77a8d6SDag-Erling Smørgrav if (prompt(msg[i]->msg, respbuf, 1) < 0 ||
343ce77a8d6SDag-Erling Smørgrav (aresp[i].resp = strdup(respbuf)) == NULL)
344f7e6344dSDag-Erling Smørgrav goto fail;
345f7e6344dSDag-Erling Smørgrav break;
346f7e6344dSDag-Erling Smørgrav case PAM_ERROR_MSG:
347f7e6344dSDag-Erling Smørgrav fputs(msg[i]->msg, stderr);
348f7e6344dSDag-Erling Smørgrav if (strlen(msg[i]->msg) > 0 &&
349f7e6344dSDag-Erling Smørgrav msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
350f7e6344dSDag-Erling Smørgrav fputc('\n', stderr);
351f7e6344dSDag-Erling Smørgrav break;
352f7e6344dSDag-Erling Smørgrav case PAM_TEXT_INFO:
353f7e6344dSDag-Erling Smørgrav fputs(msg[i]->msg, stdout);
354f7e6344dSDag-Erling Smørgrav if (strlen(msg[i]->msg) > 0 &&
355f7e6344dSDag-Erling Smørgrav msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
356f7e6344dSDag-Erling Smørgrav fputc('\n', stdout);
357f7e6344dSDag-Erling Smørgrav break;
358f7e6344dSDag-Erling Smørgrav default:
359f7e6344dSDag-Erling Smørgrav goto fail;
360f7e6344dSDag-Erling Smørgrav }
361f7e6344dSDag-Erling Smørgrav }
362f7e6344dSDag-Erling Smørgrav *resp = aresp;
363ce77a8d6SDag-Erling Smørgrav memset(respbuf, 0, sizeof respbuf);
364f7e6344dSDag-Erling Smørgrav RETURNC(PAM_SUCCESS);
365f7e6344dSDag-Erling Smørgrav fail:
366f7e6344dSDag-Erling Smørgrav for (i = 0; i < n; ++i) {
367f7e6344dSDag-Erling Smørgrav if (aresp[i].resp != NULL) {
368d64f4044SDag-Erling Smørgrav strlset(aresp[i].resp, 0, PAM_MAX_RESP_SIZE);
369f7e6344dSDag-Erling Smørgrav FREE(aresp[i].resp);
370f7e6344dSDag-Erling Smørgrav }
371f7e6344dSDag-Erling Smørgrav }
372f7e6344dSDag-Erling Smørgrav memset(aresp, 0, n * sizeof *aresp);
373f7e6344dSDag-Erling Smørgrav FREE(aresp);
374f7e6344dSDag-Erling Smørgrav *resp = NULL;
375ce77a8d6SDag-Erling Smørgrav memset(respbuf, 0, sizeof respbuf);
376f7e6344dSDag-Erling Smørgrav RETURNC(PAM_CONV_ERR);
377f7e6344dSDag-Erling Smørgrav }
378f7e6344dSDag-Erling Smørgrav
379f7e6344dSDag-Erling Smørgrav /*
380f7e6344dSDag-Erling Smørgrav * Error codes:
381f7e6344dSDag-Erling Smørgrav *
382f7e6344dSDag-Erling Smørgrav * PAM_SYSTEM_ERR
383f7e6344dSDag-Erling Smørgrav * PAM_BUF_ERR
384f7e6344dSDag-Erling Smørgrav * PAM_CONV_ERR
385f7e6344dSDag-Erling Smørgrav */
386f7e6344dSDag-Erling Smørgrav
387f7e6344dSDag-Erling Smørgrav /**
388f7e6344dSDag-Erling Smørgrav * The =openpam_ttyconv function is a standard conversation function
389f7e6344dSDag-Erling Smørgrav * suitable for use on TTY devices.
390f7e6344dSDag-Erling Smørgrav * It should be adequate for the needs of most text-based interactive
391f7e6344dSDag-Erling Smørgrav * programs.
392f7e6344dSDag-Erling Smørgrav *
393f7e6344dSDag-Erling Smørgrav * The =openpam_ttyconv function allows the application to specify a
394f7e6344dSDag-Erling Smørgrav * timeout for user input by setting the global integer variable
395f7e6344dSDag-Erling Smørgrav * :openpam_ttyconv_timeout to the length of the timeout in seconds.
396f7e6344dSDag-Erling Smørgrav *
397f7e6344dSDag-Erling Smørgrav * >openpam_nullconv
398f7e6344dSDag-Erling Smørgrav * >pam_prompt
399f7e6344dSDag-Erling Smørgrav * >pam_vprompt
400f7e6344dSDag-Erling Smørgrav */
401