fspr_getpass.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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. /* fspr_password_get.c: abstraction to provide for obtaining a password from the
  17. * command line in whatever way the OS supports. In the best case, it's a
  18. * wrapper for the system library's getpass() routine; otherwise, we
  19. * use one we define ourselves.
  20. */
  21. #include "fspr_private.h"
  22. #include "fspr_strings.h"
  23. #include "fspr_lib.h"
  24. #include "fspr_errno.h"
  25. #if APR_HAVE_SYS_TYPES_H
  26. #include <sys/types.h>
  27. #endif
  28. #if APR_HAVE_ERRNO_H
  29. #include <errno.h>
  30. #endif
  31. #if APR_HAVE_UNISTD_H
  32. #include <unistd.h>
  33. #endif
  34. #if APR_HAVE_CONIO_H
  35. #pragma warning(disable: 4032)
  36. #include <conio.h>
  37. #pragma warning(default: 4032)
  38. #endif
  39. #if APR_HAVE_STDLIB_H
  40. #include <stdlib.h>
  41. #endif
  42. #if APR_HAVE_STRING_H
  43. #include <string.h>
  44. #endif
  45. #if APR_HAVE_STRINGS_H
  46. #include <strings.h>
  47. #endif
  48. #if defined(HAVE_TERMIOS_H) && !defined(HAVE_GETPASS)
  49. #include <termios.h>
  50. #endif
  51. #if !APR_CHARSET_EBCDIC
  52. #define LF 10
  53. #define CR 13
  54. #else /* APR_CHARSET_EBCDIC */
  55. #define LF '\n'
  56. #define CR '\r'
  57. #endif /* APR_CHARSET_EBCDIC */
  58. #define MAX_STRING_LEN 256
  59. #define ERR_OVERFLOW 5
  60. #ifndef HAVE_GETPASS
  61. /* MPE, Win32, NetWare and BeOS all lack a native getpass() */
  62. #if !defined(HAVE_TERMIOS_H) && !defined(WIN32) && !defined(NETWARE)
  63. /*
  64. * MPE lacks getpass() and a way to suppress stdin echo. So for now, just
  65. * issue the prompt and read the results with echo. (Ugh).
  66. */
  67. static char *getpass(const char *prompt)
  68. {
  69. static char password[MAX_STRING_LEN];
  70. fputs(prompt, stderr);
  71. fgets((char *) &password, sizeof(password), stdin);
  72. return (char *) &password;
  73. }
  74. #elif defined (HAVE_TERMIOS_H)
  75. #include <stdio.h>
  76. static char *getpass(const char *prompt)
  77. {
  78. struct termios attr;
  79. static char password[MAX_STRING_LEN];
  80. int n=0;
  81. fputs(prompt, stderr);
  82. fflush(stderr);
  83. if (tcgetattr(STDIN_FILENO, &attr) != 0)
  84. return NULL;
  85. attr.c_lflag &= ~(ECHO);
  86. if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) != 0)
  87. return NULL;
  88. while ((password[n] = getchar()) != '\n') {
  89. if (n < sizeof(password) - 1 && password[n] >= ' ' && password[n] <= '~') {
  90. n++;
  91. } else {
  92. fprintf(stderr,"\n");
  93. fputs(prompt, stderr);
  94. fflush(stderr);
  95. n = 0;
  96. }
  97. }
  98. password[n] = '\0';
  99. printf("\n");
  100. if (n > (MAX_STRING_LEN - 1)) {
  101. password[MAX_STRING_LEN - 1] = '\0';
  102. }
  103. attr.c_lflag |= ECHO;
  104. tcsetattr(STDIN_FILENO, TCSANOW, &attr);
  105. return (char*) &password;
  106. }
  107. #else
  108. /*
  109. * Windows lacks getpass(). So we'll re-implement it here.
  110. */
  111. static char *getpass(const char *prompt)
  112. {
  113. /* WCE lacks console. So the getpass is unsuported
  114. * The only way is to use the GUI so the getpass should be implemented
  115. * on per-application basis.
  116. */
  117. #ifdef _WIN32_WCE
  118. return NULL;
  119. #else
  120. static char password[128];
  121. int n = 0;
  122. int ch;
  123. fputs(prompt, stderr);
  124. while ((ch = _getch()) != '\r') {
  125. if (ch == EOF) /* EOF */ {
  126. fputs("[EOF]\n", stderr);
  127. return NULL;
  128. }
  129. else if (ch == 0 || ch == 0xE0) {
  130. /* FN Keys (0 or E0) are a sentinal for a FN code */
  131. ch = (ch << 4) | _getch();
  132. /* Catch {DELETE}, {<--}, Num{DEL} and Num{<--} */
  133. if ((ch == 0xE53 || ch == 0xE4B || ch == 0x053 || ch == 0x04b) && n) {
  134. password[--n] = '\0';
  135. fputs("\b \b", stderr);
  136. }
  137. else {
  138. fputc('\a', stderr);
  139. }
  140. }
  141. else if ((ch == '\b' || ch == 127) && n) /* BS/DEL */ {
  142. password[--n] = '\0';
  143. fputs("\b \b", stderr);
  144. }
  145. else if (ch == 3) /* CTRL+C */ {
  146. /* _getch() bypasses Ctrl+C but not Ctrl+Break detection! */
  147. fputs("^C\n", stderr);
  148. exit(-1);
  149. }
  150. else if (ch == 26) /* CTRL+Z */ {
  151. fputs("^Z\n", stderr);
  152. return NULL;
  153. }
  154. else if (ch == 27) /* ESC */ {
  155. fputc('\n', stderr);
  156. fputs(prompt, stderr);
  157. n = 0;
  158. }
  159. else if ((n < sizeof(password) - 1) && !fspr_iscntrl(ch)) {
  160. password[n++] = ch;
  161. fputc('*', stderr);
  162. }
  163. else {
  164. fputc('\a', stderr);
  165. }
  166. }
  167. fputc('\n', stderr);
  168. password[n] = '\0';
  169. return password;
  170. #endif
  171. }
  172. #endif /* no getchar or _getch */
  173. #endif /* no getpass */
  174. /*
  175. * Use the OS getpass() routine (or our own) to obtain a password from
  176. * the input stream.
  177. *
  178. * Exit values:
  179. * 0: Success
  180. * 5: Partial success; entered text truncated to the size of the
  181. * destination buffer
  182. *
  183. * Restrictions: Truncation also occurs according to the host system's
  184. * getpass() semantics, or at position 255 if our own version is used,
  185. * but the caller is *not* made aware of it unless their own buffer is
  186. * smaller than our own.
  187. */
  188. APR_DECLARE(fspr_status_t) fspr_password_get(const char *prompt, char *pwbuf, fspr_size_t *bufsiz)
  189. {
  190. #ifdef HAVE_GETPASSPHRASE
  191. char *pw_got = getpassphrase(prompt);
  192. #else
  193. char *pw_got = getpass(prompt);
  194. #endif
  195. fspr_status_t rv = APR_SUCCESS;
  196. if (!pw_got)
  197. return APR_EINVAL;
  198. if (strlen(pw_got) >= *bufsiz) {
  199. rv = APR_ENAMETOOLONG;
  200. }
  201. fspr_cpystrn(pwbuf, pw_got, *bufsiz);
  202. memset(pw_got, 0, strlen(pw_got));
  203. return rv;
  204. }