xref: /curl/src/tool_getpass.c (revision e9a7d4a1)
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 wasn't 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 didn't 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 &= ~ECHO;
150     tcsetattr(fd, TCSANOW, &noecho);
151 #elif defined(HAVE_TERMIO_H)
152     ioctl(fd, TCGETA, &withecho);
153     noecho = withecho;
154     noecho.c_lflag &= ~ECHO;
155     ioctl(fd, TCSETA, &noecho);
156 #else
157     /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't 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 couldn't 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