Revert "Revert ABI version, make libgnutls-extra use another ABI version."
[gnutls.git] / gl / getpass.c
blob208e21bbdaf0205a84dfcd8a957a0f5a4984c2f2
1 /* Copyright (C) 1992-2001, 2003, 2004, 2005, 2006, 2007 Free Software
2 Foundation, Inc.
4 This file is part of the GNU C Library.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation,
18 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
20 #ifndef _LIBC
21 # include <config.h>
22 #endif
24 #include "getpass.h"
26 #include <stdio.h>
28 #if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
30 #include <stdbool.h>
32 #if HAVE_DECL___FSETLOCKING && HAVE___FSETLOCKING
33 # if HAVE_STDIO_EXT_H
34 # include <stdio_ext.h>
35 # endif
36 #else
37 # define __fsetlocking(stream, type) /* empty */
38 #endif
40 #if HAVE_TERMIOS_H
41 # include <termios.h>
42 #endif
44 #if USE_UNLOCKED_IO
45 # include "unlocked-io.h"
46 #else
47 # if !HAVE_DECL_FFLUSH_UNLOCKED
48 # undef fflush_unlocked
49 # define fflush_unlocked(x) fflush (x)
50 # endif
51 # if !HAVE_DECL_FLOCKFILE
52 # undef flockfile
53 # define flockfile(x) ((void) 0)
54 # endif
55 # if !HAVE_DECL_FUNLOCKFILE
56 # undef funlockfile
57 # define funlockfile(x) ((void) 0)
58 # endif
59 # if !HAVE_DECL_FPUTS_UNLOCKED
60 # undef fputs_unlocked
61 # define fputs_unlocked(str,stream) fputs (str, stream)
62 # endif
63 # if !HAVE_DECL_PUTC_UNLOCKED
64 # undef putc_unlocked
65 # define putc_unlocked(c,stream) putc (c, stream)
66 # endif
67 #endif
69 /* It is desirable to use this bit on systems that have it.
70 The only bit of terminal state we want to twiddle is echoing, which is
71 done in software; there is no need to change the state of the terminal
72 hardware. */
74 #ifndef TCSASOFT
75 # define TCSASOFT 0
76 #endif
78 static void
79 call_fclose (void *arg)
81 if (arg != NULL)
82 fclose (arg);
85 char *
86 getpass (const char *prompt)
88 FILE *tty;
89 FILE *in, *out;
90 struct termios s, t;
91 bool tty_changed = false;
92 static char *buf;
93 static size_t bufsize;
94 ssize_t nread;
96 /* Try to write to and read from the terminal if we can.
97 If we can't open the terminal, use stderr and stdin. */
99 tty = fopen ("/dev/tty", "w+");
100 if (tty == NULL)
102 in = stdin;
103 out = stderr;
105 else
107 /* We do the locking ourselves. */
108 __fsetlocking (tty, FSETLOCKING_BYCALLER);
110 out = in = tty;
113 flockfile (out);
115 /* Turn echoing off if it is on now. */
116 #if HAVE_TCGETATTR
117 if (tcgetattr (fileno (in), &t) == 0)
119 /* Save the old one. */
120 s = t;
121 /* Tricky, tricky. */
122 t.c_lflag &= ~(ECHO | ISIG);
123 tty_changed = (tcsetattr (fileno (in), TCSAFLUSH | TCSASOFT, &t) == 0);
125 #endif
127 /* Write the prompt. */
128 fputs_unlocked (prompt, out);
129 fflush_unlocked (out);
131 /* Read the password. */
132 nread = getline (&buf, &bufsize, in);
134 /* According to the C standard, input may not be followed by output
135 on the same stream without an intervening call to a file
136 positioning function. Suppose in == out; then without this fseek
137 call, on Solaris, HP-UX, AIX, OSF/1, the previous input gets
138 echoed, whereas on IRIX, the following newline is not output as
139 it should be. POSIX imposes similar restrictions if fileno (in)
140 == fileno (out). The POSIX restrictions are tricky and change
141 from POSIX version to POSIX version, so play it safe and invoke
142 fseek even if in != out. */
143 fseeko (out, 0, SEEK_CUR);
145 if (buf != NULL)
147 if (nread < 0)
148 buf[0] = '\0';
149 else if (buf[nread - 1] == '\n')
151 /* Remove the newline. */
152 buf[nread - 1] = '\0';
153 if (tty_changed)
155 /* Write the newline that was not echoed. */
156 putc_unlocked ('\n', out);
161 /* Restore the original setting. */
162 #if HAVE_TCSETATTR
163 if (tty_changed)
164 tcsetattr (fileno (in), TCSAFLUSH | TCSASOFT, &s);
165 #endif
167 funlockfile (out);
169 call_fclose (tty);
171 return buf;
174 #else /* W32 native */
176 /* Windows implementation by Martin Lambers <marlam@marlam.de>,
177 improved by Simon Josefsson. */
179 /* For PASS_MAX. */
180 #include <limits.h>
181 /* For _getch(). */
182 #include <conio.h>
183 /* For strdup(). */
184 #include <string.h>
186 #ifndef PASS_MAX
187 # define PASS_MAX 512
188 #endif
190 char *
191 getpass (const char *prompt)
193 char getpassbuf[PASS_MAX + 1];
194 size_t i = 0;
195 int c;
197 if (prompt)
199 fputs (prompt, stderr);
200 fflush (stderr);
203 for (;;)
205 c = _getch ();
206 if (c == '\r')
208 getpassbuf[i] = '\0';
209 break;
211 else if (i < PASS_MAX)
213 getpassbuf[i++] = c;
216 if (i >= PASS_MAX)
218 getpassbuf[i] = '\0';
219 break;
223 if (prompt)
225 fputs ("\r\n", stderr);
226 fflush (stderr);
229 return strdup (getpassbuf);
231 #endif