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
54251875Speter
55251875Speter/* Disable getpass() support when PASS_MAX is defined and is "small",
56251875Speter * for an arbitrary definition of "small".
57251875Speter * HP-UX truncates passwords (PR49496) so we disable getpass() for
58251875Speter * this platform too.
59251875Speter */
60251875Speter#if defined(HAVE_GETPASS) && \
61251875Speter    (defined(PASS_MAX) && PASS_MAX < 32) || defined(__hpux) || defined(__hpux__)
62251875Speter#undef HAVE_GETPASS
63251875Speter#endif
64251875Speter
65251875Speter#if defined(HAVE_TERMIOS_H) && !defined(HAVE_GETPASS)
66251875Speter#include <termios.h>
67251875Speter#endif
68251875Speter
69251875Speter#if !APR_CHARSET_EBCDIC
70251875Speter#define LF 10
71251875Speter#define CR 13
72251875Speter#else /* APR_CHARSET_EBCDIC */
73251875Speter#define LF '\n'
74251875Speter#define CR '\r'
75251875Speter#endif /* APR_CHARSET_EBCDIC */
76251875Speter
77251875Speter#define MAX_STRING_LEN 256
78251875Speter
79251875Speter#define ERR_OVERFLOW 5
80251875Speter
81251875Speter#if !defined(HAVE_GETPASS) && !defined(HAVE_GETPASSPHRASE) && !defined(HAVE_GETPASS_R)
82251875Speter
83251875Speter/* MPE, Win32, NetWare and BeOS all lack a native getpass() */
84251875Speter
85251875Speter#if !defined(HAVE_TERMIOS_H) && !defined(WIN32) && !defined(NETWARE)
86251875Speter/*
87251875Speter * MPE lacks getpass() and a way to suppress stdin echo.  So for now, just
88251875Speter * issue the prompt and read the results with echo.  (Ugh).
89251875Speter */
90251875Speter
91251875Speterstatic char *get_password(const char *prompt)
92251875Speter{
93251875Speter    static char password[MAX_STRING_LEN];
94251875Speter
95251875Speter    fputs(prompt, stderr);
96251875Speter    fgets((char *) &password, sizeof(password), stdin);
97251875Speter
98251875Speter    return (char *) &password;
99251875Speter}
100251875Speter
101251875Speter#elif defined (HAVE_TERMIOS_H)
102251875Speter#include <stdio.h>
103251875Speter
104251875Speterstatic char *get_password(const char *prompt)
105251875Speter{
106251875Speter    struct termios attr;
107251875Speter    static char password[MAX_STRING_LEN];
108251875Speter    int n=0;
109251875Speter    fputs(prompt, stderr);
110251875Speter    fflush(stderr);
111251875Speter
112251875Speter    if (tcgetattr(STDIN_FILENO, &attr) != 0)
113251875Speter        return NULL;
114251875Speter    attr.c_lflag &= ~(ECHO);
115251875Speter
116251875Speter    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) != 0)
117251875Speter        return NULL;
118251875Speter    while ((password[n] = getchar()) != '\n') {
119251875Speter        if (n < sizeof(password) - 1 && password[n] >= ' ' && password[n] <= '~') {
120251875Speter            n++;
121251875Speter        } else {
122251875Speter            fprintf(stderr,"\n");
123251875Speter            fputs(prompt, stderr);
124251875Speter            fflush(stderr);
125251875Speter            n = 0;
126251875Speter        }
127251875Speter    }
128251875Speter
129251875Speter    password[n] = '\0';
130251875Speter    printf("\n");
131251875Speter    if (n > (MAX_STRING_LEN - 1)) {
132251875Speter        password[MAX_STRING_LEN - 1] = '\0';
133251875Speter    }
134251875Speter
135251875Speter    attr.c_lflag |= ECHO;
136251875Speter    tcsetattr(STDIN_FILENO, TCSANOW, &attr);
137251875Speter    return (char*) &password;
138251875Speter}
139251875Speter
140251875Speter#else
141251875Speter
142251875Speter/*
143251875Speter * Windows lacks getpass().  So we'll re-implement it here.
144251875Speter */
145251875Speter
146251875Speterstatic char *get_password(const char *prompt)
147251875Speter{
148251875Speter/* WCE lacks console. So the getpass is unsuported
149251875Speter * The only way is to use the GUI so the getpass should be implemented
150251875Speter * on per-application basis.
151251875Speter */
152251875Speter#ifdef _WIN32_WCE
153251875Speter    return NULL;
154251875Speter#else
155251875Speter    static char password[128];
156251875Speter    int n = 0;
157251875Speter    int ch;
158251875Speter
159251875Speter    fputs(prompt, stderr);
160251875Speter
161251875Speter    while ((ch = _getch()) != '\r') {
162251875Speter        if (ch == EOF) /* EOF */ {
163251875Speter            fputs("[EOF]\n", stderr);
164251875Speter            return NULL;
165251875Speter        }
166251875Speter        else if (ch == 0 || ch == 0xE0) {
167251875Speter            /* FN Keys (0 or E0) are a sentinal for a FN code */
168251875Speter            ch = (ch << 4) | _getch();
169251875Speter            /* Catch {DELETE}, {<--}, Num{DEL} and Num{<--} */
170251875Speter            if ((ch == 0xE53 || ch == 0xE4B || ch == 0x053 || ch == 0x04b) && n) {
171251875Speter                password[--n] = '\0';
172251875Speter                fputs("\b \b", stderr);
173251875Speter            }
174251875Speter            else {
175251875Speter                fputc('\a', stderr);
176251875Speter            }
177251875Speter        }
178251875Speter        else if ((ch == '\b' || ch == 127) && n) /* BS/DEL */ {
179251875Speter            password[--n] = '\0';
180251875Speter            fputs("\b \b", stderr);
181251875Speter        }
182251875Speter        else if (ch == 3) /* CTRL+C */ {
183251875Speter            /* _getch() bypasses Ctrl+C but not Ctrl+Break detection! */
184251875Speter            fputs("^C\n", stderr);
185251875Speter            exit(-1);
186251875Speter        }
187251875Speter        else if (ch == 26) /* CTRL+Z */ {
188251875Speter            fputs("^Z\n", stderr);
189251875Speter            return NULL;
190251875Speter        }
191251875Speter        else if (ch == 27) /* ESC */ {
192251875Speter            fputc('\n', stderr);
193251875Speter            fputs(prompt, stderr);
194251875Speter            n = 0;
195251875Speter        }
196251875Speter        else if ((n < sizeof(password) - 1) && !apr_iscntrl(ch)) {
197251875Speter            password[n++] = ch;
198251875Speter            fputc('*', stderr);
199251875Speter        }
200251875Speter        else {
201251875Speter            fputc('\a', stderr);
202251875Speter        }
203251875Speter    }
204251875Speter
205251875Speter    fputc('\n', stderr);
206251875Speter    password[n] = '\0';
207251875Speter    return password;
208251875Speter#endif
209251875Speter}
210251875Speter
211251875Speter#endif /* no getchar or _getch */
212251875Speter
213251875Speter#endif /* no getpass or getpassphrase or getpass_r */
214251875Speter
215251875Speter/*
216251875Speter * Use the OS getpass() routine (or our own) to obtain a password from
217251875Speter * the input stream.
218251875Speter *
219251875Speter * Exit values:
220251875Speter *  0: Success
221251875Speter *  5: Partial success; entered text truncated to the size of the
222251875Speter *     destination buffer
223251875Speter *
224251875Speter * Restrictions: Truncation also occurs according to the host system's
225251875Speter * getpass() semantics, or at position 255 if our own version is used,
226251875Speter * but the caller is *not* made aware of it unless their own buffer is
227251875Speter * smaller than our own.
228251875Speter */
229251875Speter
230251875SpeterAPR_DECLARE(apr_status_t) apr_password_get(const char *prompt, char *pwbuf, apr_size_t *bufsiz)
231251875Speter{
232251875Speter    apr_status_t rv = APR_SUCCESS;
233251875Speter#if defined(HAVE_GETPASS_R)
234251875Speter    if (getpass_r(prompt, pwbuf, *bufsiz) == NULL)
235251875Speter        return APR_EINVAL;
236251875Speter#else
237251875Speter#if defined(HAVE_GETPASSPHRASE)
238251875Speter    char *pw_got = getpassphrase(prompt);
239251875Speter#elif defined(HAVE_GETPASS)
240251875Speter    char *pw_got = getpass(prompt);
241251875Speter#else /* use the replacement implementation above */
242251875Speter    char *pw_got = get_password(prompt);
243251875Speter#endif
244251875Speter
245251875Speter    if (!pw_got)
246251875Speter        return APR_EINVAL;
247251875Speter    if (strlen(pw_got) >= *bufsiz) {
248251875Speter        rv = APR_ENAMETOOLONG;
249251875Speter    }
250251875Speter    apr_cpystrn(pwbuf, pw_got, *bufsiz);
251251875Speter    memset(pw_got, 0, strlen(pw_got));
252251875Speter#endif /* HAVE_GETPASS_R */
253251875Speter    return rv;
254251875Speter}
255