69 votes

Masquer la saisie du mot de passe sur le terminal

Je veux masquer mon mot de passe tout en l'écrivant avec * . J'utilise Linux GCC pour ce code. Je sais qu'une solution consiste à utiliser getch() comme ceci

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

mais le problème est que GCC ne comprend pas conio.h ainsi, getch() est inutile pour moi. Quelqu'un a-t-il une solution ?

1 votes

Ne pouvez-vous pas simplement utiliser getc(stdin) au lieu de getch ?

10 votes

Getc(stdin) résulte toujours en un écho de l'entrée sur le terminal. L'OP ne veut pas que l'entrée soit renvoyée sur le terminal.

0 votes

Comme susam Pal, getc() ou getc(stdin) ou fgetc(stdin) n'arrête pas l'écho.

56voto

matt Points 161

Dans le monde Linux, le masquage n'est généralement pas effectué avec des astérisques, normalement l'écho est simplement désactivé et le terminal affiche des blancs. su ou se connecter à un terminal virtuel, etc.

Il existe une fonction de bibliothèque pour gérer l'obtention des mots de passe, elle ne masque pas le mot de passe avec des astérisques mais désactive l'écho du mot de passe dans le terminal. J'ai tiré cela d'un livre sur Linux que j'ai. Je crois que cela fait partie du standard Posix.

#include <unistd.h>
char *getpass(const char *prompt);

/*Returns pointer to statically allocated input password string
on success, or NULL on error*/

La fonction getpass() désactive tout d'abord l'écho et tout traitement des caractères spéciaux du terminal (tels que les interruptions de service). caractères spéciaux du terminal (tels que le caractère d'interruption, normalement Control-C).

Il imprime ensuite la chaîne pointée par prompt, et lit une ligne d'entrée de d'entrée, et renvoie la chaîne d'entrée à terminaison nulle avec la le saut de ligne de queue, comme résultat de la fonction.

Une recherche google pour getpass() donne une référence à l'implémentation GNU (qui devrait être dans la plupart des distributions linux) et quelques exemples de code pour implémenter le vôtre si nécessaire.

http://www.gnu.org/s/hello/manual/libc/getpass.html

Leur exemple pour rouler votre propre :

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

Si nécessaire, vous pouvez vous en servir comme base et le modifier pour afficher des astérisques.

18 votes

Selon l'homme la fonction getpass est obsolète : "Cette fonction est obsolète. Ne l'utilisez pas."

1 votes

Sous Mac OS X 10.7.5, getpass() renvoie un pointeur invalide qui fera planter le programme si vous essayez de l'utiliser.

0 votes

De plus, pour une raison quelconque, tcgetattr renvoie ENOTTY sur stdin (fileno=0) lorsqu'il est exécuté depuis la ligne de commande !

11voto

Delan Azabani Points 33013

La fonctionnalité de getch (qui est une fonction non standard de Windows) peut être émulée avec ce 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;
}

Notez que votre approche n'est pas parfaite - il est préférable d'utiliser quelque chose comme ncurses ou une autre bibliothèque de terminal pour gérer ces choses.

0 votes

Hey Delan Azabani, votre code fonctionne, mais ce que vous dites sur la bibliothèque ncurses. s'il vous plaît expliquer.

1 votes

Ncurses est une bibliothèque de terminal qui peut gérer de nombreuses tâches courantes de manière élégante. Elle est très populaire et peut être trouvée incluse dans presque tous les systèmes d'exploitation basés sur Linux.

0 votes

L'utilisation de tcsetattr() est correct, mais n'oubliez pas que le terminal renvoie le caractère et qu'il le fait lorsqu'il est tapé, et non lorsqu'il est récupéré. Vous devez donc désactiver ICANON, lire toutes les données en attente à partir de stdin (pour que l'utilisateur ne puisse pas taper le mot de passe plus tôt où il serait encore visible), demander à l'utilisateur son mot de passe, le lire et seulement après réactiver ICANON.

6voto

Susam Pal Points 6171

Vous pouvez créer votre propre getch() sur Linux de cette manière.

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

Code démo :

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

1 votes

Encore une même réponse, encore un même problème ! Vous devez désactiver ICANON, supprimer tout ce qui est mis en mémoire tampon sur stdin, demander le mot de passe à l'utilisateur, lire le mot de passe et seulement après activer ICANON.

3voto

trojanfoe Points 61927

Votre méthode est correcte, mais vous devez désactiver l'écho du terminal pendant la saisie du mot de passe :

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

Au lieu de getch() pourquoi ne pas simplement utiliser getc() à la place ?

0 votes

Trojanfoe, j'ai intégré son code dans mon code mais il donne des erreurs comme celles-ci, aidez-moi à les résoudre. 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 : Dans la fonction '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 declared

3 votes

Notez que si l'utilisateur interrompt le processus (disons en appuyant sur Ctrl+C) pendant qu'il saisit le mot de passe, l'écho du terminal serait en état d'arrêt et l'utilisateur pourrait ne pas être en mesure de voir les autres commandes Linux qu'il tape dans le shell. Normalement, l'utilisateur devrait pouvoir se sortir de cette situation en exécutant (il doit taper à l'aveugle) : stty sane

0 votes

Susam : Des programmes tels que sudo captent les signaux afin de s'assurer que l'état ATS est restauré.

2voto

niko Points 3622
#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;
}

Il suffit de copier ces extraits et de les utiliser. J'espère que cela vous a aidé

7 votes

Ne donnez pas de leçons à l'OP. Expliquez comment le code fonctionne.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X