Password Prompt in The C Programming Language with termios

Password or passphrase must be hidden, i.e., password input in your command line programs must be securely requested. The most common way to ask password in command line programs is to disable echo-back of the input characters. This page provides a sample implementation of this function in the C programming language with termios. Note that termios is general terminal line discipline.

Search from the Internet:
Custom Search

Password Prompt with termios

Overview

Common password prompts, such as SSH password login and sudo password prompts, disable the echo-back of command line standard input to prevent terminal applications to display or cache on the screen. In shell scripts, stty is widely used to disable or enable the echo-back. For example, use

$ stty -echo

to disable echo-back and

$ stty echo

to enable it. Here we note that

$ stty sane

restores the default setting in case you face troubles with your terminal.

We provide information to produce the same behavior in C programming language with termios without that shell command.

The sample implementation

The following code is a sample implementation of password prompt. This program requests you password and compare the input password with the defined password "scyphus". If you enter "scyphus" and LF (return key), you would get "Got correct password." Otherwise, you would get "Got wrong password." Allowed password input length (i.e., buffer size) is 127 bytes (characters) excluding '\0' in this sample code, and neglects characters over length of 128.

You can download this source code from password_prompt.c.

/*_
 * Copyright 2011 Scyphus Solutions Co. Ltd.  All rights reserved.
 *
 * Authors:
 *      Hirochika Asai
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <errno.h>
#include <ctype.h>
#include <signal.h>

/*
 * Terminal configuration for restore
 */

struct termios saved_term;

/*
 * Restore terminal configuration
 */

void
restore_terminal(void)
{
    if( -1 == tcsetattr(fileno(stdin), TCSANOW, &saved_term) ){
        perror("tcsetattr(): Cannot revert terminal setting");
        exit(EXIT_FAILURE);
    }
}

/*
 * Signal handler for SIGINT
 */

void
sigint_handler(int sig)
{
    if ( SIGINT == sig ) {
        /* Restore */
        restore_terminal();
    }
    exit(EXIT_SUCCESS);
}

int
main(int argcconst char *const argv[], const char *const envp[])
{
    int i;
    int c;
    char passwd[128];
    struct termios tmp_term;
    struct sigaction sa_sigint;

    /* Save current terminal configuration */
    if ( -1 == tcgetattr(fileno(stdin), &saved_term) ) {
        perror("tcgetattr(): Cannot retrieve the current terminal setting");
        exit(EXIT_FAILURE);
    }
    tmp_term = saved_term;

    /* Set signal for SIGINT */
    memset(&sa_sigint0sizeof(struct sigaction));
    sa_sigint.sa_handler = sigint_handler;
    sa_sigint.sa_flags = 0;
    if ( sigaction(SIGINT, &sa_sigintNULL) < 0 ) {
        perror("sigaction()");
        exit(EXIT_FAILURE);
    }

    /* Set terminal options for password prompt */
    tmp_term.c_lflag &= ~ECHO;  /* Disable echo-back */
    if ( -1 == tcsetattr(fileno(stdin), TCSANOW, &tmp_term) ) {
        perror("tcsetattr(): Cannot update terminal setting");
        exit(EXIT_FAILURE);
    }

    /* Prompt */
    printf("Password: ");
    i = 0;
    do {
        /* Get character from stdin */
        c = fgetc(stdin);
        if ( isascii(c) && '\r' != c && '\n' != c ) {
            if ( i < sizeof(passwd) - 1 ) {
                passwd[i] = c;
                i++;
            }
        }
    } while ( c != '\n' );
    passwd[i] = '\0';
    printf("\n");

    /* Here we compare your input password with string "scyphus".  Please
       change add your original code here as you wish. */

    if ( 0 == strcmp("scyphus"passwd) ) {
        printf("Got correct password.\n");
    } else {
        printf("Got wrong password.\n");
    }

    /* Restore terminal configuration */
    restore_terminal();

    return 0;
}

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: sw=4 ts=4 fdm=marker
 * vim<600: sw=4 ts=4
 */