Hide password input on terminal
Asked Answered
D

16

68

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?

Drachm answered 28/7, 2011 at 9:16 Comment(7)
Can't you just use getc(stdin) instead of getch?Valaria
getc(stdin) still results in the input being echoed on the terminal. The OP doesn't want the input to be echoed on the terminal.Rikki
right susam Pal, getc() or getc(stdin) or fgetc(stdin) doesn't stop echoing.Lamellibranch
conio.h is not available under Linux, neither getch() is.Hornbook
Check out this question: What is equivalent to getch() & getche() in Linux?.Rees
It's not available because it's not part of the C standard. Still you don't want asterisks. Turning off echo is better. Doesn't show many characters are there. Okay relying on that solely is a bad idea but in addition to other things it's not bad (though the password is one of the weakest links in the chain so it probably is helpful if someone is looking over your shoulder though if they are they might as well just observe the characters you're typing!).Symploce
@Hornbook .. not true. getch() is a function. However it's a curses function so it's not the same thing and you obviously have to link in the curses library.Symploce
G
56

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.

Gurkha answered 29/7, 2011 at 5:58 Comment(6)
According to man getpass function is obsolete: "This function is obsolete. Do not use it."Dateline
On Mac OS X 10.7.5, getpass() returns an invalid pointer which will crash the program if you try to use it.Prattle
Also, for some receive tcgetattr is returning ENOTTY on stdin (fileno=0) when running from the command line!Prattle
POSIX 1997 supported getpass(), but it was marked 'legacy'. The next version, POSIX 2004, did not require getpass().Motorcycle
Kind OT: in the case of telnet (and yes there are legitimate uses for it just not for remotely logging into systems) you can send the sequence: (char) IAC, (char) WILL, (char) TELOPT_ECHO, (char) 0 and to disable (char) IAC, (char) WONT, (char) TELOPT_ECHO, (char) TELOPT_NAOFFD, (char) TELOPT_NAOCRD, (char) 0 - but that's just an aside for sockets programming specific to telnet.Symploce
Theo - yes that Theo - suggested it's because the function has no length passed in. But the function just discards the remaining part. I'm not sure if it NUL terminates it in that case but I'd hope so. I have no idea how its allocation works or if it does any. But that probably is why. Still strange without a replacement though yes. Some systems have readpassphrase() which might be used instead.Symploce
T
19

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)
Tonry answered 6/9, 2015 at 8:43 Comment(5)
To actually read from the terminal, you should not use stdin, but open /dev/tty in main. And in getpasswd, instead of using file descriptor 0, use fileno(fp) to be consistent.Conquest
I wonder what new_kbd_mode.c_cc[VTIME] = 0; and new_kbd_mode.c_cc[VMIN] = 1; actually do. I don't get that point in the man page termios(3). Can you explain?Conquest
Sorry for the late reply, had an appellate brief due. My understanding of MIN > 0, TIME == 0 (blocking read) from the man page is read blocks until MIN bytes are available rather than polling and returning 0 if nothing is available. There are 4 combination explained under the noncanonical section of the man page. I'll look into your /dev/tty suggestion -- makes sense, but if I recall, you also have to designate which tty.Tonry
/dev/tty is (automagically) the controlling tty of the current process, and therefore usually the "right" one.Conquest
@DavidC.Rankin Yes that's how blocking I/O works. Similar can be done with curses with the function timeout(-1);. After this getch() will wait indefinitely. In half-delay mode the function waits up to a certain amount of time or a character is read, whichever comes first.Symploce
N
11

The functionality of getch (which is a non-standard, Windows function) can be emulated with this code:

#include <termios.h>
#include <unistd.h>
int getch() {
    struct termios oldt, newt;
    int ch;
    tcgetattr(STDIN_FILENO, &oldt);
    newt = oldt;
    newt.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
    ch = getchar();
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
    return ch;
}

Note that your approach is not perfect - it's better to use something like ncurses or another terminal library to handle these things.

