2 * Copyright 1990 - 1995, Julianne Frances Haugh
3 * Copyright 1998, Pavel Machek <pavel@ucw.cz>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #ident "$Id: getpass.c,v 1.15 2006/05/12 22:54:22 kloczek Exp $"
41 /* new code, #undef if there are any problems... */
45 static sigjmp_buf intr; /* where to jump on SIGINT */
48 static int sig_caught;
51 static struct sigaction sigact;
54 /*ARGSUSED*/ static RETSIGTYPE sig_catch (int sig)
65 static char *readpass (FILE * ifp, FILE * ofp, int with_echo, int max_asterisks)
67 static char input[MAXLEN + 1], asterix[MAXLEN + 1];
72 if (max_asterisks < 0) {
73 /* traditional code using fgets() */
74 if (fgets (input, sizeof input, ifp) != input)
76 cp = strrchr (input, '\n');
80 input[sizeof input - 1] = '\0';
84 srandom (time (0) * getpid ());
89 while (read (fileno (ifp), &c, 1)) {
99 for (i = *ap; i > 0; i--)
100 fputs ("\b \b", ofp);
104 putc ('\a', ofp); /* BEL */
107 case '\025': /* Ctrl-U = erase everything typed so far */
109 putc ('\a', ofp); /* BEL */
114 for (i = *ap; i > 0; i--)
115 fputs ("\b \b", ofp);
125 } else if (max_asterisks > 0) {
126 *ap = (random () % max_asterisks) + 1;
127 for (i = *ap; i > 0; i--)
136 if (cp >= input + MAXLEN) {
137 putc ('\a', ofp); /* BEL */
147 static char *prompt_password (const char *prompt, int with_echo)
149 static char nostring[1] = "";
150 static char *return_value;
151 volatile int tty_opened;
152 static FILE *ifp, *ofp;
155 #ifdef HAVE_SIGACTION
156 struct sigaction old_sigact;
158 RETSIGTYPE (*old_signal) ();
161 int max_asterisks = getdef_num ("GETPASS_ASTERISKS", -1);
164 * set a flag so the SIGINT signal can be re-sent if it
173 * if /dev/tty can't be opened, getpass() needs to read
174 * from stdin and write to stderr instead.
177 if (!(ifp = fopen ("/dev/tty", "r+"))) {
184 setbuf (ifp, (char *) 0);
187 * the current tty modes must be saved so they can be
188 * restored later on. echo will be turned off, except
189 * for the newline character
193 if (GTTY (fileno (ifp), &old_modes)) {
198 * If we get a SIGINT, sig_catch() will jump here -
199 * no need to press Enter after Ctrl-C.
201 if (sigsetjmp (intr, 1))
205 #ifdef HAVE_SIGACTION
206 sigact.sa_handler = sig_catch;
207 sigemptyset (&sigact.sa_mask);
209 sigaction (SIGINT, &sigact, &old_sigact);
211 old_signal = signal (SIGINT, sig_catch);
215 TERMIO new_modes = old_modes;
217 if (max_asterisks < 0)
218 new_modes.c_lflag |= ICANON;
220 new_modes.c_lflag &= ~(ICANON);
223 new_modes.c_lflag |= (ECHO | ECHOE | ECHOK);
225 new_modes.c_lflag &= ~(ECHO | ECHOE | ECHOK);
227 new_modes.c_lflag |= ECHONL;
229 if (STTY (fileno (ifp), &new_modes))
234 * the prompt is output, and the response read without
235 * echoing. the trailing newline must be removed. if
236 * the fgets() returns an error, a NULL pointer is
240 if ((fputs (prompt, ofp) != EOF) && (fflush (ofp) != EOF))
241 return_value = readpass (ifp, ofp, with_echo, max_asterisks);
244 * the old SIGINT handler is restored after the tty
245 * modes. then /dev/tty is closed if it was opened in
246 * the beginning. finally, if a signal was caught it
247 * is sent to this process for normal processing.
251 if (STTY (fileno (ifp), &old_modes))
254 #ifdef HAVE_SIGACTION
255 (void) sigaction (SIGINT, &old_sigact, NULL);
257 (void) signal (SIGINT, old_signal);
263 kill (getpid (), SIGINT);
268 return_value = nostring;
273 char *libshadow_getpass (const char *prompt)
275 return prompt_password (prompt, 0);
278 char *getpass_with_echo (const char *prompt)
280 return prompt_password (prompt, 1);