Ohne getch
sich darauf zu verlassen und das veraltete getpass
zu vermeiden , ist der empfohlene Ansatz, Terminal ECHO über termios
zu deaktivieren verwenden. Nach ein paar Suchen nach einer vorgefertigten flexiblen Passwortroutine war ich überrascht, dass nur sehr wenige für die eigenständige Verwendung mit C geeignet waren. Anstatt einfach getch
neu zu codieren mit termios c_lflag
Optionen, etwas allgemeinerer Ansatz erfordert nur ein paar Ergänzungen. Über das Ersetzen von getch
hinaus Jede Routine sollte eine bestimmte maximale Länge erzwingen, um einen Überlauf zu verhindern, abschneiden, wenn der Benutzer versucht, über das Maximum hinaus einzugeben, und warnen, wenn auf irgendeine Weise abgeschnitten wird.
Unten erlauben die Zusätze das Lesen von jedem FILE *
Eingabestrom, begrenzt die Länge auf eine bestimmte Länge, bietet minimale Bearbeitungsmöglichkeiten (Rücktaste) bei der Eingabe, ermöglicht die Angabe oder vollständige Deaktivierung der Zeichenmaske und gibt schließlich die Länge des eingegebenen Passworts zurück. Eine Warnung wurde hinzugefügt, wenn das eingegebene Passwort auf die maximale oder angegebene Länge gekürzt wurde.
Hoffentlich wird es anderen mit dieser Frage, die nach einer ähnlichen Lösung suchen, nützlich sein:
#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 */
}
Ein einfaches Programm, das die Verwendung zeigt, wäre wie folgt. Wenn Sie ein statisches Array von Zeichen zum Speichern des Passworts verwenden, stellen Sie einfach sicher, dass ein Zeiger an die Funktion übergeben wird.
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;
}
Beispielausgabe
$ ./bin/getpasswd2
Enter password: ******
you entered : 123456 (6 chars)
Enter password:
you entered : abcdef (6 chars)
In der Linux-Welt erfolgt die Maskierung normalerweise nicht mit Sternchen, normalerweise wird das Echo einfach ausgeschaltet und das Terminal zeigt Leerzeichen an, z. wenn Sie su
verwenden oder in ein virtuelles Terminal einloggen etc.
Es gibt eine Bibliotheksfunktion zum Abrufen von Passwörtern, die das Passwort nicht mit Sternchen maskiert, sondern das Echo des Passworts an das Terminal deaktiviert. Ich zog dies aus einem Linux-Buch, das ich habe. Ich glaube, es ist Teil des Posix-Standards
#include <unistd.h> char *getpass(const char *prompt); /*Returns pointer to statically allocated input password string on success, or NULL on error*/
Die getpass()-Funktion deaktiviert zunächst das Echoing und die gesamte Verarbeitung von Terminal-Sonderzeichen (wie etwa das Interrupt-Zeichen, normalerweise Strg-C).
Dann gibt es den String aus, auf den prompt zeigt, und liest eine Eingabezeile, wobei es den auf Null endenden Eingabestring mit entferntem Zeilenumbruch als Funktionsergebnis zurückgibt.
Eine Google-Suche nach getpass() enthält einen Verweis auf die GNU-Implementierung (sollte in den meisten Linux-Distributionen enthalten sein) und einigen Beispielcode für die Implementierung Ihres eigenen Codes, falls erforderlich
http://www.gnu.org/s/hello/manual/libc/getpass.html
Ihr Beispiel zum Selberrollen:
#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;
}
Bei Bedarf können Sie dies als Grundlage verwenden, indem Sie es so ändern, dass Sternchen angezeigt werden.