]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/apr/passwd/apr_getpass.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / apr / passwd / apr_getpass.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /* apr_password_get.c: abstraction to provide for obtaining a password from the
18  * command line in whatever way the OS supports.  In the best case, it's a
19  * wrapper for the system library's getpass() routine; otherwise, we
20  * use one we define ourselves.
21  */
22 #include "apr_private.h"
23 #include "apr_strings.h"
24 #include "apr_lib.h"
25 #include "apr_errno.h"
26 #if APR_HAVE_SYS_TYPES_H
27 #include <sys/types.h>
28 #endif
29 #if APR_HAVE_ERRNO_H
30 #include <errno.h>
31 #endif
32
33 #if APR_HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #if APR_HAVE_CONIO_H
37 #ifdef _MSC_VER
38 #pragma warning(disable: 4032)
39 #include <conio.h>
40 #pragma warning(default: 4032)
41 #else
42 #include <conio.h>
43 #endif
44 #endif
45 #if APR_HAVE_STDLIB_H
46 #include <stdlib.h>
47 #endif
48 #if APR_HAVE_STRING_H
49 #include <string.h>
50 #endif
51 #if APR_HAVE_STRINGS_H
52 #include <strings.h>
53 #endif
54
55 /* Disable getpass() support when PASS_MAX is defined and is "small",
56  * for an arbitrary definition of "small".
57  * HP-UX truncates passwords (PR49496) so we disable getpass() for
58  * this platform too.
59  */
60 #if defined(HAVE_GETPASS) && \
61     (defined(PASS_MAX) && PASS_MAX < 32) || defined(__hpux) || defined(__hpux__)
62 #undef HAVE_GETPASS
63 #endif
64
65 #if defined(HAVE_TERMIOS_H) && !defined(HAVE_GETPASS)
66 #include <termios.h>
67 #endif
68
69 #if !APR_CHARSET_EBCDIC
70 #define LF 10
71 #define CR 13
72 #else /* APR_CHARSET_EBCDIC */
73 #define LF '\n'
74 #define CR '\r'
75 #endif /* APR_CHARSET_EBCDIC */
76
77 #define MAX_STRING_LEN 256
78
79 #define ERR_OVERFLOW 5
80
81 #if !defined(HAVE_GETPASS) && !defined(HAVE_GETPASSPHRASE) && !defined(HAVE_GETPASS_R)
82
83 /* MPE, Win32, NetWare and BeOS all lack a native getpass() */
84
85 #if !defined(HAVE_TERMIOS_H) && !defined(WIN32) && !defined(NETWARE)
86 /*
87  * MPE lacks getpass() and a way to suppress stdin echo.  So for now, just
88  * issue the prompt and read the results with echo.  (Ugh).
89  */
90
91 static char *get_password(const char *prompt)
92 {
93     static char password[MAX_STRING_LEN];
94
95     fputs(prompt, stderr);
96     fgets((char *) &password, sizeof(password), stdin);
97
98     return (char *) &password;
99 }
100
101 #elif defined (HAVE_TERMIOS_H)
102 #include <stdio.h>
103
104 static char *get_password(const char *prompt)
105 {
106     struct termios attr;
107     static char password[MAX_STRING_LEN];
108     int n=0;
109     fputs(prompt, stderr);
110     fflush(stderr);
111
112     if (tcgetattr(STDIN_FILENO, &attr) != 0)
113         return NULL;
114     attr.c_lflag &= ~(ECHO);
115
116     if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) != 0)
117         return NULL;
118     while ((password[n] = getchar()) != '\n') {
119         if (n < sizeof(password) - 1 && password[n] >= ' ' && password[n] <= '~') {
120             n++;
121         } else {
122             fprintf(stderr,"\n");
123             fputs(prompt, stderr);
124             fflush(stderr);
125             n = 0;
126         }
127     }
128  
129     password[n] = '\0';
130     printf("\n");
131     if (n > (MAX_STRING_LEN - 1)) {
132         password[MAX_STRING_LEN - 1] = '\0';
133     }
134
135     attr.c_lflag |= ECHO;
136     tcsetattr(STDIN_FILENO, TCSANOW, &attr);
137     return (char*) &password;
138 }
139
140 #else
141
142 /*
143  * Windows lacks getpass().  So we'll re-implement it here.
144  */
145
146 static char *get_password(const char *prompt)
147 {
148 /* WCE lacks console. So the getpass is unsuported
149  * The only way is to use the GUI so the getpass should be implemented
150  * on per-application basis.
151  */ 
152 #ifdef _WIN32_WCE
153     return NULL;
154 #else
155     static char password[128];
156     int n = 0;
157     int ch;
158
159     fputs(prompt, stderr);
160     
161     while ((ch = _getch()) != '\r') {
162         if (ch == EOF) /* EOF */ {
163             fputs("[EOF]\n", stderr);
164             return NULL;
165         }
166         else if (ch == 0 || ch == 0xE0) {
167             /* FN Keys (0 or E0) are a sentinal for a FN code */ 
168             ch = (ch << 4) | _getch();
169             /* Catch {DELETE}, {<--}, Num{DEL} and Num{<--} */
170             if ((ch == 0xE53 || ch == 0xE4B || ch == 0x053 || ch == 0x04b) && n) {
171                 password[--n] = '\0';
172                 fputs("\b \b", stderr);
173             }
174             else {
175                 fputc('\a', stderr);
176             }
177         }
178         else if ((ch == '\b' || ch == 127) && n) /* BS/DEL */ {
179             password[--n] = '\0';
180             fputs("\b \b", stderr);
181         }
182         else if (ch == 3) /* CTRL+C */ {
183             /* _getch() bypasses Ctrl+C but not Ctrl+Break detection! */
184             fputs("^C\n", stderr);
185             exit(-1);
186         }
187         else if (ch == 26) /* CTRL+Z */ {
188             fputs("^Z\n", stderr);
189             return NULL;
190         }
191         else if (ch == 27) /* ESC */ {
192             fputc('\n', stderr);
193             fputs(prompt, stderr);
194             n = 0;
195         }
196         else if ((n < sizeof(password) - 1) && !apr_iscntrl(ch)) {
197             password[n++] = ch;
198             fputc('*', stderr);
199         }
200         else {
201             fputc('\a', stderr);
202         }
203     }
204  
205     fputc('\n', stderr);
206     password[n] = '\0';
207     return password;
208 #endif
209 }
210
211 #endif /* no getchar or _getch */
212
213 #endif /* no getpass or getpassphrase or getpass_r */
214
215 /*
216  * Use the OS getpass() routine (or our own) to obtain a password from
217  * the input stream.
218  *
219  * Exit values:
220  *  0: Success
221  *  5: Partial success; entered text truncated to the size of the
222  *     destination buffer
223  *
224  * Restrictions: Truncation also occurs according to the host system's
225  * getpass() semantics, or at position 255 if our own version is used,
226  * but the caller is *not* made aware of it unless their own buffer is
227  * smaller than our own.
228  */
229
230 APR_DECLARE(apr_status_t) apr_password_get(const char *prompt, char *pwbuf, apr_size_t *bufsiz)
231 {
232     apr_status_t rv = APR_SUCCESS;
233 #if defined(HAVE_GETPASS_R)
234     if (getpass_r(prompt, pwbuf, *bufsiz) == NULL)
235         return APR_EINVAL;
236 #else
237 #if defined(HAVE_GETPASSPHRASE)
238     char *pw_got = getpassphrase(prompt);
239 #elif defined(HAVE_GETPASS)
240     char *pw_got = getpass(prompt);
241 #else /* use the replacement implementation above */
242     char *pw_got = get_password(prompt);
243 #endif
244
245     if (!pw_got)
246         return APR_EINVAL;
247     if (strlen(pw_got) >= *bufsiz) {
248         rv = APR_ENAMETOOLONG;
249     }
250     apr_cpystrn(pwbuf, pw_got, *bufsiz);
251     memset(pw_got, 0, strlen(pw_got));
252 #endif /* HAVE_GETPASS_R */
253     return rv;
254 }