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 */
68char *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
109char *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__
142char *getpass_r(const char *prompt, char *buffer, size_t buflen)
143{
144 return getpassword(prompt, buffer, buflen);
145}
146#else
147char *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
188static 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
226char *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