1 | /*************************************************************************** |
2 | * _ _ ____ _ |
3 | * Project ___| | | | _ \| | |
4 | * / __| | | | |_) | | |
5 | * | (__| |_| | _ <| |___ |
6 | * \___|\___/|_| \_\_____| |
7 | * |
8 | * Copyright (C) 1998 - 2019, 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.haxx.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 */ |
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 | #ifdef __SYMBIAN32__ |
104 | # define getch() getchar() |
105 | #endif |
106 | |
107 | #if defined(WIN32) || defined(__SYMBIAN32__) |
108 | |
109 | char *getpass_r(const char *prompt, char *buffer, size_t buflen) |
110 | { |
111 | size_t i; |
112 | fputs(prompt, stderr); |
113 | |
114 | for(i = 0; i < buflen; i++) { |
115 | buffer[i] = (char)getch(); |
116 | if(buffer[i] == '\r' || buffer[i] == '\n') { |
117 | buffer[i] = '\0'; |
118 | break; |
119 | } |
120 | else |
121 | if(buffer[i] == '\b') |
122 | /* remove this letter and if this is not the first key, remove the |
123 | previous one as well */ |
124 | i = i - (i >= 1 ? 2 : 1); |
125 | } |
126 | #ifndef __SYMBIAN32__ |
127 | /* since echo is disabled, print a newline */ |
128 | fputs("\n" , stderr); |
129 | #endif |
130 | /* if user didn't hit ENTER, terminate buffer */ |
131 | if(i == buflen) |
132 | buffer[buflen-1] = '\0'; |
133 | |
134 | return buffer; /* we always return success */ |
135 | } |
136 | #define DONE |
137 | #endif /* WIN32 || __SYMBIAN32__ */ |
138 | |
139 | #ifdef NETWARE |
140 | /* NetWare implementation */ |
141 | #ifdef __NOVELL_LIBC__ |
142 | char *getpass_r(const char *prompt, char *buffer, size_t buflen) |
143 | { |
144 | return getpassword(prompt, buffer, buflen); |
145 | } |
146 | #else |
147 | char *getpass_r(const char *prompt, char *buffer, size_t buflen) |
148 | { |
149 | size_t i = 0; |
150 | |
151 | printf("%s" , prompt); |
152 | do { |
153 | buffer[i++] = getch(); |
154 | if(buffer[i-1] == '\b') { |
155 | /* remove this letter and if this is not the first key, |
156 | remove the previous one as well */ |
157 | if(i > 1) { |
158 | printf("\b \b" ); |
159 | i = i - 2; |
160 | } |
161 | else { |
162 | RingTheBell(); |
163 | i = i - 1; |
164 | } |
165 | } |
166 | else if(buffer[i-1] != 13) |
167 | putchar('*'); |
168 | |
169 | } while((buffer[i-1] != 13) && (i < buflen)); |
170 | buffer[i-1] = '\0'; |
171 | printf("\r\n" ); |
172 | return buffer; |
173 | } |
174 | #endif /* __NOVELL_LIBC__ */ |
175 | #define DONE |
176 | #endif /* NETWARE */ |
177 | |
178 | #ifndef DONE /* not previously provided */ |
179 | |
180 | #ifdef HAVE_TERMIOS_H |
181 | # define struct_term struct termios |
182 | #elif defined(HAVE_TERMIO_H) |
183 | # define struct_term struct termio |
184 | #else |
185 | # undef struct_term |
186 | #endif |
187 | |
188 | static bool ttyecho(bool enable, int fd) |
189 | { |
190 | #ifdef struct_term |
191 | static struct_term withecho; |
192 | static struct_term noecho; |
193 | #endif |
194 | if(!enable) { |
195 | /* disable echo by extracting the current 'withecho' mode and remove the |
196 | ECHO bit and set back the struct */ |
197 | #ifdef HAVE_TERMIOS_H |
198 | tcgetattr(fd, &withecho); |
199 | noecho = withecho; |
200 | noecho.c_lflag &= ~ECHO; |
201 | tcsetattr(fd, TCSANOW, &noecho); |
202 | #elif defined(HAVE_TERMIO_H) |
203 | ioctl(fd, TCGETA, &withecho); |
204 | noecho = withecho; |
205 | noecho.c_lflag &= ~ECHO; |
206 | ioctl(fd, TCSETA, &noecho); |
207 | #else |
208 | /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */ |
209 | (void)fd; |
210 | return FALSE; /* not disabled */ |
211 | #endif |
212 | return TRUE; /* disabled */ |
213 | } |
214 | /* re-enable echo, assumes we disabled it before (and set the structs we |
215 | now use to reset the terminal status) */ |
216 | #ifdef HAVE_TERMIOS_H |
217 | tcsetattr(fd, TCSAFLUSH, &withecho); |
218 | #elif defined(HAVE_TERMIO_H) |
219 | ioctl(fd, TCSETA, &withecho); |
220 | #else |
221 | return FALSE; /* not enabled */ |
222 | #endif |
223 | return TRUE; /* enabled */ |
224 | } |
225 | |
226 | char *getpass_r(const char *prompt, /* prompt to display */ |
227 | char *password, /* buffer to store password in */ |
228 | size_t buflen) /* size of buffer to store password in */ |
229 | { |
230 | ssize_t nread; |
231 | bool disabled; |
232 | int fd = open("/dev/tty" , O_RDONLY); |
233 | if(-1 == fd) |
234 | fd = STDIN_FILENO; /* use stdin if the tty couldn't be used */ |
235 | |
236 | disabled = ttyecho(FALSE, fd); /* disable terminal echo */ |
237 | |
238 | fputs(prompt, stderr); |
239 | nread = read(fd, password, buflen); |
240 | if(nread > 0) |
241 | password[--nread] = '\0'; /* zero terminate where enter is stored */ |
242 | else |
243 | password[0] = '\0'; /* got nothing */ |
244 | |
245 | if(disabled) { |
246 | /* if echo actually was disabled, add a newline */ |
247 | fputs("\n" , stderr); |
248 | (void)ttyecho(TRUE, fd); /* enable echo */ |
249 | } |
250 | |
251 | if(STDIN_FILENO != fd) |
252 | close(fd); |
253 | |
254 | return password; /* return pointer to buffer */ |
255 | } |
256 | |
257 | #endif /* DONE */ |
258 | #endif /* HAVE_GETPASS_R */ |
259 | |