source: openpam/trunk/lib/openpam_ttyconv.c @ 417

Last change on this file since 417 was 417, checked in by des, 6 years ago

Update copyright, and coincidentially root out the last remaining vestige
of iso-8859-1 in favor of utf-8.

  • Property svn:keywords set to Id
File size: 6.2 KB
Line 
1/*-
2 * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
3 * Copyright (c) 2004-2008 Dag-Erling Smørgrav
4 * All rights reserved.
5 *
6 * This software was developed for the FreeBSD Project by ThinkSec AS and
7 * Network Associates Laboratories, the Security Research Division of
8 * Network Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
9 * ("CBOSS"), as part of the DARPA CHATS research program.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote
20 *    products derived from this software without specific prior written
21 *    permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * $Id$
36 */
37
38#ifdef HAVE_CONFIG_H
39# include "config.h"
40#endif
41
42#include <sys/types.h>
43
44#include <ctype.h>
45#include <errno.h>
46#include <setjmp.h>
47#include <signal.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <termios.h>
52#include <unistd.h>
53
54#include <security/pam_appl.h>
55
56#include "openpam_impl.h"
57
58int openpam_ttyconv_timeout = 0;
59
60static void
61timeout(int sig)
62{
63
64        (void)sig;
65}
66
67static char *
68prompt(const char *msg)
69{
70        char buf[PAM_MAX_RESP_SIZE];
71        struct sigaction action, saved_action;
72        sigset_t saved_sigset, sigset;
73        unsigned int saved_alarm;
74        int eof, error, fd;
75        size_t len;
76        char *retval;
77        char ch;
78
79        sigemptyset(&sigset);
80        sigaddset(&sigset, SIGINT);
81        sigaddset(&sigset, SIGTSTP);
82        sigprocmask(SIG_SETMASK, &sigset, &saved_sigset);
83        action.sa_handler = &timeout;
84        action.sa_flags = 0;
85        sigemptyset(&action.sa_mask);
86        sigaction(SIGALRM, &action, &saved_action);
87        fputs(msg, stdout);
88        fflush(stdout);
89#ifdef HAVE_FPURGE
90        fpurge(stdin);
91#endif
92        fd = fileno(stdin);
93        buf[0] = '\0';
94        eof = error = 0;
95        saved_alarm = 0;
96        if (openpam_ttyconv_timeout >= 0)
97                saved_alarm = alarm(openpam_ttyconv_timeout);
98        ch = '\0';
99        for (len = 0; ch != '\n' && !eof && !error; ++len) {
100                switch (read(fd, &ch, 1)) {
101                case 1:
102                        if (len < PAM_MAX_RESP_SIZE - 1) {
103                                buf[len + 1] = '\0';
104                                buf[len] = ch;
105                        }
106                        break;
107                case 0:
108                        eof = 1;
109                        break;
110                default:
111                        error = errno;
112                        break;
113                }
114        }
115        if (openpam_ttyconv_timeout >= 0)
116                alarm(0);
117        sigaction(SIGALRM, &saved_action, NULL);
118        sigprocmask(SIG_SETMASK, &saved_sigset, NULL);
119        if (saved_alarm > 0)
120                alarm(saved_alarm);
121        if (error == EINTR)
122                fputs(" timeout!", stderr);
123        if (error || eof) {
124                fputs("\n", stderr);
125                memset(buf, 0, sizeof(buf));
126                return (NULL);
127        }
128        /* trim trailing whitespace */
129        for (len = strlen(buf); len > 0; --len)
130                if (buf[len - 1] != '\r' && buf[len - 1] != '\n')
131                        break;
132        buf[len] = '\0';
133        retval = strdup(buf);
134        memset(buf, 0, sizeof(buf));
135        return (retval);
136}
137
138static char *
139prompt_echo_off(const char *msg)
140{
141        struct termios tattr;
142        tcflag_t lflag;
143        char *ret;
144        int fd;
145
146        fd = fileno(stdin);
147        if (tcgetattr(fd, &tattr) != 0) {
148                openpam_log(PAM_LOG_ERROR, "tcgetattr(): %m");
149                return (NULL);
150        }
151        lflag = tattr.c_lflag;
152        tattr.c_lflag &= ~ECHO;
153        if (tcsetattr(fd, TCSAFLUSH, &tattr) != 0) {
154                openpam_log(PAM_LOG_ERROR, "tcsetattr(): %m");
155                return (NULL);
156        }
157        ret = prompt(msg);
158        tattr.c_lflag = lflag;
159        (void)tcsetattr(fd, TCSANOW, &tattr);
160        if (ret != NULL)
161                fputs("\n", stdout);
162        return (ret);
163}
164
165/*
166 * OpenPAM extension
167 *
168 * Simple tty-based conversation function
169 */
170
171int
172openpam_ttyconv(int n,
173         const struct pam_message **msg,
174         struct pam_response **resp,
175         void *data)
176{
177        struct pam_response *aresp;
178        int i;
179
180        ENTER();
181        (void)data;
182        if (n <= 0 || n > PAM_MAX_NUM_MSG)
183                RETURNC(PAM_CONV_ERR);
184        if ((aresp = calloc(n, sizeof *aresp)) == NULL)
185                RETURNC(PAM_BUF_ERR);
186        for (i = 0; i < n; ++i) {
187                aresp[i].resp_retcode = 0;
188                aresp[i].resp = NULL;
189                switch (msg[i]->msg_style) {
190                case PAM_PROMPT_ECHO_OFF:
191                        aresp[i].resp = prompt_echo_off(msg[i]->msg);
192                        if (aresp[i].resp == NULL)
193                                goto fail;
194                        break;
195                case PAM_PROMPT_ECHO_ON:
196                        aresp[i].resp = prompt(msg[i]->msg);
197                        if (aresp[i].resp == NULL)
198                                goto fail;
199                        break;
200                case PAM_ERROR_MSG:
201                        fputs(msg[i]->msg, stderr);
202                        if (strlen(msg[i]->msg) > 0 &&
203                            msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
204                                fputc('\n', stderr);
205                        break;
206                case PAM_TEXT_INFO:
207                        fputs(msg[i]->msg, stdout);
208                        if (strlen(msg[i]->msg) > 0 &&
209                            msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
210                                fputc('\n', stdout);
211                        break;
212                default:
213                        goto fail;
214                }
215        }
216        *resp = aresp;
217        RETURNC(PAM_SUCCESS);
218 fail:
219        for (i = 0; i < n; ++i) {
220                if (aresp[i].resp != NULL) {
221                        memset(aresp[i].resp, 0, strlen(aresp[i].resp));
222                        FREE(aresp[i].resp);
223                }
224        }
225        memset(aresp, 0, n * sizeof *aresp);
226        FREE(aresp);
227        *resp = NULL;
228        RETURNC(PAM_CONV_ERR);
229}
230
231/*
232 * Error codes:
233 *
234 *      PAM_SYSTEM_ERR
235 *      PAM_BUF_ERR
236 *      PAM_CONV_ERR
237 */
238
239/**
240 * The =openpam_ttyconv function is a standard conversation function
241 * suitable for use on TTY devices.
242 * It should be adequate for the needs of most text-based interactive
243 * programs.
244 *
245 * The =openpam_ttyconv function allows the application to specify a
246 * timeout for user input by setting the global integer variable
247 * :openpam_ttyconv_timeout to the length of the timeout in seconds.
248 *
249 * >openpam_nullconv
250 * >pam_prompt
251 * >pam_vprompt
252 */
Note: See TracBrowser for help on using the repository browser.