Nellie answered 28/7, 2011 at 9:21 Comment(4)
hey Delan Azabani, your code works, but what you tell about ncurses library. please explain.Lamellibranch
ncurses is a terminal library that can handle many common tasks in an elegant way. It is very popular and can be found included with almost all Linux-based operating systems.Nellie
The use of tcsetattr() is correct, but remember that the terminal echoes the character and that it does so when it is typed, not when it is retrieved. So you have to turn off ICANON, read all pending data from stdin (so user can't type the password early where it would still be visible), ask user for password, read it and only than turn ICANON back on.Acroterion
Yes .. curses is great if one can appreciate the way it works. For a normal text application it might not always be the right choice.Symploce
R
6

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;
}
Rikki answered 28/7, 2011 at 9:21 Comment(1)
One more same answer, one more same problem! You must turn off ICANON, discard anything buffered on stdin, ask user for password, read the password and only than turn ICANON on.Acroterion
S
3

Your method is correct, however you'll need to turn off terminal echo while the password is being entered:

#include <sgtty.h>

void echo_off()
{
    struct sgttyb state;
    (void)ioctl(0, (int)TIOCGETP, (char *)&state);
    state.sg_flags &= ~ECHO;
    (void)ioctl(0, (int)TIOCSETP, (char *)&state);
}

void echo_on()
{
    struct sgttyb state;
    (void)ioctl(0, (int)TIOCGETP, (char *)&state);
    state.sg_flags |= ECHO;
    (void)ioctl(0, (int)TIOCSETP, (char *)&state);
}

Instead of getch(), why not just use getc() instead?

Secluded answered 28/7, 2011 at 9:24 Comment(7)
Trojanfoe, I had marge his code in my code but it gives errors like this, please help to solve them. pass.cpp: In function ‘void echo_off()’: pass.cpp:7:17: error: aggregate ‘sgttyb state’ has incomplete type and cannot be defined pass.cpp:8:23: error: ‘TIOCGETP’ was not declared in this scope pass.cpp:9:22: error: ‘ECHO’ was not declared in this scope pass.cpp:10:23: error: ‘TIOCSETP’ was not declared in this scope pass.cpp: In function ‘void echo_on()’: pass.cpp:15:17: error: aggregate ‘sgttyb state’ has incomplete type and cannot be defined pass.cpp:16:23: error: ‘TIOCGETP’ was not declaredLamellibranch
Note that if the user presses interrupts the process (say by pressing Ctrl+C) while entering the password, the terminal echo would be on off state and the user may not be able to see other Linux commands he types in the shell. Normally, the user should be able to recover from this situation by executing (he has to type blindly): stty saneRikki
Susam: Programs such as sudo catch signals in order to ensure that the TTY state is restored.Alverta
@Heet Kansagra: Looks like you might also need #include <asm/ioctls.h> as well.Secluded
@Secluded Errors are as it is after adding #include <asm/ioctls.h>Lamellibranch
@SusamPal yes but sometimes reset is better than stty sane. if echo was turned off you can just do stty echo instead. It's an important point to consider though!Symploce
@PeterT.B.Brett .. but not all do catch it.Symploce
D
3

Thanks all of you whose help & support to solve my problem. I find a best way to hide my password in linux that fits me best. To use getpass() function. It just need to include "unistd.h" file.

syntex of getpass function:

char * getpass (const char *prompt)

Parameters: prompt: string pointer to print while asking for Password

Return Value: string pointer of password

Example:

#include <stdio.h>
#include <unistd.h>   
int main()
{
    char *password; // password string pointer
    password = getpass("Enter Password: "); // get a password
    printf("%s\n",password); // this is just for conformation
                             // that password stored successfully
    return 1;
}

output:

Enter Password:

heet

Drachm answered 29/7, 2011 at 11:58 Comment(2)
On Mac OS X 10.7.5, getpass() returns an invalid pointer which will crash the program if you try to use it.Prattle
This only declares it. It doesn't mean it's there. It's not required and it's obsolete. That's the entire point. So you're right but you're missing the point.Symploce
E
2

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.

Exhibitionist answered 28/7, 2011 at 10:24 Comment(2)
One more answer, the same problem again. ICANON must be off before you print the prompt and you must clear out any buffered input after you turn it off and before you print the prompt. Otherwise the user may type in the password too early and it will be visible.Acroterion
Hey thanks, It works awesome. Changing the third line of portablegetch.h for #if defined(__unix__) || defined(__APPLE__) will make it also work in macOS.Harpist
S
2
#include <termios.h>
#include <stdio.h>

static struct termios old, new;

void initTermios(int echo) {
    tcgetattr(0, &old);
    new = old;
    new.c_lflag &= ~ICANON;
    new.c_lflag &= echo ? ECHO : ~ECHO;
    tcsetattr(0, TCSANOW, &new);
}

