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