2009-07-28 5 views
20

Je pourrais utiliser getpass() pour obtenir un mot de passe. Cependant, la page de manuel indique:Obtenir un mot de passe en C sans utiliser getpass (3)?

Cette fonction est obsolète. N'utilisez pas .

Quelle est la manière actuelle d'obtenir un mot de passe du terminal de l'utilisateur sans écho, d'une manière compatible POSIX? [À l'origine j'ai dit "portably", mais mon intention était d'éviter d'utiliser une fonction obsolète.]

+4

Il n'y a pas de manière portable - cela dépend fortement de votre plate-forme. –

+0

@Jerry, ça n'en vaut pas la peine ... même si c'est LEGACY, c'est la façon la plus portable de s'y prendre. –

Répondre

13

cela devrait fonctionner sur Linux/MacOSX, une version de Windows devrait utiliser Get/Set ConsoleMode

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

int 
main(int argc, char **argv) 
{ 
    struct termios oflags, nflags; 
    char password[64]; 

    /* disabling echo */ 
    tcgetattr(fileno(stdin), &oflags); 
    nflags = oflags; 
    nflags.c_lflag &= ~ECHO; 
    nflags.c_lflag |= ECHONL; 

    if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0) { 
     perror("tcsetattr"); 
     return EXIT_FAILURE; 
    } 

    printf("password: "); 
    fgets(password, sizeof(password), stdin); 
    password[strlen(password) - 1] = 0; 
    printf("you typed '%s'\n", password); 

    /* restore terminal */ 
    if (tcsetattr(fileno(stdin), TCSANOW, &oflags) != 0) { 
     perror("tcsetattr"); 
     return EXIT_FAILURE; 
    } 

    return 0; 
} 
+0

Cela semble le moyen le plus simple pour moi. –

+3

Vous devriez d'abord utiliser/dev/tty avant d'essayer stdin, comme si vous utilisiez un pipe, stdin serait le contenu canalisé, pas l'entrée du terminal. – xryl669

+3

Ça ne me dérangerait pas de voir le mot de passe char [64] = {0}; ou un memset avant qu'il soit utilisé s'il est réentrant –

4

Vous pouvez utiliser la bibliothèque ncurses pour lire à partir de l'entrée standard sans renvoyer les résultats à l'écran. (Appelez le noecho() avant d'obtenir une entrée). La bibliothèque a été autour depuis des siècles et travaille sur une grande variété de plates-formes (la version Windows se trouve here)

+0

J'ai fait une simple application de curses (ça a été un couple décadé depuis que j'ai utilisé des sorts), et j'ai trouvé que ça effaçait l'écran quand j'ai fait initscr(). Il y a probablement un moyen de contourner cela, mais ce n'était pas évident à partir d'une lecture rapide des pages man. –

1

Sur les fenêtres, vous pouvez probablement utiliser le SetConsoleMode api, décrit here.

2

Selon le University of Milwaukee's documentation est obsolète parce que:

La fonction getpass() n'est pas threadsafe car il manipule l'état de signal global .

La fonction getpass() doit être retirée d'une future version de la spécification XE Open CAE.

+3

Il a été retiré de POSIX/Single UNIX (le successeur de X/Open) depuis 2001. –

+2

Comment est-ce une réponse? Cela devrait vraiment être un commentaire. –

3

Bien que ce soit une question très ancienne qui a déjà répondu, voici ce que je l'ai utilisé (qui est très similaire à la réponse acceptée):

#include <termios.h> 
#include <cstdio> 

// 
// The following is a slightly modifed version taken from: 
// http://www.gnu.org/software/libc/manual/html_node/getpass.html 
// 
ssize_t my_getpass (char *prompt, 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; 

    /* Display the prompt */ 
    if (prompt) 
     printf("%s", prompt); 

    /* Read the password. */ 
    nread = getline (lineptr, n, stream); 

    /* Remove the carriage return */ 
    if (nread >= 1 && (*lineptr)[nread - 1] == '\n') 
    { 
     (*lineptr)[nread-1] = 0; 
     nread--; 
    } 
    printf("\n"); 

    /* Restore terminal. */ 
    (void) tcsetattr (fileno (stream), TCSAFLUSH, &_old); 

    return nread; 
} 

// 
// Test harness - demonstrate calling my_getpass(). 
// 
int main(int argc, char *argv[]) 
{ 
    size_t maxlen = 255; 
    char pwd[maxlen]; 
    char *pPwd = pwd; // <-- haven't figured out how to avoid this. 

    int count = my_getpass((char*)"Enter Password: ", &pPwd, &maxlen, stdin); 

    printf("Size of password: %d\nPassword in plaintext: %s\n", count, pwd); 

    return 0; 
} 
+0

Me gusta. Cela vous permettra même de rediriger votre mot de passe depuis la ligne de commande; Cependant, si vous faites cela, vous ne voudrez peut-être pas imprimer une invite de mot de passe. – JesseTG

Questions connexes