void resetTermios(void) {
    tcsetattr(0, TCSANOW, &old);
}

char getch_(int echo) {
    char ch;
    initTermios(echo);
    ch = getchar();
    resetTermios();
    return ch;
}

char getch(void) {
    return getch_(0);
}

int main(void) {
    char c;
    printf("(getch example) please type a letter...");
    c = getch();
    printf("\nYou typed: %c\n", c);
    return 0;
}

Just copy these snippet and use it. Hope it helped

Stubborn answered 28/9, 2011 at 12:31 Comment(1)
Do not spoon-feed the OP. Explain how the code works.Rees
W
1

Just pass for it the char* that you want to set password in and its size and the function will do its job

void set_Password(char *get_in, int sz){
    for (int i = 0; i < sz;) {
        char ch = getch();
        if (ch == 13) {
            get_in[i] = '\0';
            break;
        }
        else if(ch != 8){
            get_in[i++] = ch;
            putch('*');
        }
        else if(i > 0)
            cout << "\b \b",get_in[i--] = '\0';
    }
    cout << "\n";
}

This is an example, run it on your compiler

Westsouthwest answered 28/4, 2022 at 5:17 Comment(0)
T
0

Unfortunately in the C standard library there is no such function out of the box. Maybe in third party library.

One option is use ANSI escape sequences to set the background color to foreground color in the console to conceal the password. Try this link.

