Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / openpam / lib / openpam_ttyconv.c
blob65b40ac13c02dccde30fe7268b474c7cdb96b02d
1 /*-
2 * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
3 * Copyright (c) 2004-2007 Dag-Erling Smørgrav
4 * All rights reserved.
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.
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.
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.
35 * $Id: openpam_ttyconv.c,v 1.11 2008/01/27 01:23:00 christos Exp $
38 #include <sys/types.h>
40 #include <ctype.h>
41 #include <errno.h>
42 #include <setjmp.h>
43 #include <signal.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <termios.h>
48 #include <unistd.h>
49 #include <paths.h>
51 #include <security/pam_appl.h>
53 #include "openpam_impl.h"
55 int openpam_ttyconv_timeout = 0;
57 static void
58 timeout(int sig)
60 /*LINTED unused*/
61 (void)sig;
64 static char *
65 prompt(const char *msg, FILE *infp, FILE *outfp, FILE *errfp)
67 char buf[PAM_MAX_RESP_SIZE];
68 struct sigaction action, saved_action;
69 sigset_t saved_sigset, sigs;
70 unsigned int saved_alarm;
71 int eof, error, fd;
72 size_t len;
73 char *retval;
74 char ch;
76 saved_alarm = 0;
77 sigemptyset(&sigs);
78 sigaddset(&sigs, SIGINT);
79 sigaddset(&sigs, SIGTSTP);
80 sigprocmask(SIG_SETMASK, &sigs, &saved_sigset);
81 action.sa_handler = &timeout;
82 action.sa_flags = 0;
83 sigemptyset(&action.sa_mask);
84 sigaction(SIGALRM, &action, &saved_action);
87 fputs(msg, outfp);
88 fflush(outfp);
89 #ifdef HAVE_FPURGE
90 fpurge(infp);
91 #endif
92 fd = fileno(infp);
93 buf[0] = '\0';
94 eof = error = 0;
95 saved_alarm = 0;
96 if (openpam_ttyconv_timeout >= 0)
97 saved_alarm = alarm((unsigned int)openpam_ttyconv_timeout);
98 ch = '\0';
99 for (len = 0; ch != '\n' && !eof && !error; ++len) {
100 switch (read(fd, &ch, (size_t)1)) {
101 case 1:
102 if (len < PAM_MAX_RESP_SIZE - 1) {
103 buf[len + 1] = '\0';
104 buf[len] = ch;
106 break;
107 case 0:
108 eof = 1;
109 break;
110 default:
111 error = errno;
112 break;
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!", errfp);
123 if (error || eof) {
124 fputs("\n", errfp);
125 memset(buf, 0, sizeof(buf));
126 return (NULL);
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);
138 static char *
139 prompt_echo_off(const char *msg, FILE *infp, FILE *outfp, FILE *errfp)
141 struct termios tattr;
142 tcflag_t lflag;
143 char *ret;
144 int fd;
146 fd = fileno(infp);
147 if (tcgetattr(fd, &tattr) != 0) {
148 openpam_log(PAM_LOG_ERROR, "tcgetattr(): %m");
149 return (NULL);
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);
157 ret = prompt(msg, infp, outfp, errfp);
158 tattr.c_lflag = lflag;
159 (void)tcsetattr(fd, TCSANOW, &tattr);
160 if (ret != NULL)
161 fputs("\n", outfp);
162 return (ret);
166 * OpenPAM extension
168 * Simple tty-based conversation function
172 openpam_ttyconv(int n,
173 const struct pam_message **msg,
174 struct pam_response **resp,
175 void *data)
177 struct pam_response *aresp;
178 int i;
179 FILE *infp, *outfp, *errfp;
181 ENTER();
182 /*LINTED unused*/
183 (void)data;
184 if (n <= 0 || n > PAM_MAX_NUM_MSG)
185 RETURNC(PAM_CONV_ERR);
186 if ((aresp = calloc((size_t)n, sizeof *aresp)) == NULL)
187 RETURNC(PAM_BUF_ERR);
190 * read and write to /dev/tty if possible; else read from
191 * stdin and write to stderr.
193 if ((outfp = infp = errfp = fopen(_PATH_TTY, "w+")) == NULL) {
194 errfp = stderr;
195 outfp = stderr;
196 infp = stdin;
199 for (i = 0; i < n; ++i) {
200 aresp[i].resp_retcode = 0;
201 aresp[i].resp = NULL;
202 switch (msg[i]->msg_style) {
203 case PAM_PROMPT_ECHO_OFF:
204 aresp[i].resp = prompt_echo_off(msg[i]->msg, infp,
205 outfp, errfp);
206 if (aresp[i].resp == NULL)
207 goto fail;
208 break;
209 case PAM_PROMPT_ECHO_ON:
210 aresp[i].resp = prompt(msg[i]->msg, infp, outfp, errfp);
211 if (aresp[i].resp == NULL)
212 goto fail;
213 break;
214 case PAM_ERROR_MSG:
215 fputs(msg[i]->msg, errfp);
216 if (strlen(msg[i]->msg) > 0 &&
217 msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
218 fputc('\n', errfp);
219 break;
220 case PAM_TEXT_INFO:
221 fputs(msg[i]->msg, outfp);
222 if (strlen(msg[i]->msg) > 0 &&
223 msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
224 fputc('\n', outfp);
225 break;
226 default:
227 goto fail;
230 if (infp != stdin)
231 (void)fclose(infp);
232 *resp = aresp;
233 RETURNC(PAM_SUCCESS);
234 fail:
235 if (infp != stdin)
236 (void)fclose(infp);
237 for (i = 0; i < n; ++i) {
238 if (aresp[i].resp != NULL) {
239 memset(aresp[i].resp, 0, strlen(aresp[i].resp));
240 FREE(aresp[i].resp);
243 memset(aresp, 0, n * sizeof *aresp);
244 FREE(aresp);
245 *resp = NULL;
246 RETURNC(PAM_CONV_ERR);
247 /*NOTREACHED*/
251 * Error codes:
253 * PAM_SYSTEM_ERR
254 * PAM_BUF_ERR
255 * PAM_CONV_ERR
259 * The =openpam_ttyconv function is a standard conversation function
260 * suitable for use on TTY devices.
261 * It should be adequate for the needs of most text-based interactive
262 * programs.
264 * The =openpam_ttyconv function displays a prompt to, and reads in a
265 * password from /dev/tty. If this file is not accessible, =openpam_ttyconv
266 * displays the prompt on the standard error output and reads from the
267 * standard input.
269 * The =openpam_ttyconv function allows the application to specify a
270 * timeout for user input by setting the global integer variable
271 * :openpam_ttyconv_timeout to the length of the timeout in seconds.
273 * >openpam_nullconv
274 * >pam_prompt
275 * >pam_vprompt
276 * >getpass