Passworteingabe am Terminal ausblenden

Lesezeit: 13 Minuten

Benutzeravatar von Hits
Treffer

Ich möchte mein Passwort maskieren, während ich es schreibe *. Ich verwende Linux GCC für diesen Code. Ich weiß, dass eine Lösung zu verwenden ist getch() funktionieren so

#include <conio.h>   
int main()
{
    char c,password[10];
    int i;
    while( (c=getch())!= '\n');{
        password[i] = c;
        printf("*");
        i++;
    }
    return 1;
}

aber das problem ist das GCC beinhaltet nicht conio.h Datei so, getch() ist für mich nutzlos. Hat jemand eine Lösung?

  • Kannst du nicht einfach verwenden getc(stdin) Anstatt von getch?

    – Dämon

    28. Juli 2011 um 9:27 Uhr

  • getc(stdin) führt immer noch dazu, dass die Eingabe auf dem Terminal wiedergegeben wird. Das OP möchte nicht, dass die Eingabe auf dem Terminal wiedergegeben wird.

    – Susan Pal

    28. Juli 2011 um 9:35 Uhr

  • richtig susam Pal, getc() oder getc(stdin) oder fgetc(stdin) hören nicht auf zu echoen.

    – Treffer

    28. Juli 2011 um 9:47 Uhr

  • conio.h ist unter Linux auch nicht verfügbar getch() ist.

    – alk

    17. Oktober 2012 um 8:23 Uhr


  • Schauen Sie sich diese Frage an: Was ist äquivalent zu getch() & getche() in Linux?.

    – Kiste Kiste Kiste Kiste

    16. Januar 2016 um 5:09 Uhr

Benutzeravatar von matt
matt

In der Linux-Welt erfolgt die Maskierung normalerweise nicht mit Sternchen, normalerweise ist das Echo einfach ausgeschaltet und das Terminal zeigt Leerzeichen an, z. B. wenn Sie verwenden su oder sich 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 zuerst das Echoing und die gesamte Verarbeitung von Terminal-Sonderzeichen (wie das Interrupt-Zeichen, normalerweise Strg-C).

Dann gibt es den String aus, auf den die Eingabeaufforderung zeigt, und liest eine Eingabezeile, wobei es den nullterminierten 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 vorhanden sein) und einige Beispielcodes zur Implementierung Ihrer eigenen, 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, um es so zu ändern, dass Sternchen angezeigt werden.

  • Laut man ist die Getpass-Funktion veraltet: “Diese Funktion ist veraltet. Verwenden Sie sie nicht.”

    – chmurli

    8. Mai 2012 um 12:00 Uhr


  • Unter Mac OS X 10.7.5 gibt getpass() einen ungültigen Zeiger zurück, der das Programm zum Absturz bringt, wenn Sie versuchen, es zu verwenden.

    – Michael

    1. Februar 2013 um 17:39 Uhr

  • Außerdem gibt tcgetattr für einige Empfangsvorgänge ENOTTY auf stdin (fileno=0) zurück, wenn es von der Befehlszeile ausgeführt wird!

    – Michael

    1. Februar 2013 um 18:08 Uhr

  • POSIX 1997 unterstützt getpass(), aber es war als “Legacy” gekennzeichnet. Die nächste Version, POSIX 2004nicht erforderlich getpass().

    – Jonathan Leffler

    21. Dezember 2017 um 5:50 Uhr


Benutzeravatar von David C. Rankin
David C. Rankin

Ohne getch sich auf Veraltetes zu verlassen und es zu vermeiden getpassist der empfohlene Ansatz, das Terminal ECHO durch zu deaktivieren termios verwenden. Nach ein paar Recherchen, um eine vorgefertigte flexible Passwortroutine zu finden, war ich überrascht, dass nur sehr wenige für die eigenständige Verwendung mit C geeignet waren. Anstatt einfach neu zu codieren getch mit Terminus c_lflag Optionen, etwas allgemeinerer Ansatz erfordert nur ein paar Ergänzungen. Jenseits des Ersetzens getch Jede Routine sollte eine angegebene 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 werden die Ergänzungen das Lesen von beliebigen ermöglichen 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 sich für andere mit dieser Frage als nützlich erweisen, die nach einer ähnlichen Lösung suchen:

