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 argc, const 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_sigint, 0, sizeof(struct sigaction));
sa_sigint.sa_handler = sigint_handler;
sa_sigint.sa_flags = 0;
if ( sigaction(SIGINT, &sa_sigint, NULL) < 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
*/