/* * getpass.c * Pieter Droogendijk */ #include #include #include #include /* * Suitable to read a password from the controlling terminal. * Takes a prompt, a buffer and that buffer's length. * Returns the length of the password. */ size_t safegetpass (const char *prompt, char *buf, size_t buflen) { FILE *fp; char *cterminal; struct termios temptermopt, oldtermopt; sigset_t tempsigset, oldsigset; int input; size_t obuflen = buflen; /* Open controlling terminal. */ cterminal = ctermid (NULL); fp = fopen (cterminal, "r+"); if (fp == NULL) return -1; /* Disable stdio buffering. */ setbuf (fp, NULL); /* Block SIGINT, SIGQUIT, SIGSTOP and SIGTSTP. */ sigemptyset (&tempsigset); sigaddset (&tempsigset, SIGINT); sigaddset (&tempsigset, SIGQUIT); sigaddset (&tempsigset, SIGSTOP); sigaddset (&tempsigset, SIGTSTP); sigprocmask (SIG_BLOCK, &tempsigset, &oldsigset); /* Disable echoing on controlling terminal. */ tcgetattr (fileno (fp), &oldtermopt); temptermopt = oldtermopt; temptermopt.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL); tcsetattr (fileno (fp), TCSAFLUSH, &temptermopt); fputs (prompt, fp); /* Get the password. */ while ( (input = getc(fp)) != EOF && input != '\n' ) { if (buflen <= 1) break; buflen --; *buf++ = input; } *buf = '\0'; putc ('\n', fp); /* Restore terminal and signal settings. */ tcsetattr (fileno (fp), TCSAFLUSH, &oldtermopt); sigprocmask (SIG_SETMASK, &oldsigset, NULL); /* We're done with the terminal now. */ fclose (fp); return obuflen - buflen; } int main (void) { char buf[5]; size_t len = safegetpass ("Password", buf, sizeof buf); printf ("%u '%s'\n", (unsigned) len, buf); }