1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2012, 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 http://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#ifndef HAVE_GETPASS_R
25/* this file is only for systems without getpass_r() */
26
27#ifdef HAVE_FCNTL_H
28#  include <fcntl.h>
29#endif
30
31#ifdef HAVE_TERMIOS_H
32#  include <termios.h>
33#elif defined(HAVE_TERMIO_H)
34#  include <termio.h>
35#endif
36
37#ifdef __VMS
38#  include descrip
39#  include starlet
40#  include iodef
41#endif
42
43#ifdef WIN32
44#  include <conio.h>
45#endif
46
47#ifdef NETWARE
48#  ifdef __NOVELL_LIBC__
49#    include <screen.h>
50#  else
51#    include <nwconio.h>
52#  endif
53#endif
54
55#define _MPRINTF_REPLACE
56#include <curl/mprintf.h>
57
58#include "tool_getpass.h"
59
60#include "memdebug.h" /* keep this as LAST include */
61
62#ifdef __VMS
63/* VMS implementation */
64char *getpass_r(const char *prompt, char *buffer, size_t buflen)
65{
66  long sts;
67  short chan;
68
69  /* MSK, 23-JAN-2004, iosbdef.h wasn't in VAX V7.2 or CC 6.4  */
70  /* distribution so I created this.  May revert back later to */
71  /* struct _iosb iosb;                                        */
72  struct _iosb
73     {
74     short int iosb$w_status; /* status     */
75     short int iosb$w_bcnt;   /* byte count */
76     int       unused;        /* unused     */
77     } iosb;
78
79  $DESCRIPTOR(ttdesc, "TT");
80
81  buffer[0] = '\0';
82  sts = sys$assign(&ttdesc, &chan, 0, 0);
83  if(sts & 1) {
84    sts = sys$qiow(0, chan,
85                   IO$_READPROMPT | IO$M_NOECHO,
86                   &iosb, 0, 0, buffer, buflen, 0, 0,
87                   prompt, strlen(prompt));
88
89    if((sts & 1) && (iosb.iosb$w_status & 1))
90      buffer[iosb.iosb$w_bcnt] = '\0';
91
92    sts = sys$dassgn(chan);
93  }
94  return buffer; /* we always return success */
95}
96#define DONE
97#endif /* __VMS */
98
99#ifdef __SYMBIAN32__
100#  define getch() getchar()
101#endif
102
103#if defined(WIN32) || defined(__SYMBIAN32__)
104
105char *getpass_r(const char *prompt, char *buffer, size_t buflen)
106{
107  size_t i;
108  fputs(prompt, stderr);
109
110  for(i = 0; i < buflen; i++) {
111    buffer[i] = (char)getch();
112    if(buffer[i] == '\r' || buffer[i] == '\n') {
113      buffer[i] = '\0';
114      break;
115    }
116    else
117      if(buffer[i] == '\b')
118        /* remove this letter and if this is not the first key, remove the
119           previous one as well */
120        i = i - (i >= 1 ? 2 : 1);
121  }
122#ifndef __SYMBIAN32__
123  /* since echo is disabled, print a newline */
124  fputs("\n", stderr);
125#endif
126  /* if user didn't hit ENTER, terminate buffer */
127  if(i == buflen)
128    buffer[buflen-1] = '\0';
129
130  return buffer; /* we always return success */
131}
132#define DONE
133#endif /* WIN32 || __SYMBIAN32__ */
134
135#ifdef NETWARE
136/* NetWare implementation */
137#ifdef __NOVELL_LIBC__
138char *getpass_r(const char *prompt, char *buffer, size_t buflen)
139{
140  return getpassword(prompt, buffer, buflen);
141}
142#else
143char *getpass_r(const char *prompt, char *buffer, size_t buflen)
144{
145  size_t i = 0;
146
147  printf("%s", prompt);
148  do {
149    buffer[i++] = getch();
150    if(buffer[i-1] == '\b') {
151      /* remove this letter and if this is not the first key,
152         remove the previous one as well */
153      if(i > 1) {
154        printf("\b \b");
155        i = i - 2;
156      }
157      else {
158        RingTheBell();
159        i = i - 1;
160      }
161    }
162    else if(buffer[i-1] != 13)
163      putchar('*');
164
165  } while((buffer[i-1] != 13) && (i < buflen));
166  buffer[i-1] = '\0';
167  printf("\r\n");
168  return buffer;
169}
170#endif /* __NOVELL_LIBC__ */
171#define DONE
172#endif /* NETWARE */
173
174#ifndef DONE /* not previously provided */
175
176#ifdef HAVE_TERMIOS_H
177#  define struct_term  struct termios
178#elif defined(HAVE_TERMIO_H)
179#  define struct_term  struct termio
180#else
181#  undef  struct_term
182#endif
183
184static bool ttyecho(bool enable, int fd)
185{
186#ifdef struct_term
187  static struct_term withecho;
188  static struct_term noecho;
189#endif
190  if(!enable) {
191    /* disable echo by extracting the current 'withecho' mode and remove the
192       ECHO bit and set back the struct */
193#ifdef HAVE_TERMIOS_H
194    tcgetattr(fd, &withecho);
195    noecho = withecho;
196    noecho.c_lflag &= ~ECHO;
197    tcsetattr(fd, TCSANOW, &noecho);
198#elif defined(HAVE_TERMIO_H)
199    ioctl(fd, TCGETA, &withecho);
200    noecho = withecho;
201    noecho.c_lflag &= ~ECHO;
202    ioctl(fd, TCSETA, &noecho);
203#else
204    /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */
205    (void)fd;
206    return FALSE; /* not disabled */
207#endif
208    return TRUE; /* disabled */
209  }
210  else {
211    /* re-enable echo, assumes we disabled it before (and set the structs we
212       now use to reset the terminal status) */
213#ifdef HAVE_TERMIOS_H
214    tcsetattr(fd, TCSAFLUSH, &withecho);
215#elif defined(HAVE_TERMIO_H)
216    ioctl(fd, TCSETA, &withecho);
217#else
218    return FALSE; /* not enabled */
219#endif
220    return TRUE; /* enabled */
221  }
222}
223
224char *getpass_r(const char *prompt, /* prompt to display */
225                char *password,     /* buffer to store password in */
226                size_t buflen)      /* size of buffer to store password in */
227{
228  ssize_t nread;
229  bool disabled;
230  int fd = open("/dev/tty", O_RDONLY);
231  if(-1 == fd)
232    fd = 1; /* use stdin if the tty couldn't be used */
233
234  disabled = ttyecho(FALSE, fd); /* disable terminal echo */
235
236  fputs(prompt, stderr);
237  nread = read(fd, password, buflen);
238  if(nread > 0)
239    password[--nread] = '\0'; /* zero terminate where enter is stored */
240  else
241    password[0] = '\0'; /* got nothing */
242
243  if(disabled) {
244    /* if echo actually was disabled, add a newline */
245    fputs("\n", stderr);
246    (void)ttyecho(TRUE, fd); /* enable echo */
247  }
248
249  if(1 != fd)
250    close(fd);
251
252  return password; /* return pointer to buffer */
253}
254
255#endif /* DONE */
256#endif /* HAVE_GETPASS_R */
257