xref: /third_party/curl/src/tool_getpass.c (revision 13498266)
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 */
62char *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
99char *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
137static 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
175char *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