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