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