2 * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
3 * Copyright (c) 2004-2007 Dag-Erling Smørgrav
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
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
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
35 * $Id: openpam_ttyconv.c,v 1.11 2008/01/27 01:23:00 christos Exp $
38 #include <sys/types.h>
51 #include <security/pam_appl.h>
53 #include "openpam_impl.h"
55 int openpam_ttyconv_timeout
= 0;
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
;
78 sigaddset(&sigs
, SIGINT
);
79 sigaddset(&sigs
, SIGTSTP
);
80 sigprocmask(SIG_SETMASK
, &sigs
, &saved_sigset
);
81 action
.sa_handler
= &timeout
;
83 sigemptyset(&action
.sa_mask
);
84 sigaction(SIGALRM
, &action
, &saved_action
);
96 if (openpam_ttyconv_timeout
>= 0)
97 saved_alarm
= alarm((unsigned int)openpam_ttyconv_timeout
);
99 for (len
= 0; ch
!= '\n' && !eof
&& !error
; ++len
) {
100 switch (read(fd
, &ch
, (size_t)1)) {
102 if (len
< PAM_MAX_RESP_SIZE
- 1) {
115 if (openpam_ttyconv_timeout
>= 0)
117 sigaction(SIGALRM
, &saved_action
, NULL
);
118 sigprocmask(SIG_SETMASK
, &saved_sigset
, NULL
);
122 fputs(" timeout!", errfp
);
125 memset(buf
, 0, sizeof(buf
));
128 /* trim trailing whitespace */
129 for (len
= strlen(buf
); len
> 0; --len
)
130 if (buf
[len
- 1] != '\r' && buf
[len
- 1] != '\n')
133 retval
= strdup(buf
);
134 memset(buf
, 0, sizeof(buf
));
139 prompt_echo_off(const char *msg
, FILE *infp
, FILE *outfp
, FILE *errfp
)
141 struct termios tattr
;
147 if (tcgetattr(fd
, &tattr
) != 0) {
148 openpam_log(PAM_LOG_ERROR
, "tcgetattr(): %m");
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");
157 ret
= prompt(msg
, infp
, outfp
, errfp
);
158 tattr
.c_lflag
= lflag
;
159 (void)tcsetattr(fd
, TCSANOW
, &tattr
);
168 * Simple tty-based conversation function
172 openpam_ttyconv(int n
,
173 const struct pam_message
**msg
,
174 struct pam_response
**resp
,
177 struct pam_response
*aresp
;
179 FILE *infp
, *outfp
, *errfp
;
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
) {
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
,
206 if (aresp
[i
].resp
== NULL
)
209 case PAM_PROMPT_ECHO_ON
:
210 aresp
[i
].resp
= prompt(msg
[i
]->msg
, infp
, outfp
, errfp
);
211 if (aresp
[i
].resp
== NULL
)
215 fputs(msg
[i
]->msg
, errfp
);
216 if (strlen(msg
[i
]->msg
) > 0 &&
217 msg
[i
]->msg
[strlen(msg
[i
]->msg
) - 1] != '\n')
221 fputs(msg
[i
]->msg
, outfp
);
222 if (strlen(msg
[i
]->msg
) > 0 &&
223 msg
[i
]->msg
[strlen(msg
[i
]->msg
) - 1] != '\n')
233 RETURNC(PAM_SUCCESS
);
237 for (i
= 0; i
< n
; ++i
) {
238 if (aresp
[i
].resp
!= NULL
) {
239 memset(aresp
[i
].resp
, 0, strlen(aresp
[i
].resp
));
243 memset(aresp
, 0, n
* sizeof *aresp
);
246 RETURNC(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
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
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.