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