Home | History | Annotate | Download | only in src
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel (at) 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.haxx.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  ***************************************************************************/
     22 #include "tool_setup.h"
     23 
     24 #if defined(__AMIGA__) && !defined(__amigaos4__)
     25 #  undef HAVE_TERMIOS_H
     26 #endif
     27 
     28 #ifndef HAVE_GETPASS_R
     29 /* this file is only for systems without getpass_r() */
     30 
     31 #ifdef HAVE_FCNTL_H
     32 #  include <fcntl.h>
     33 #endif
     34 
     35 #ifdef HAVE_TERMIOS_H
     36 #  include <termios.h>
     37 #elif defined(HAVE_TERMIO_H)
     38 #  include <termio.h>
     39 #endif
     40 
     41 #ifdef __VMS
     42 #  include descrip
     43 #  include starlet
     44 #  include iodef
     45 #endif
     46 
     47 #ifdef WIN32
     48 #  include <conio.h>
     49 #endif
     50 
     51 #ifdef NETWARE
     52 #  ifdef __NOVELL_LIBC__
     53 #    include <screen.h>
     54 #  else
     55 #    include <nwconio.h>
     56 #  endif
     57 #endif
     58 
     59 #ifdef HAVE_UNISTD_H
     60 #include <unistd.h>
     61 #endif
     62 #include "tool_getpass.h"
     63 
     64 #include "memdebug.h" /* keep this as LAST include */
     65 
     66 #ifdef __VMS
     67 /* VMS implementation */
     68 char *getpass_r(const char *prompt, char *buffer, size_t buflen)
     69 {
     70   long sts;
     71   short chan;
     72 
     73   /* MSK, 23-JAN-2004, iosbdef.h wasn't in VAX V7.2 or CC 6.4  */
     74   /* distribution so I created this.  May revert back later to */
     75   /* struct _iosb iosb;                                        */
     76   struct _iosb
     77      {
     78      short int iosb$w_status; /* status     */
     79      short int iosb$w_bcnt;   /* byte count */
     80      int       unused;        /* unused     */
     81      } iosb;
     82 
     83   $DESCRIPTOR(ttdesc, "TT");
     84 
     85   buffer[0] = '\0';
     86   sts = sys$assign(&ttdesc, &chan, 0, 0);
     87   if(sts & 1) {
     88     sts = sys$qiow(0, chan,
     89                    IO$_READPROMPT | IO$M_NOECHO,
     90                    &iosb, 0, 0, buffer, buflen, 0, 0,
     91                    prompt, strlen(prompt));
     92 
     93     if((sts & 1) && (iosb.iosb$w_status & 1))
     94       buffer[iosb.iosb$w_bcnt] = '\0';
     95 
     96     sts = sys$dassgn(chan);
     97   }
     98   return buffer; /* we always return success */
     99 }
    100 #define DONE
    101 #endif /* __VMS */
    102 
    103 #ifdef __SYMBIAN32__
    104 #  define getch() getchar()
    105 #endif
    106 
    107 #if defined(WIN32) || defined(__SYMBIAN32__)
    108 
    109 char *getpass_r(const char *prompt, char *buffer, size_t buflen)
    110 {
    111   size_t i;
    112   fputs(prompt, stderr);
    113 
    114   for(i = 0; i < buflen; i++) {
    115     buffer[i] = (char)getch();
    116     if(buffer[i] == '\r' || buffer[i] == '\n') {
    117       buffer[i] = '\0';
    118       break;
    119     }
    120     else
    121       if(buffer[i] == '\b')
    122         /* remove this letter and if this is not the first key, remove the
    123            previous one as well */
    124         i = i - (i >= 1 ? 2 : 1);
    125   }
    126 #ifndef __SYMBIAN32__
    127   /* since echo is disabled, print a newline */
    128   fputs("\n", stderr);
    129 #endif
    130   /* if user didn't hit ENTER, terminate buffer */
    131   if(i == buflen)
    132     buffer[buflen-1] = '\0';
    133 
    134   return buffer; /* we always return success */
    135 }
    136 #define DONE
    137 #endif /* WIN32 || __SYMBIAN32__ */
    138 
    139 #ifdef NETWARE
    140 /* NetWare implementation */
    141 #ifdef __NOVELL_LIBC__
    142 char *getpass_r(const char *prompt, char *buffer, size_t buflen)
    143 {
    144   return getpassword(prompt, buffer, buflen);
    145 }
    146 #else
    147 char *getpass_r(const char *prompt, char *buffer, size_t buflen)
    148 {
    149   size_t i = 0;
    150 
    151   printf("%s", prompt);
    152   do {
    153     buffer[i++] = getch();
    154     if(buffer[i-1] == '\b') {
    155       /* remove this letter and if this is not the first key,
    156          remove the previous one as well */
    157       if(i > 1) {
    158         printf("\b \b");
    159         i = i - 2;
    160       }
    161       else {
    162         RingTheBell();
    163         i = i - 1;
    164       }
    165     }
    166     else if(buffer[i-1] != 13)
    167       putchar('*');
    168 
    169   } while((buffer[i-1] != 13) && (i < buflen));
    170   buffer[i-1] = '\0';
    171   printf("\r\n");
    172   return buffer;
    173 }
    174 #endif /* __NOVELL_LIBC__ */
    175 #define DONE
    176 #endif /* NETWARE */
    177 
    178 #ifndef DONE /* not previously provided */
    179 
    180 #ifdef HAVE_TERMIOS_H
    181 #  define struct_term  struct termios
    182 #elif defined(HAVE_TERMIO_H)
    183 #  define struct_term  struct termio
    184 #else
    185 #  undef  struct_term
    186 #endif
    187 
    188 static bool ttyecho(bool enable, int fd)
    189 {
    190 #ifdef struct_term
    191   static struct_term withecho;
    192   static struct_term noecho;
    193 #endif
    194   if(!enable) {
    195     /* disable echo by extracting the current 'withecho' mode and remove the
    196        ECHO bit and set back the struct */
    197 #ifdef HAVE_TERMIOS_H
    198     tcgetattr(fd, &withecho);
    199     noecho = withecho;
    200     noecho.c_lflag &= ~ECHO;
    201     tcsetattr(fd, TCSANOW, &noecho);
    202 #elif defined(HAVE_TERMIO_H)
    203     ioctl(fd, TCGETA, &withecho);
    204     noecho = withecho;
    205     noecho.c_lflag &= ~ECHO;
    206     ioctl(fd, TCSETA, &noecho);
    207 #else
    208     /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */
    209     (void)fd;
    210     return FALSE; /* not disabled */
    211 #endif
    212     return TRUE; /* disabled */
    213   }
    214   /* re-enable echo, assumes we disabled it before (and set the structs we
    215      now use to reset the terminal status) */
    216 #ifdef HAVE_TERMIOS_H
    217   tcsetattr(fd, TCSAFLUSH, &withecho);
    218 #elif defined(HAVE_TERMIO_H)
    219   ioctl(fd, TCSETA, &withecho);
    220 #else
    221   return FALSE; /* not enabled */
    222 #endif
    223   return TRUE; /* enabled */
    224 }
    225 
    226 char *getpass_r(const char *prompt, /* prompt to display */
    227                 char *password,     /* buffer to store password in */
    228                 size_t buflen)      /* size of buffer to store password in */
    229 {
    230   ssize_t nread;
    231   bool disabled;
    232   int fd = open("/dev/tty", O_RDONLY);
    233   if(-1 == fd)
    234     fd = STDIN_FILENO; /* use stdin if the tty couldn't be used */
    235 
    236   disabled = ttyecho(FALSE, fd); /* disable terminal echo */
    237 
    238   fputs(prompt, stderr);
    239   nread = read(fd, password, buflen);
    240   if(nread > 0)
    241     password[--nread] = '\0'; /* zero terminate where enter is stored */
    242   else
    243     password[0] = '\0'; /* got nothing */
    244 
    245   if(disabled) {
    246     /* if echo actually was disabled, add a newline */
    247     fputs("\n", stderr);
    248     (void)ttyecho(TRUE, fd); /* enable echo */
    249   }
    250 
    251   if(STDIN_FILENO != fd)
    252     close(fd);
    253 
    254   return password; /* return pointer to buffer */
    255 }
    256 
    257 #endif /* DONE */
    258 #endif /* HAVE_GETPASS_R */
    259