Hide password input on terminal

后端 未结 15 1372
清酒与你
清酒与你 2020-11-22 09:55

I want to mask my password while writing it with *. I use Linux GCC for this code. I know one solution is to use getch() function like this

相关标签:
15条回答
  • 2020-11-22 10:45

    You might use ncurses.h if it is not necessary to be portable onto Windows for that, but here is some kind of a more "portable" version:

    If it is not necessery to be portable ill point you to a ncurses solution

    portablegetch.h

    /*portablegetch.h*/
    #ifndef PGETCH
    #define PGETCH
    #ifdef __unix__
    #include <termios.h>
    #include <unistd.h>
    
    static struct termios n_term;
    static struct termios o_term;
    
    static int
    cbreak(int fd) 
    {
       if((tcgetattr(fd, &o_term)) == -1)
          return -1;
       n_term = o_term;
       n_term.c_lflag = n_term.c_lflag & ~(ECHO|ICANON);
       n_term.c_cc[VMIN] = 1;
       n_term.c_cc[VTIME]= 0;
       if((tcsetattr(fd, TCSAFLUSH, &n_term)) == -1)
          return -1;
       return 1;
    }
    
    int 
    getch() 
    {
       int cinput;
    
       if(cbreak(STDIN_FILENO) == -1) {
          fprintf(stderr, "cbreak failure, exiting \n");
          exit(EXIT_FAILURE);
       }
       cinput = getchar();
       tcsetattr(STDIN_FILENO, TCSANOW, &o_term);
    
       return cinput;
    }
    
    #elif _MSC_VER  || __WIN32__ || __MS_DOS__
      #include <conio.h>
    #endif
    #endif
    

    And the c-file

    whatever.c

    #include <stdio.h>
    #include <stdlib.h>
    #include "portablegetch.h"
    
    int 
    main(int argc, char **argv) 
    {
      int input;
    
      printf("Please Enter your Password:\t");
    
      while(( input=getch() ) != '\n')
            printf("*");
      printf("\n");
    
      return EXIT_SUCCESS;
    }
    

    That should fit to your problem.

    Hope that helps.

    0 讨论(0)
  • 2020-11-22 10:46

    Without getch to rely on and avoiding the obsolete getpass, the recommended approach is to disable terminal ECHO through termios use. After a few searches to find a canned flexible password routine, I was surprised that very few for stand-alone use with C. Rather than simply recoding getch with termios c_lflag options, slightly more generalized approach takes just a few additions. Beyond replacing getch any routine should enforce a specified maximum length to prevent overflow, truncate if the user attempt to enter beyond the maximum, and warn if truncation occurs in some manner.

    Below, the additions will allow reading from any FILE * input stream, limiting the length to a specified length, provide minimal editing (backspace) ability when taking input, allow the character mask to be specified or disabled completely, and finally return the length of the password entered. A warning was added when the password entered was truncated to the maximum or specified length.

    Hopefully it will prove useful to others with this question looking for a similar solution:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <termios.h>
    
    #define MAXPW 32
    
    /* read a string from fp into pw masking keypress with mask char.
    getpasswd will read upto sz - 1 chars into pw, null-terminating
    the resulting string. On success, the number of characters in
    pw are returned, -1 otherwise.
    */
    ssize_t getpasswd (char **pw, size_t sz, int mask, FILE *fp)
    {
        if (!pw || !sz || !fp) return -1;       /* validate input   */
    #ifdef MAXPW
        if (sz > MAXPW) sz = MAXPW;
    #endif
    
        if (*pw == NULL) {              /* reallocate if no address */
            void *tmp = realloc (*pw, sz * sizeof **pw);
            if (!tmp)
                return -1;
            memset (tmp, 0, sz);    /* initialize memory to 0   */
            *pw =  (char*) tmp;
        }
    
        size_t idx = 0;         /* index, number of chars in read   */
        int c = 0;
    
        struct termios old_kbd_mode;    /* orig keyboard settings   */
        struct termios new_kbd_mode;
    
        if (tcgetattr (0, &old_kbd_mode)) { /* save orig settings   */
            fprintf (stderr, "%s() error: tcgetattr failed.\n", __func__);
            return -1;
        }   /* copy old to new */
        memcpy (&new_kbd_mode, &old_kbd_mode, sizeof(struct termios));
    
        new_kbd_mode.c_lflag &= ~(ICANON | ECHO);  /* new kbd flags */
        new_kbd_mode.c_cc[VTIME] = 0;
        new_kbd_mode.c_cc[VMIN] = 1;
        if (tcsetattr (0, TCSANOW, &new_kbd_mode)) {
            fprintf (stderr, "%s() error: tcsetattr failed.\n", __func__);
            return -1;
        }
    
        /* read chars from fp, mask if valid char specified */
        while (((c = fgetc (fp)) != '\n' && c != EOF && idx < sz - 1) ||
                (idx == sz - 1 && c == 127))
        {
            if (c != 127) {
                if (31 < mask && mask < 127)    /* valid ascii char */
                    fputc (mask, stdout);
                (*pw)[idx++] = c;
            }
            else if (idx > 0) {         /* handle backspace (del)   */
                if (31 < mask && mask < 127) {
                    fputc (0x8, stdout);
                    fputc (' ', stdout);
                    fputc (0x8, stdout);
                }
                (*pw)[--idx] = 0;
            }
        }
        (*pw)[idx] = 0; /* null-terminate   */
    
        /* reset original keyboard  */
        if (tcsetattr (0, TCSANOW, &old_kbd_mode)) {
            fprintf (stderr, "%s() error: tcsetattr failed.\n", __func__);
            return -1;
        }
    
        if (idx == sz - 1 && c != '\n') /* warn if pw truncated */
            fprintf (stderr, " (%s() warning: truncated at %zu chars.)\n",
                    __func__, sz - 1);
    
        return idx; /* number of chars in passwd    */
    }
    

    A simple program showing the use would be as follows. If using a static array of character for holding the password, just insure a pointer is passed to the function.

    int main (void ) {
    
        char pw[MAXPW] = {0};
        char *p = pw;
        FILE *fp = stdin;
        ssize_t nchr = 0;
    
        printf ( "\n Enter password: ");
        nchr = getpasswd (&p, MAXPW, '*', fp);
        printf ("\n you entered   : %s  (%zu chars)\n", p, nchr);
    
        printf ( "\n Enter password: ");
        nchr = getpasswd (&p, MAXPW, 0, fp);
        printf ("\n you entered   : %s  (%zu chars)\n\n", p, nchr);
    
        return 0;
    }
    

    Example Output

    $ ./bin/getpasswd2
    
     Enter password: ******
     you entered   : 123456  (6 chars)
    
     Enter password:
     you entered   : abcdef  (6 chars)
    
    0 讨论(0)
  • 2020-11-22 10:47

    You can create your own getch() function on Linux in this manner.

    int getch() {
        struct termios oldtc, newtc;
        int ch;
        tcgetattr(STDIN_FILENO, &oldtc);
        newtc = oldtc;
        newtc.c_lflag &= ~(ICANON | ECHO);
        tcsetattr(STDIN_FILENO, TCSANOW, &newtc);
        ch=getchar();
        tcsetattr(STDIN_FILENO, TCSANOW, &oldtc);
        return ch;
    }
    

    Demo code:

    int main(int argc, char **argv) {
        int ch;
        printf("Press x to exit.\n\n");
        for (;;) {
            ch = getch();
            printf("ch = %c (%d)\n", ch, ch);
            if(ch == 'x')
                  break;
        }
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题