1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 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 HAVE_UNISTD_H
54 #include <unistd.h>
55 #endif
56 #include "tool_getpass.h"
57
58 #include "memdebug.h" /* keep this as LAST include */
59
60 #ifdef __VMS
61 /* VMS implementation */
getpass_r(const char * prompt,char * buffer,size_t buflen)62 char *getpass_r(const char *prompt, char *buffer, size_t buflen)
63 {
64 long sts;
65 short chan;
66
67 /* MSK, 23-JAN-2004, iosbdef.h was not in VAX V7.2 or CC 6.4 */
68 /* distribution so I created this. May revert back later to */
69 /* struct _iosb iosb; */
70 struct _iosb
71 {
72 short int iosb$w_status; /* status */
73 short int iosb$w_bcnt; /* byte count */
74 int unused; /* unused */
75 } iosb;
76
77 $DESCRIPTOR(ttdesc, "TT");
78
79 buffer[0] = '\0';
80 sts = sys$assign(&ttdesc, &chan, 0, 0);
81 if(sts & 1) {
82 sts = sys$qiow(0, chan,
83 IO$_READPROMPT | IO$M_NOECHO,
84 &iosb, 0, 0, buffer, buflen, 0, 0,
85 prompt, strlen(prompt));
86
87 if((sts & 1) && (iosb.iosb$w_status & 1))
88 buffer[iosb.iosb$w_bcnt] = '\0';
89
90 sys$dassgn(chan);
91 }
92 return buffer; /* we always return success */
93 }
94 #define DONE
95 #endif /* __VMS */
96
97 #if defined(_WIN32)
98
getpass_r(const char * prompt,char * buffer,size_t buflen)99 char *getpass_r(const char *prompt, char *buffer, size_t buflen)
100 {
101 size_t i;
102 fputs(prompt, tool_stderr);
103
104 for(i = 0; i < buflen; i++) {
105 buffer[i] = (char)getch();
106 if(buffer[i] == '\r' || buffer[i] == '\n') {
107 buffer[i] = '\0';
108 break;
109 }
110 else
111 if(buffer[i] == '\b')
112 /* remove this letter and if this is not the first key, remove the
113 previous one as well */
114 i = i - (i >= 1 ? 2 : 1);
115 }
116 /* since echo is disabled, print a newline */
117 fputs("\n", tool_stderr);
118 /* if user did not hit ENTER, terminate buffer */
119 if(i == buflen)
120 buffer[buflen-1] = '\0';
121
122 return buffer; /* we always return success */
123 }
124 #define DONE
125 #endif /* _WIN32 */
126
127 #ifndef DONE /* not previously provided */
128
129 #ifdef HAVE_TERMIOS_H
130 # define struct_term struct termios
131 #elif defined(HAVE_TERMIO_H)
132 # define struct_term struct termio
133 #else
134 # undef struct_term
135 #endif
136
ttyecho(bool enable,int fd)137 static bool ttyecho(bool enable, int fd)
138 {
139 #ifdef struct_term
140 static struct_term withecho;
141 static struct_term noecho;
142 #endif
143 if(!enable) {
144 /* disable echo by extracting the current 'withecho' mode and remove the
145 ECHO bit and set back the struct */
146 #ifdef HAVE_TERMIOS_H
147 tcgetattr(fd, &withecho);
148 noecho = withecho;
149 noecho.c_lflag &= ~(tcflag_t)ECHO;
150 tcsetattr(fd, TCSANOW, &noecho);
151 #elif defined(HAVE_TERMIO_H)
152 ioctl(fd, TCGETA, &withecho);
153 noecho = withecho;
154 noecho.c_lflag &= ~(tcflag_t)ECHO;
155 ioctl(fd, TCSETA, &noecho);
156 #else
157 /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we cannot disable echo! */
158 (void)fd;
159 return FALSE; /* not disabled */
160 #endif
161 return TRUE; /* disabled */
162 }
163 /* re-enable echo, assumes we disabled it before (and set the structs we
164 now use to reset the terminal status) */
165 #ifdef HAVE_TERMIOS_H
166 tcsetattr(fd, TCSAFLUSH, &withecho);
167 #elif defined(HAVE_TERMIO_H)
168 ioctl(fd, TCSETA, &withecho);
169 #else
170 return FALSE; /* not enabled */
171 #endif
172 return TRUE; /* enabled */
173 }
174
getpass_r(const char * prompt,char * password,size_t buflen)175 char *getpass_r(const char *prompt, /* prompt to display */
176 char *password, /* buffer to store password in */
177 size_t buflen) /* size of buffer to store password in */
178 {
179 ssize_t nread;
180 bool disabled;
181 int fd = open("/dev/tty", O_RDONLY);
182 if(-1 == fd)
183 fd = STDIN_FILENO; /* use stdin if the tty could not be used */
184
185 disabled = ttyecho(FALSE, fd); /* disable terminal echo */
186
187 fputs(prompt, tool_stderr);
188 nread = read(fd, password, buflen);
189 if(nread > 0)
190 password[--nread] = '\0'; /* null-terminate where enter is stored */
191 else
192 password[0] = '\0'; /* got nothing */
193
194 if(disabled) {
195 /* if echo actually was disabled, add a newline */
196 fputs("\n", tool_stderr);
197 (void)ttyecho(TRUE, fd); /* enable echo */
198 }
199
200 if(STDIN_FILENO != fd)
201 close(fd);
202
203 return password; /* return pointer to buffer */
204 }
205
206 #endif /* DONE */
207 #endif /* HAVE_GETPASS_R */
208