#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)

  • Um das Terminal tatsächlich auszulesen, sollten Sie es nicht verwenden stdinaber offen /dev/tty in main. Und in getpasswdanstatt den Dateideskriptor zu verwenden 0verwenden fileno(fp) konsequent sein.

    – kein Benutzer

    16. März 2017 um 19:53 Uhr


  • I frage mich, was new_kbd_mode.c_cc[VTIME] = 0; und new_kbd_mode.c_cc[VMIN] = 1; eigentlich tun. Ich verstehe diesen Punkt in der Manpage nicht termios(3). Können Sie erklären?

    – kein Benutzer

    16. März 2017 um 19:59 Uhr


  • Entschuldigung für die späte Antwort, hatte eine Berufungsschrift fällig. Mein Verständnis von MIN > 0, TIME == 0 (blocking read) aus der Manpage ist read blockiert bis MIN Bytes sind verfügbar, anstatt abzufragen und zurückzugeben 0 wenn nichts verfügbar ist. Es gibt 4 Kombinationen, die unter erklärt werden noncanonical Abschnitt der Manpage. Ich schaue mir deine an /dev/tty Vorschlag – macht Sinn, aber wenn ich mich erinnere, müssen Sie auch angeben, welches tty.

    – David C. Rankin

    17. März 2017 um 0:49 Uhr

  • /dev/tty ist (automatisch) das steuernde tty des aktuellen Prozesses und daher meist das “richtige”.

    – kein Benutzer

    30. März 2017 um 13:04 Uhr


Die Funktionalität von getch (was eine nicht standardmäßige Windows-Funktion ist) kann mit diesem Code emuliert werden:

#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;
}

Beachten Sie, dass Ihr Ansatz nicht perfekt ist – es ist besser, etwas wie zu verwenden ncurses oder eine andere Terminalbibliothek, um diese Dinge zu handhaben.

  • Hey Delan Azabani, dein Code funktioniert, aber was du über die Ncurses-Bibliothek erzählst. bitte erkläre.

    – Treffer

    28. Juli 2011 um 10:00 Uhr

  • ncurses ist eine Terminalbibliothek, die viele allgemeine Aufgaben auf elegante Weise erledigen kann. Es ist sehr beliebt und in fast allen Linux-basierten Betriebssystemen enthalten.

    – Delan Azabani

    28. Juli 2011 um 10:02 Uhr

  • Die Verwendung von tcsetattr() ist richtig, aber denken Sie daran, dass das Terminal das Zeichen echot und dass es dies tut, wenn es eingegeben wird, nicht wenn es abgerufen wird. Sie müssen also ICANON ausschalten, alle ausstehenden Daten von stdin lesen (damit der Benutzer das Passwort nicht früh eingeben kann, wo es noch sichtbar wäre), den Benutzer nach dem Passwort fragen, es lesen und erst dann ICANON wieder einschalten.

    – Jan Hudec

    28. Juli 2011 um 11:30 Uhr

Benutzeravatar von Susam Pal
Susan Pal

Sie können Ihre eigenen erstellen getch() funktionieren unter Linux auf diese Weise.

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;
}

Benutzeravatar von trojanfoe
Trojaner

Ihre Methode ist korrekt, Sie müssen jedoch das Terminal-Echo ausschalten, während das Passwort eingegeben wird:

#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);
}

Anstatt von getch()warum nicht einfach verwenden getc() stattdessen?

  • Trojanfoe, ich hatte seinen Code in meinem Code marge, aber es gibt Fehler wie diesen, bitte helfen Sie, sie zu lösen. pass.cpp: In Funktion ‘void echo_off()’: pass.cpp:7:17: Fehler: Aggregat ‘sgttyb state’ hat unvollständigen Typ und kann nicht definiert werden pass.cpp:8:23: Fehler: ‘TIOCGETP’ war nicht in diesem Geltungsbereich deklariert pass.cpp:9:22: Fehler: ‘ECHO’ wurde in diesem Scope nicht deklariert pass.cpp:10:23: Fehler: ‘TIOCSETP’ wurde in diesem Scope nicht deklariert pass.cpp: In Funktion ‘void echo_on()’: pass.cpp:15:17: Fehler: Aggregat ‘sgttyb state’ hat unvollständigen Typ und kann nicht definiert werden pass.cpp:16:23: Fehler: ‘TIOCGETP’ wurde nicht deklariert

    – Treffer

    28. Juli 2011 um 9:43 Uhr

  • Beachten Sie, dass, wenn der Benutzer den Vorgang unterbricht (z. B. durch Drücken von Strg+C), während er das Passwort eingibt, das Terminal-Echo den Status Ein Aus hat und der Benutzer andere Linux-Befehle, die er in die Shell eingibt, möglicherweise nicht sehen kann. Normalerweise sollte der Benutzer in der Lage sein, sich von dieser Situation zu erholen, indem er Folgendes ausführt (er muss blind tippen): stty sane

    – Susan Pal

    28. Juli 2011 um 9:46 Uhr


  • Susam: Programme wie sudo fangen Signale ab, um sicherzustellen, dass der TTY-Zustand wiederhergestellt wird.

    – Peter TB Brett

    28. Juli 2011 um 10:26 Uhr

  • @Heet Kansagra: Sieht so aus, als ob Sie es auch brauchen könnten #include <asm/ioctls.h> auch.

    – Trojaner

    28. Juli 2011 um 11:35 Uhr

  • @trojanfoe-Fehler bleiben unverändert, nachdem #include hinzugefügt wurde

    – Treffer

    29. Juli 2011 um 7:07 Uhr

