1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2011, 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
23/* This file is a reimplementation of the previous one, due to license
24   problems. */
25
26#include "setup.h"
27
28#ifndef HAVE_GETPASS_R
29/* this file is only for systems without getpass_r() */
30
31#include <stdio.h>
32#include <string.h>
33
34#ifdef HAVE_UNISTD_H
35#include <unistd.h>
36#endif
37
38#include "getpass.h"
39
40#ifdef HAVE_FCNTL_H
41#include <fcntl.h>
42#endif
43#ifdef HAVE_TERMIOS_H
44#include <termios.h>
45#else
46#ifdef HAVE_TERMIO_H
47#include <termio.h>
48#endif
49#endif
50
51/* The last #include file should be: */
52#if defined(CURLDEBUG) && defined(CURLTOOLDEBUG)
53#include "memdebug.h"
54#endif
55
56#ifdef __VMS
57/* VMS implementation */
58#include descrip
59#include starlet
60#include iodef
61/* #include iosbdef */
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    sts = sys$dassgn(chan);
91  }
92  return buffer; /* we always return success */
93}
94#define DONE
95#endif /* __VMS */
96
97
98#ifdef WIN32
99/* Windows implementation */
100#include <conio.h>
101#endif
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__
142#include <screen.h>
143char *getpass_r(const char *prompt, char *buffer, size_t buflen)
144{
145  return getpassword(prompt, buffer, buflen);
146}
147#else
148#include <nwconio.h>
149char *getpass_r(const char *prompt, char *buffer, size_t buflen)
150{
151  size_t i = 0;
152
153  printf("%s", prompt);
154  do {
155    buffer[i++] = getch();
156    if(buffer[i-1] == '\b') {
157      /* remove this letter and if this is not the first key,
158         remove the previous one as well */
159      if(i > 1) {
160        printf("\b \b");
161        i = i - 2;
162      }
163      else {
164        RingTheBell();
165        i = i - 1;
166      }
167    }
168    else if(buffer[i-1] != 13)
169      putchar('*');
170
171  } while((buffer[i-1] != 13) && (i < buflen));
172  buffer[i-1] = 0;
173  printf("\r\n");
174  return buffer;
175}
176#endif /* __NOVELL_LIBC__ */
177#define DONE
178#endif /* NETWARE */
179
180#ifndef DONE /* not previously provided */
181
182#ifdef HAVE_TERMIOS_H
183#define struct_term struct termios
184#else
185#ifdef HAVE_TERMIO_H
186#define struct_term  struct termio
187#else
188#undef struct_term
189#endif
190#endif
191
192static bool ttyecho(bool enable, int fd)
193{
194#ifdef struct_term
195  static struct_term withecho;
196  static struct_term noecho;
197#endif
198  if(!enable) {
199    /* disable echo by extracting the current 'withecho' mode and remove the
200       ECHO bit and set back the struct */
201#ifdef HAVE_TERMIOS_H
202    tcgetattr(fd, &withecho);
203    noecho = withecho;
204    noecho.c_lflag &= ~ECHO;
205    tcsetattr(fd, TCSANOW, &noecho);
206#else /* HAVE_TERMIOS_H */
207#ifdef HAVE_TERMIO_H
208    ioctl(fd, TCGETA, &withecho);
209    noecho = withecho;
210    noecho.c_lflag &= ~ECHO;
211    ioctl(fd, TCSETA, &noecho);
212#else /* HAVE_TERMIO_H */
213/* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */
214    (void)fd; /* prevent compiler warning on unused variable */
215    return FALSE; /* not disabled */
216#endif
217#endif
218    return TRUE; /* disabled */
219  }
220  else {
221    /* re-enable echo, assumes we disabled it before (and set the structs we
222       now use to reset the terminal status) */
223#ifdef HAVE_TERMIOS_H
224    tcsetattr(fd, TCSAFLUSH, &withecho);
225#else /* HAVE_TERMIOS_H */
226#ifdef HAVE_TERMIO_H
227    ioctl(fd, TCSETA, &withecho);
228#else
229/* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H */
230    return FALSE; /* not enabled */
231#endif
232#endif
233    return TRUE; /* enabled */
234  }
235}
236
237char *getpass_r(const char *prompt, /* prompt to display */
238                char *password,     /* buffer to store password in */
239                size_t buflen)      /* size of buffer to store password in */
240{
241  ssize_t nread;
242  bool disabled;
243  int fd=open("/dev/tty", O_RDONLY);
244  if(-1 == fd)
245    fd = 1; /* use stdin if the tty couldn't be used */
246
247  disabled = ttyecho(FALSE, fd); /* disable terminal echo */
248
249  fputs(prompt, stderr);
250  nread=read(fd, password, buflen);
251  if(nread > 0)
252    password[--nread]=0; /* zero terminate where enter is stored */
253  else
254    password[0]=0; /* got nothing */
255
256  if(disabled) {
257    /* if echo actually was disabled, add a newline */
258    fputs("\n", stderr);
259    (void)ttyecho(TRUE, fd); /* enable echo */
260  }
261
262  if(1 != fd)
263    close(fd);
264
265  return password; /* return pointer to buffer */
266}
267
268#endif /* DONE */
269#endif /* HAVE_GETPASS_R */
270