Search code examples
clinuxgccterminalmasking

Hide password input on terminal


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

#include <conio.h>   
int main()
{
    char c,password[10];
    int i;
    while( (c=getch())!= '\n');{
        password[i] = c;
        printf("*");
        i++;
    }
    return 1;
}

but the problem is that GCC does not include conio.h file so, getch() is useless for me. Does anyone have a solution?


Solution

  • In the Linux world, masking isn't usually done with asterisks, normally echoing is just turned off and the terminal displays blanks E.g. if you use su or log into a virtual terminal etc.

    There is a library function to handle getting passwords, it won't mask the password with asterisks but will disable echoing of the password to terminal. I pulled this out of a linux book I have. I believe its part of the posix standard

    #include <unistd.h>
    char *getpass(const char *prompt);
    
    /*Returns pointer to statically allocated input password string
    on success, or NULL on error*/
    

    The getpass() function first disables echoing and all processing of terminal special characters (such as the interrupt character, normally Control-C).

    It then prints the string pointed to by prompt, and reads a line of input, returning the null-terminated input string with the trailing newline stripped, as its function result.

    A google search for getpass() has a reference to the GNU implementation (should be in most linux distros) and some sample code for implementing your own if need be

    http://www.gnu.org/s/hello/manual/libc/getpass.html

    Their example for rolling your own:

    #include <termios.h>
    #include <stdio.h>
    
    ssize_t
    my_getpass (char **lineptr, size_t *n, FILE *stream)
    {
        struct termios old, new;
        int nread;
    
        /* Turn echoing off and fail if we can't. */
        if (tcgetattr (fileno (stream), &old) != 0)
            return -1;
        new = old;
        new.c_lflag &= ~ECHO;
        if (tcsetattr (fileno (stream), TCSAFLUSH, &new) != 0)
            return -1;
    
        /* Read the password. */
        nread = getline (lineptr, n, stream);
    
        /* Restore terminal. */
        (void) tcsetattr (fileno (stream), TCSAFLUSH, &old);
    
        return nread;
    }
    

    If need be you could use this as the basis as modify it to display asterisks.