Benutzeravatar von Hits
Treffer

Vielen Dank an alle, deren Hilfe und Unterstützung mein Problem gelöst haben. Ich finde einen besten Weg, mein Passwort in Linux zu verbergen, der am besten zu mir passt. So verwenden Sie die Funktion getpass(). Es muss nur die Datei “unistd.h” enthalten sein.

Syntax der getpass-Funktion:

char * getpass (const char *prompt)

Parameter: prompt: Zeichenfolgenzeiger, der gedruckt werden soll, während nach dem Passwort gefragt wird

Rückgabewert: String-Zeiger des Passworts

Beispiel:

#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;
}

Ausgang:

Passwort eingeben:

hehe

  • Trojanfoe, ich hatte seinen Code in meinem Code marge, aber es gibt Fehler wie diesen, bitte helfen Sie, sie zu lösen. pass.cpp: In Funktion ‘void echo_off()’: pass.cpp:7:17: Fehler: Aggregat ‘sgttyb state’ hat unvollständigen Typ und kann nicht definiert werden pass.cpp:8:23: Fehler: ‘TIOCGETP’ war nicht in diesem Geltungsbereich deklariert pass.cpp:9:22: Fehler: ‘ECHO’ wurde in diesem Scope nicht deklariert pass.cpp:10:23: Fehler: ‘TIOCSETP’ wurde in diesem Scope nicht deklariert pass.cpp: In Funktion ‘void echo_on()’: pass.cpp:15:17: Fehler: Aggregat ‘sgttyb state’ hat unvollständigen Typ und kann nicht definiert werden pass.cpp:16:23: Fehler: ‘TIOCGETP’ wurde nicht deklariert

    – Treffer

    28. Juli 2011 um 9:43 Uhr

  • Beachten Sie, dass, wenn der Benutzer den Vorgang unterbricht (z. B. durch Drücken von Strg+C), während er das Passwort eingibt, das Terminal-Echo den Status Ein Aus hat und der Benutzer andere Linux-Befehle, die er in die Shell eingibt, möglicherweise nicht sehen kann. Normalerweise sollte der Benutzer in der Lage sein, sich von dieser Situation zu erholen, indem er Folgendes ausführt (er muss blind tippen): stty sane

    – Susan Pal

    28. Juli 2011 um 9:46 Uhr


  • Susam: Programme wie sudo fangen Signale ab, um sicherzustellen, dass der TTY-Zustand wiederhergestellt wird.

    – Peter TB Brett

    28. Juli 2011 um 10:26 Uhr

  • @Heet Kansagra: Sieht so aus, als ob Sie es auch brauchen könnten #include <asm/ioctls.h> auch.

    – Trojaner

    28. Juli 2011 um 11:35 Uhr

  • @trojanfoe-Fehler bleiben unverändert, nachdem #include hinzugefügt wurde

    – Treffer

    29. Juli 2011 um 7:07 Uhr

Benutzeravatar von Tim Cooper
Tim Cooper

Sie können ncurses.h verwenden, wenn es dafür nicht auf Windows portierbar sein muss, aber hier ist eine Art “portablerer” Version:

Wenn es nicht notwendig ist, tragbar zu sein, verweise ich Sie auf eine ncurses-Lösung

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

Und die c-Datei

was auch immer.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;
}

Das sollte zu deinem Problem passen.

Ich hoffe, das hilft.

  • Noch eine Antwort, wieder das gleiche Problem. ICANON muss deaktiviert sein, bevor Sie die Eingabeaufforderung drucken, und Sie müssen alle gepufferten Eingaben nach dem Deaktivieren und vor dem Drucken der Eingabeaufforderung löschen. Andernfalls kann der Benutzer das Passwort zu früh eingeben und es wird sichtbar.

    – Jan Hudec

    28. Juli 2011 um 11:34 Uhr

  • Hey danke, es funktioniert super. Ändern der dritten Zeile von portablegetch.h zum #if defined(__unix__) || defined(__APPLE__) wird es auch in macOS funktionieren.

    – Benutzer9869932

    22. Mai 2021 um 23:08 Uhr


1415180cookie-checkPassworteingabe am Terminal ausblenden

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy