1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251875Speter * contributor license agreements.  See the NOTICE file distributed with
3251875Speter * this work for additional information regarding copyright ownership.
4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251875Speter * (the "License"); you may not use this file except in compliance with
6251875Speter * the License.  You may obtain a copy of the License at
7251875Speter *
8251875Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251875Speter *
10251875Speter * Unless required by applicable law or agreed to in writing, software
11251875Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251875Speter * See the License for the specific language governing permissions and
14251875Speter * limitations under the License.
15251875Speter */
16251875Speter
17251875Speter/* apr_password_get.c: abstraction to provide for obtaining a password from the
18251875Speter * command line in whatever way the OS supports.  In the best case, it's a
19251875Speter * wrapper for the system library's getpass() routine; otherwise, we
20251875Speter * use one we define ourselves.
21251875Speter */
22251875Speter#include "apr_private.h"
23251875Speter#include "apr_strings.h"
24251875Speter#include "apr_lib.h"
25251875Speter#include "apr_errno.h"
26251875Speter#if APR_HAVE_SYS_TYPES_H
27251875Speter#include <sys/types.h>
28251875Speter#endif
29251875Speter#if APR_HAVE_ERRNO_H
30251875Speter#include <errno.h>
31251875Speter#endif
32251875Speter
33251875Speter#if APR_HAVE_UNISTD_H
34251875Speter#include <unistd.h>
35251875Speter#endif
36251875Speter#if APR_HAVE_CONIO_H
37251875Speter#ifdef _MSC_VER
38251875Speter#pragma warning(disable: 4032)
39251875Speter#include <conio.h>
40251875Speter#pragma warning(default: 4032)
41251875Speter#else
42251875Speter#include <conio.h>
43251875Speter#endif
44251875Speter#endif
45251875Speter#if APR_HAVE_STDLIB_H
46251875Speter#include <stdlib.h>
47251875Speter#endif
48251875Speter#if APR_HAVE_STRING_H
49251875Speter#include <string.h>
50251875Speter#endif
51251875Speter#if APR_HAVE_STRINGS_H
52251875Speter#include <strings.h>
53251875Speter#endif
54266735Speter#if APR_HAVE_STDIO_H
55266735Speter#include <stdio.h>
56266735Speter#endif
57251875Speter
58251875Speter/* Disable getpass() support when PASS_MAX is defined and is "small",
59251875Speter * for an arbitrary definition of "small".
60251875Speter * HP-UX truncates passwords (PR49496) so we disable getpass() for
61251875Speter * this platform too.
62251875Speter */
63251875Speter#if defined(HAVE_GETPASS) && \
64251875Speter    (defined(PASS_MAX) && PASS_MAX < 32) || defined(__hpux) || defined(__hpux__)
65251875Speter#undef HAVE_GETPASS
66251875Speter#endif
67251875Speter
68251875Speter#if defined(HAVE_TERMIOS_H) && !defined(HAVE_GETPASS)
69251875Speter#include <termios.h>
70251875Speter#endif
71251875Speter
72251875Speter#if !APR_CHARSET_EBCDIC
73251875Speter#define LF 10
74251875Speter#define CR 13
75251875Speter#else /* APR_CHARSET_EBCDIC */
76251875Speter#define LF '\n'
77251875Speter#define CR '\r'
78251875Speter#endif /* APR_CHARSET_EBCDIC */
79251875Speter
80251875Speter#define MAX_STRING_LEN 256
81251875Speter
82251875Speter#define ERR_OVERFLOW 5
83251875Speter
84251875Speter#if !defined(HAVE_GETPASS) && !defined(HAVE_GETPASSPHRASE) && !defined(HAVE_GETPASS_R)
85251875Speter
86266735Speter/* MPE, Win32, and BeOS all lack a native getpass() */
87251875Speter
88266735Speter#if !defined(HAVE_TERMIOS_H) && !defined(WIN32)
89251875Speter/*
90251875Speter * MPE lacks getpass() and a way to suppress stdin echo.  So for now, just
91251875Speter * issue the prompt and read the results with echo.  (Ugh).
92251875Speter */
93251875Speter
94251875Speterstatic char *get_password(const char *prompt)
95251875Speter{
96251875Speter    static char password[MAX_STRING_LEN];
97251875Speter
98251875Speter    fputs(prompt, stderr);
99251875Speter    fgets((char *) &password, sizeof(password), stdin);
100251875Speter
101251875Speter    return (char *) &password;
102251875Speter}
103251875Speter
104266735Speter#elif defined(WIN32)
105251875Speter
106251875Speter/*
107251875Speter * Windows lacks getpass().  So we'll re-implement it here.
108251875Speter */
109251875Speter
110251875Speterstatic char *get_password(const char *prompt)
111251875Speter{
112251875Speter/* WCE lacks console. So the getpass is unsuported
113251875Speter * The only way is to use the GUI so the getpass should be implemented
114251875Speter * on per-application basis.
115251875Speter */
116251875Speter#ifdef _WIN32_WCE
117251875Speter    return NULL;
118251875Speter#else
119251875Speter    static char password[128];
120251875Speter    int n = 0;
121251875Speter    int ch;
122251875Speter
123251875Speter    fputs(prompt, stderr);
124251875Speter
125251875Speter    while ((ch = _getch()) != '\r') {
126251875Speter        if (ch == EOF) /* EOF */ {
127251875Speter            fputs("[EOF]\n", stderr);
128251875Speter            return NULL;
129251875Speter        }
130251875Speter        else if (ch == 0 || ch == 0xE0) {
131251875Speter            /* FN Keys (0 or E0) are a sentinal for a FN code */
132251875Speter            ch = (ch << 4) | _getch();
133251875Speter            /* Catch {DELETE}, {<--}, Num{DEL} and Num{<--} */
134251875Speter            if ((ch == 0xE53 || ch == 0xE4B || ch == 0x053 || ch == 0x04b) && n) {
135251875Speter                password[--n] = '\0';
136251875Speter                fputs("\b \b", stderr);
137251875Speter            }
138251875Speter            else {
139251875Speter                fputc('\a', stderr);
140251875Speter            }
141251875Speter        }
142251875Speter        else if ((ch == '\b' || ch == 127) && n) /* BS/DEL */ {
143251875Speter            password[--n] = '\0';
144251875Speter            fputs("\b \b", stderr);
145251875Speter        }
146251875Speter        else if (ch == 3) /* CTRL+C */ {
147251875Speter            /* _getch() bypasses Ctrl+C but not Ctrl+Break detection! */
148251875Speter            fputs("^C\n", stderr);
149251875Speter            exit(-1);
150251875Speter        }
151251875Speter        else if (ch == 26) /* CTRL+Z */ {
152251875Speter            fputs("^Z\n", stderr);
153251875Speter            return NULL;
154251875Speter        }
155251875Speter        else if (ch == 27) /* ESC */ {
156251875Speter            fputc('\n', stderr);
157251875Speter            fputs(prompt, stderr);
158251875Speter            n = 0;
159251875Speter        }
160251875Speter        else if ((n < sizeof(password) - 1) && !apr_iscntrl(ch)) {
161251875Speter            password[n++] = ch;
162251875Speter            fputc('*', stderr);
163251875Speter        }
164251875Speter        else {
165251875Speter            fputc('\a', stderr);
166251875Speter        }
167251875Speter    }
168251875Speter
169251875Speter    fputc('\n', stderr);
170251875Speter    password[n] = '\0';
171251875Speter    return password;
172251875Speter#endif
173251875Speter}
174251875Speter
175266735Speter#elif defined (HAVE_TERMIOS_H)
176266735Speter
177266735Speterstatic char *get_password(const char *prompt)
178266735Speter{
179266735Speter    struct termios attr;
180266735Speter    static char password[MAX_STRING_LEN];
181266735Speter    int n=0;
182266735Speter    fputs(prompt, stderr);
183266735Speter    fflush(stderr);
184266735Speter
185266735Speter    if (tcgetattr(STDIN_FILENO, &attr) != 0)
186266735Speter        return NULL;
187266735Speter    attr.c_lflag &= ~(ECHO);
188266735Speter
189266735Speter    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) != 0)
190266735Speter        return NULL;
191266735Speter    while ((password[n] = getchar()) != '\n') {
192266735Speter        if (n < sizeof(password) - 1 && password[n] >= ' ' && password[n] <= '~') {
193266735Speter            n++;
194266735Speter        } else {
195266735Speter            fprintf(stderr,"\n");
196266735Speter            fputs(prompt, stderr);
197266735Speter            fflush(stderr);
198266735Speter            n = 0;
199266735Speter        }
200266735Speter    }
201266735Speter
202266735Speter    password[n] = '\0';
203266735Speter    printf("\n");
204266735Speter    if (n > (MAX_STRING_LEN - 1)) {
205266735Speter        password[MAX_STRING_LEN - 1] = '\0';
206266735Speter    }
207266735Speter
208266735Speter    attr.c_lflag |= ECHO;
209266735Speter    tcsetattr(STDIN_FILENO, TCSANOW, &attr);
210266735Speter    return (char*) &password;
211266735Speter}
212266735Speter
213251875Speter#endif /* no getchar or _getch */
214251875Speter
215251875Speter#endif /* no getpass or getpassphrase or getpass_r */
216251875Speter
217251875Speter/*
218251875Speter * Use the OS getpass() routine (or our own) to obtain a password from
219251875Speter * the input stream.
220251875Speter *
221251875Speter * Exit values:
222251875Speter *  0: Success
223251875Speter *  5: Partial success; entered text truncated to the size of the
224251875Speter *     destination buffer
225251875Speter *
226251875Speter * Restrictions: Truncation also occurs according to the host system's
227251875Speter * getpass() semantics, or at position 255 if our own version is used,
228251875Speter * but the caller is *not* made aware of it unless their own buffer is
229251875Speter * smaller than our own.
230251875Speter */
231251875Speter
232251875SpeterAPR_DECLARE(apr_status_t) apr_password_get(const char *prompt, char *pwbuf, apr_size_t *bufsiz)
233251875Speter{
234251875Speter    apr_status_t rv = APR_SUCCESS;
235251875Speter#if defined(HAVE_GETPASS_R)
236251875Speter    if (getpass_r(prompt, pwbuf, *bufsiz) == NULL)
237251875Speter        return APR_EINVAL;
238251875Speter#else
239251875Speter#if defined(HAVE_GETPASSPHRASE)
240251875Speter    char *pw_got = getpassphrase(prompt);
241251875Speter#elif defined(HAVE_GETPASS)
242251875Speter    char *pw_got = getpass(prompt);
243251875Speter#else /* use the replacement implementation above */
244251875Speter    char *pw_got = get_password(prompt);
245251875Speter#endif
246251875Speter
247251875Speter    if (!pw_got)
248251875Speter        return APR_EINVAL;
249251875Speter    if (strlen(pw_got) >= *bufsiz) {
250251875Speter        rv = APR_ENAMETOOLONG;
251251875Speter    }
252251875Speter    apr_cpystrn(pwbuf, pw_got, *bufsiz);
253251875Speter    memset(pw_got, 0, strlen(pw_got));
254251875Speter#endif /* HAVE_GETPASS_R */
255251875Speter    return rv;
256251875Speter}
257