Termagant answered 28/7, 2011 at 9:23 Comment(3)
That's very unsafe; the password string can still be selected with the mouse in X11 or a console where a mouse daemon is installed.Quiver
actually getc(), getch() or gets() this all functions are unsafe and give the warnings warning: the `gets' function is dangerous and should not be used.Lamellibranch
There's nothing unsafe about getc.Quiver
D
0

With scanning the characters you can take it into a buffer. Also you need to write code if backspace is pressed, and appropriately correct the inserted password.

Here is a code which once i wrote with the curses. Compile with gcc file.c -o pass_prog -lcurses

#include <stdio.h>
#include <stdlib.h>
#include <curses.h>

#define ENOUGH_SIZE 256

#define ECHO_ON 1
#define ECHO_OFF 0

#define BACK_SPACE 127

char *my_getpass (int echo_state);

int main (void)
{
  char *pass;

  initscr ();

  printw ("Enter Password: ");
  pass = my_getpass (ECHO_ON);

  printw ("\nEntered Password: %s", pass);
  refresh ();
  getch ();
  endwin ();
  return 0;
}


char *my_getpass (int echo_state)
{
  char *pass, c;
  int i=0;

  pass = malloc (sizeof (char) * ENOUGH_SIZE);
  if (pass == NULL)
  {
    perror ("Exit");
    exit (1);
  }

  cbreak ();
  noecho ();

  while ((c=getch()) != '\n')
  {
    if (c == BACK_SPACE)
    {
      /* Do not let the buffer underflow */
      if (i > 0)
      { 
        i--;
        if (echo_state == ECHO_ON)
               printw ("\b \b");
      }
    }
    else if (c == '\t')
      ; /* Ignore tabs */
    else
    {
      pass[i] = c;
      i = (i >= ENOUGH_SIZE) ? ENOUGH_SIZE - 1 : i+1;
      if (echo_state == ECHO_ON)
        printw ("*");
    }
  }
  echo ();
  nocbreak ();
  /* Terminate the password string with NUL */
  pass[i] = '\0';
  endwin ();
  return pass;
}
Deflation answered 28/7, 2011 at 16:23 Comment(0)
D
0

In C you can use getpasswd() function which pretty much doing similar thing as stty in shell, example:

#include <stdio.h>
#include <string.h>
#include <pwd.h>
#include <unistd.h>

int main()
{
    char acct[80], password[80];

    printf(“Account: “);
    fgets(acct, 80, stdin);

    acct[strlen(acct)-1] = 0; /* remove carriage return */

    strncpy(password, getpass(“Password: “), 80);
    printf(“You entered acct %s and pass %s\n”, acct, password);

    return 0;
}

Here is equivalent shell script which use stty (which changes the settings of your tty):

save_state=$(stty -g)
/bin/echo -n “Account: “
read acct
/bin/echo -n “Password: “
stty -echo
read password # this won’t echo
stty “$save_state”
echo “”
echo account = $acct and password = $password

Source: How can I read a password without echoing it in C?

Dosser answered 27/8, 2015 at 17:53 Comment(0)
S
0

man getpass

This function is obsolete. Do not use it. If you want to read input without terminal echoing enabled, see the description of the ECHO flag in termios(3)

# include <termios.h>
# include <unistd.h>   /* needed for STDIN_FILENO which is an int file descriptor */

struct termios tp, save;

tcgetattr( STDIN_FILENO, &tp);              /* get existing terminal properties */
save = tp;                                  /* save existing terminal properties */

tp.c_lflag &= ~ECHO;                        /* only cause terminal echo off */

tcsetattr( STDIN_FILENO, TCSAFLUSH, &tp );  /* set terminal settings */

/*
   now input by user in terminal will not be displayed
   and cursor will not move
*/

tcsetattr( STDIN_FILENO, TCSANOW, &save);   /* restore original terminal settings */

If you notice, most current linux distro's do not mask a password with asterisks. Doing so divulges the length of the password which is no way beneficial. It is easier and better to simply make the cursor not move when a password is typed in. If for whatever reason you require a * to be printed for every character that's typed then you would have to grab every keypress before Enter is hit and that's always been problematic.

Solve answered 24/3, 2019 at 16:30 Comment(0)
T
0
printf("\nENTER PASSWORD: ");
while (1)
{
    ch=getch();
    if(ch==13)    //ON ENTER PRESS
        break;

    else if(ch==8)    //ON BACKSPACE PRESS REMOVES CHARACTER
    {
        if(i>0)
        {
            i--;
            password[i]='\0';
            printf("\b \b");
        }
    }
    else if (ch==32 || ch==9)    //ON PRESSING TAB OR SPACE KEY
        continue;
    else
    {
        password[i]=ch;
        i++;
        printf("*");
    }         
}
password[i]='\0';
Tercet answered 17/5, 2020 at 13:45 Comment(1)
Thank you for this code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by showing why this is a good solution to the problem and would make it more useful to future readers with other, similar questions. Please edit your answer to add some explanation, including the assumptions you’ve made.Lush
K
0

Here is my idea, adapted from that of the C++ official site.

#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
string getpass(const char *prompt, bool showchar = false, char echochar = '*')
{
    struct termios oi, ni;
    tcgetattr(STDIN_FILENO, &oi);
    ni = oi;
    ni.c_lflag &= ~(ICANON | ECHO);
    const char DELETE = 127;
    const char RETURN = 10;
    string password;
    unsigned char ch = 0;
    cout << prompt;
    tcsetattr(STDIN_FILENO, TCSANOW, &ni);
    while (getchar() != RETURN) {
        if (ch == DELETE) {
            if(password.length != 0){
                if (showchar) cout << "\b \b";
                password.resize(password.length() - 1);
            }
        }else {
            password += getchar();
            if (showchar) cout << echochar;
        }
    }
    tcsetattr(STDIN_FILENO,TCSANOW,&oi)
    cout << endl;
    return password;
}

It will read one character at once and add it to the string and supports showing another character.

Kostman answered 5/9, 2020 at 8:25 Comment(1)
Please note that this is also suitable for UNIX as well. :-)Kostman
M
-1

note that the ICANON termios lflag turns off the processing carriagereturn/linefeed, and the negative ECHO termios setting turns off echo for STDIN.

when using this (with or without the echo being on) to read a password and print '*' for entered characters, it's not just a matter of reading characters until a newline/carriage return is encountered, you also have to process backspace in your 'string building routine' (else the backspaces end up in the actual string, and do not cause characters to be removed from it such as would be the case with the various string based input functions).

the same would happen in C in DOS with getch tho. that would also happily return 0x08 for backspace (or 127 or whatever your specific os uses as backspace)

keeping track of 'not deleting -before- the start of the string', replacing the 'new end of the string' with 0 and moving the current position counter back by one (unless you are at position 0) is up to the programmer with any of these functions (even the getch on dos C).

getpass() doesn't do what the user originally asked for btw, he wants *'s (which still disclose the length of the password to people standing behind him and looking at his screen, as well as in the scrollbuffer of the terminal if he doesn't close it after use). but without *'s is probably a better idea in 'non closed environments'.

Martensite answered 16/1, 2016 at 4:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.