1 /* Copyright (C) 1992-2001, 2003-2007, 2009-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
10 This file is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19 /* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc
20 warns for the null checks on 'prompt' below. */
21 # define _GL_ARG_NONNULL(params)
29 #if !(defined _WIN32 && !defined __CYGWIN__)
31 # if HAVE_DECL___FSETLOCKING && HAVE___FSETLOCKING
33 # include <stdio_ext.h>
36 # define __fsetlocking(stream, type) /* empty */
44 # include "unlocked-io.h"
46 # if !HAVE_DECL_FFLUSH_UNLOCKED
47 # undef fflush_unlocked
48 # define fflush_unlocked(x) fflush (x)
50 # if !HAVE_DECL_FLOCKFILE
52 # define flockfile(x) ((void) 0)
54 # if !HAVE_DECL_FUNLOCKFILE
56 # define funlockfile(x) ((void) 0)
58 # if !HAVE_DECL_FPUTS_UNLOCKED
59 # undef fputs_unlocked
60 # define fputs_unlocked(str,stream) fputs (str, stream)
62 # if !HAVE_DECL_PUTC_UNLOCKED
64 # define putc_unlocked(c,stream) putc (c, stream)
68 /* It is desirable to use this bit on systems that have it.
69 The only bit of terminal state we want to twiddle is echoing, which is
70 done in software; there is no need to change the state of the terminal
78 call_fclose (void *arg
)
85 getpass (const char *prompt
)
92 bool tty_changed
= false;
94 static size_t bufsize
;
97 /* Try to write to and read from the terminal if we can.
98 If we can't open the terminal, use stderr and stdin. */
100 tty
= fopen ("/dev/tty", "w+e");
108 /* We do the locking ourselves. */
109 __fsetlocking (tty
, FSETLOCKING_BYCALLER
);
116 /* Turn echoing off if it is on now. */
118 if (tcgetattr (fileno (in
), &t
) == 0)
120 /* Save the old one. */
122 /* Tricky, tricky. */
123 t
.c_lflag
&= ~(ECHO
| ISIG
);
124 tty_changed
= (tcsetattr (fileno (in
), TCSAFLUSH
| TCSASOFT
, &t
) == 0);
130 /* Write the prompt. */
131 fputs_unlocked (prompt
, out
);
132 fflush_unlocked (out
);
135 /* Read the password. */
136 nread
= getline (&buf
, &bufsize
, in
);
138 /* According to the C standard, input may not be followed by output
139 on the same stream without an intervening call to a file
140 positioning function. Suppose in == out; then without this fseek
141 call, on Solaris, HP-UX, AIX, OSF/1, the previous input gets
142 echoed, whereas on IRIX, the following newline is not output as
143 it should be. POSIX imposes similar restrictions if fileno (in)
144 == fileno (out). The POSIX restrictions are tricky and change
145 from POSIX version to POSIX version, so play it safe and invoke
146 fseek even if in != out. */
147 fseeko (out
, 0, SEEK_CUR
);
153 else if (buf
[nread
- 1] == '\n')
155 /* Remove the newline. */
156 buf
[nread
- 1] = '\0';
159 /* Write the newline that was not echoed. */
160 putc_unlocked ('\n', out
);
165 /* Restore the original setting. */
168 tcsetattr (fileno (in
), TCSAFLUSH
| TCSASOFT
, &s
);
178 #else /* W32 native */
180 /* Windows implementation by Martin Lambers <marlam@marlam.de>,
181 improved by Simon Josefsson. */
191 # define PASS_MAX 512
195 getpass (const char *prompt
)
197 char getpassbuf
[PASS_MAX
+ 1];
203 fputs (prompt
, stderr
);
212 getpassbuf
[i
] = '\0';
215 else if (i
< PASS_MAX
)
222 getpassbuf
[i
] = '\0';
229 fputs ("\r\n", stderr
);
233 return strdup (getpassbuf
);