blob: c959c5a5258fc39e251dd7c88e131cde393ad290 [file] [log] [blame]
xf.li6c8fc1e2023-08-12 00:11:09 -07001/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24#include "tool_setup.h"
25
26#if defined(__AMIGA__) && !defined(__amigaos4__)
27# undef HAVE_TERMIOS_H
28#endif
29
30#ifndef HAVE_GETPASS_R
31/* this file is only for systems without getpass_r() */
32
33#ifdef HAVE_FCNTL_H
34# include <fcntl.h>
35#endif
36
37#ifdef HAVE_TERMIOS_H
38# include <termios.h>
39#elif defined(HAVE_TERMIO_H)
40# include <termio.h>
41#endif
42
43#ifdef __VMS
44# include descrip
45# include starlet
46# include iodef
47#endif
48
49#ifdef WIN32
50# include <conio.h>
51#endif
52
53#ifdef NETWARE
54# ifdef __NOVELL_LIBC__
55# include <screen.h>
56# else
57# include <nwconio.h>
58# endif
59#endif
60
61#ifdef HAVE_UNISTD_H
62#include <unistd.h>
63#endif
64#include "tool_getpass.h"
65
66#include "memdebug.h" /* keep this as LAST include */
67
68#ifdef __VMS
69/* VMS implementation */
70char *getpass_r(const char *prompt, char *buffer, size_t buflen)
71{
72 long sts;
73 short chan;
74
75 /* MSK, 23-JAN-2004, iosbdef.h wasn't in VAX V7.2 or CC 6.4 */
76 /* distribution so I created this. May revert back later to */
77 /* struct _iosb iosb; */
78 struct _iosb
79 {
80 short int iosb$w_status; /* status */
81 short int iosb$w_bcnt; /* byte count */
82 int unused; /* unused */
83 } iosb;
84
85 $DESCRIPTOR(ttdesc, "TT");
86
87 buffer[0] = '\0';
88 sts = sys$assign(&ttdesc, &chan, 0, 0);
89 if(sts & 1) {
90 sts = sys$qiow(0, chan,
91 IO$_READPROMPT | IO$M_NOECHO,
92 &iosb, 0, 0, buffer, buflen, 0, 0,
93 prompt, strlen(prompt));
94
95 if((sts & 1) && (iosb.iosb$w_status & 1))
96 buffer[iosb.iosb$w_bcnt] = '\0';
97
98 sys$dassgn(chan);
99 }
100 return buffer; /* we always return success */
101}
102#define DONE
103#endif /* __VMS */
104
105#if defined(WIN32)
106
107char *getpass_r(const char *prompt, char *buffer, size_t buflen)
108{
109 size_t i;
110 fputs(prompt, stderr);
111
112 for(i = 0; i < buflen; i++) {
113 buffer[i] = (char)getch();
114 if(buffer[i] == '\r' || buffer[i] == '\n') {
115 buffer[i] = '\0';
116 break;
117 }
118 else
119 if(buffer[i] == '\b')
120 /* remove this letter and if this is not the first key, remove the
121 previous one as well */
122 i = i - (i >= 1 ? 2 : 1);
123 }
124 /* since echo is disabled, print a newline */
125 fputs("\n", stderr);
126 /* if user didn't hit ENTER, terminate buffer */
127 if(i == buflen)
128 buffer[buflen-1] = '\0';
129
130 return buffer; /* we always return success */
131}
132#define DONE
133#endif /* WIN32 */
134
135#ifdef NETWARE
136/* NetWare implementation */
137#ifdef __NOVELL_LIBC__
138char *getpass_r(const char *prompt, char *buffer, size_t buflen)
139{
140 return getpassword(prompt, buffer, buflen);
141}
142#else
143char *getpass_r(const char *prompt, char *buffer, size_t buflen)
144{
145 size_t i = 0;
146
147 printf("%s", prompt);
148 do {
149 buffer[i++] = getch();
150 if(buffer[i-1] == '\b') {
151 /* remove this letter and if this is not the first key,
152 remove the previous one as well */
153 if(i > 1) {
154 printf("\b \b");
155 i = i - 2;
156 }
157 else {
158 RingTheBell();
159 i = i - 1;
160 }
161 }
162 else if(buffer[i-1] != 13)
163 putchar('*');
164
165 } while((buffer[i-1] != 13) && (i < buflen));
166 buffer[i-1] = '\0';
167 printf("\r\n");
168 return buffer;
169}
170#endif /* __NOVELL_LIBC__ */
171#define DONE
172#endif /* NETWARE */
173
174#ifndef DONE /* not previously provided */
175
176#ifdef HAVE_TERMIOS_H
177# define struct_term struct termios
178#elif defined(HAVE_TERMIO_H)
179# define struct_term struct termio
180#else
181# undef struct_term
182#endif
183
184static bool ttyecho(bool enable, int fd)
185{
186#ifdef struct_term
187 static struct_term withecho;
188 static struct_term noecho;
189#endif
190 if(!enable) {
191 /* disable echo by extracting the current 'withecho' mode and remove the
192 ECHO bit and set back the struct */
193#ifdef HAVE_TERMIOS_H
194 tcgetattr(fd, &withecho);
195 noecho = withecho;
196 noecho.c_lflag &= ~ECHO;
197 tcsetattr(fd, TCSANOW, &noecho);
198#elif defined(HAVE_TERMIO_H)
199 ioctl(fd, TCGETA, &withecho);
200 noecho = withecho;
201 noecho.c_lflag &= ~ECHO;
202 ioctl(fd, TCSETA, &noecho);
203#else
204 /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */
205 (void)fd;
206 return FALSE; /* not disabled */
207#endif
208 return TRUE; /* disabled */
209 }
210 /* re-enable echo, assumes we disabled it before (and set the structs we
211 now use to reset the terminal status) */
212#ifdef HAVE_TERMIOS_H
213 tcsetattr(fd, TCSAFLUSH, &withecho);
214#elif defined(HAVE_TERMIO_H)
215 ioctl(fd, TCSETA, &withecho);
216#else
217 return FALSE; /* not enabled */
218#endif
219 return TRUE; /* enabled */
220}
221
222char *getpass_r(const char *prompt, /* prompt to display */
223 char *password, /* buffer to store password in */
224 size_t buflen) /* size of buffer to store password in */
225{
226 ssize_t nread;
227 bool disabled;
228 int fd = open("/dev/tty", O_RDONLY);
229 if(-1 == fd)
230 fd = STDIN_FILENO; /* use stdin if the tty couldn't be used */
231
232 disabled = ttyecho(FALSE, fd); /* disable terminal echo */
233
234 fputs(prompt, stderr);
235 nread = read(fd, password, buflen);
236 if(nread > 0)
237 password[--nread] = '\0'; /* null-terminate where enter is stored */
238 else
239 password[0] = '\0'; /* got nothing */
240
241 if(disabled) {
242 /* if echo actually was disabled, add a newline */
243 fputs("\n", stderr);
244 (void)ttyecho(TRUE, fd); /* enable echo */
245 }
246
247 if(STDIN_FILENO != fd)
248 close(fd);
249
250 return password; /* return pointer to buffer */
251}
252
253#endif /* DONE */
254#endif /* HAVE_GETPASS_R */