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