1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24#include "tool_setup.h" 25 26#if defined(__AMIGA__) && !defined(__amigaos4__) 27# undef HAVE_TERMIOS_H 28#endif 29 30#ifndef HAVE_GETPASS_R 31/* this file is only for systems without getpass_r() */ 32 33#ifdef HAVE_FCNTL_H 34# include <fcntl.h> 35#endif 36 37#ifdef HAVE_TERMIOS_H 38# include <termios.h> 39#elif defined(HAVE_TERMIO_H) 40# include <termio.h> 41#endif 42 43#ifdef __VMS 44# include descrip 45# include starlet 46# include iodef 47#endif 48 49#ifdef _WIN32 50# include <conio.h> 51#endif 52 53#ifdef HAVE_UNISTD_H 54#include <unistd.h> 55#endif 56#include "tool_getpass.h" 57 58#include "memdebug.h" /* keep this as LAST include */ 59 60#ifdef __VMS 61/* VMS implementation */ 62char *getpass_r(const char *prompt, char *buffer, size_t buflen) 63{ 64 long sts; 65 short chan; 66 67 /* MSK, 23-JAN-2004, iosbdef.h wasn't in VAX V7.2 or CC 6.4 */ 68 /* distribution so I created this. May revert back later to */ 69 /* struct _iosb iosb; */ 70 struct _iosb 71 { 72 short int iosb$w_status; /* status */ 73 short int iosb$w_bcnt; /* byte count */ 74 int unused; /* unused */ 75 } iosb; 76 77 $DESCRIPTOR(ttdesc, "TT"); 78 79 buffer[0] = '\0'; 80 sts = sys$assign(&ttdesc, &chan, 0, 0); 81 if(sts & 1) { 82 sts = sys$qiow(0, chan, 83 IO$_READPROMPT | IO$M_NOECHO, 84 &iosb, 0, 0, buffer, buflen, 0, 0, 85 prompt, strlen(prompt)); 86 87 if((sts & 1) && (iosb.iosb$w_status & 1)) 88 buffer[iosb.iosb$w_bcnt] = '\0'; 89 90 sys$dassgn(chan); 91 } 92 return buffer; /* we always return success */ 93} 94#define DONE 95#endif /* __VMS */ 96 97#if defined(_WIN32) 98 99char *getpass_r(const char *prompt, char *buffer, size_t buflen) 100{ 101 size_t i; 102 fputs(prompt, tool_stderr); 103 104 for(i = 0; i < buflen; i++) { 105 buffer[i] = (char)getch(); 106 if(buffer[i] == '\r' || buffer[i] == '\n') { 107 buffer[i] = '\0'; 108 break; 109 } 110 else 111 if(buffer[i] == '\b') 112 /* remove this letter and if this is not the first key, remove the 113 previous one as well */ 114 i = i - (i >= 1 ? 2 : 1); 115 } 116 /* since echo is disabled, print a newline */ 117 fputs("\n", tool_stderr); 118 /* if user didn't hit ENTER, terminate buffer */ 119 if(i == buflen) 120 buffer[buflen-1] = '\0'; 121 122 return buffer; /* we always return success */ 123} 124#define DONE 125#endif /* _WIN32 */ 126 127#ifndef DONE /* not previously provided */ 128 129#ifdef HAVE_TERMIOS_H 130# define struct_term struct termios 131#elif defined(HAVE_TERMIO_H) 132# define struct_term struct termio 133#else 134# undef struct_term 135#endif 136 137static bool ttyecho(bool enable, int fd) 138{ 139#ifdef struct_term 140 static struct_term withecho; 141 static struct_term noecho; 142#endif 143 if(!enable) { 144 /* disable echo by extracting the current 'withecho' mode and remove the 145 ECHO bit and set back the struct */ 146#ifdef HAVE_TERMIOS_H 147 tcgetattr(fd, &withecho); 148 noecho = withecho; 149 noecho.c_lflag &= ~ECHO; 150 tcsetattr(fd, TCSANOW, &noecho); 151#elif defined(HAVE_TERMIO_H) 152 ioctl(fd, TCGETA, &withecho); 153 noecho = withecho; 154 noecho.c_lflag &= ~ECHO; 155 ioctl(fd, TCSETA, &noecho); 156#else 157 /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */ 158 (void)fd; 159 return FALSE; /* not disabled */ 160#endif 161 return TRUE; /* disabled */ 162 } 163 /* re-enable echo, assumes we disabled it before (and set the structs we 164 now use to reset the terminal status) */ 165#ifdef HAVE_TERMIOS_H 166 tcsetattr(fd, TCSAFLUSH, &withecho); 167#elif defined(HAVE_TERMIO_H) 168 ioctl(fd, TCSETA, &withecho); 169#else 170 return FALSE; /* not enabled */ 171#endif 172 return TRUE; /* enabled */ 173} 174 175char *getpass_r(const char *prompt, /* prompt to display */ 176 char *password, /* buffer to store password in */ 177 size_t buflen) /* size of buffer to store password in */ 178{ 179 ssize_t nread; 180 bool disabled; 181 int fd = open("/dev/tty", O_RDONLY); 182 if(-1 == fd) 183 fd = STDIN_FILENO; /* use stdin if the tty couldn't be used */ 184 185 disabled = ttyecho(FALSE, fd); /* disable terminal echo */ 186 187 fputs(prompt, tool_stderr); 188 nread = read(fd, password, buflen); 189 if(nread > 0) 190 password[--nread] = '\0'; /* null-terminate where enter is stored */ 191 else 192 password[0] = '\0'; /* got nothing */ 193 194 if(disabled) { 195 /* if echo actually was disabled, add a newline */ 196 fputs("\n", tool_stderr); 197 (void)ttyecho(TRUE, fd); /* enable echo */ 198 } 199 200 if(STDIN_FILENO != fd) 201 close(fd); 202 203 return password; /* return pointer to buffer */ 204} 205 206#endif /* DONE */ 207#endif /* HAVE_GETPASS_R */ 208