Masquer mot de passe [Résolu/Fermé]

Signaler
Messages postés
25
Date d'inscription
dimanche 30 décembre 2012
Statut
Membre
Dernière intervention
20 juin 2013
-
Messages postés
11066
Date d'inscription
samedi 5 mai 2007
Statut
Contributeur
Dernière intervention
18 octobre 2016
-
Bonjour,

Mon but est d'arriver à masquer mon mot de passe lors de la saisie.
pour être plus claire,quand je saisie mon mot de passe sous la console(UNIX) je voudrais avoir des '*' au lieu des caractères tapés.

Merci d'avance...

4 réponses

Messages postés
4242
Date d'inscription
samedi 8 septembre 2007
Statut
Membre
Dernière intervention
29 août 2018
194
yosh !

Je sais pas si quelque chose existe, mais tu peux faire :

a chaque caractère différent de ENTER : je le stock, je clearscreen et j'affiche une '*' en plus
SI le caractère est enter => je valide mes caractères stockés
Messages postés
4242
Date d'inscription
samedi 8 septembre 2007
Statut
Membre
Dernière intervention
29 août 2018
194
Messages postés
11066
Date d'inscription
samedi 5 mai 2007
Statut
Contributeur
Dernière intervention
18 octobre 2016
1 720
Installer allegro pour si peu... De plus cela ne repond toujours pas au besoin.
Readey () lit dans le buffer clavier. Il faudra donc attendre la touche entrée.
Bref je répète : il faut passer le terminal en raw. Et après on utilise la fonction de lecture de son choix. Cf. Réponse de Dal.
La seule fonction posix qui faisait tout est getpass (). Mais elle est obsolète.
Messages postés
4242
Date d'inscription
samedi 8 septembre 2007
Statut
Membre
Dernière intervention
29 août 2018
194
de ce que j'en lit, non, mais vu que je ne peux pas tester c'est pas simple, mais je suis persuadé que ça existe, d'un part parceque dans le cadre d'un tp je l'avais fais, et d'autre part car de manière native, chaque instruction clavier lève un évènement, et le fait d'attendre la touche 'enter' est une 'surcharge' (le terme est pas terrible vu qu'on est en dev, mais sur le coup j'ai pas mieux ^^) de cette évènement, qui rajoute simplement à une pile le code hexa tappé.

Pour ce qui est du clearscreen, j'avais pas fais gaffe, mais l'utilisateur peu remonter mais seulement un certain nombre de lignes il me semble (ou alors c'est que dans windows, j'ai un doute), mais si c'est bien ca, il faut juste passer le nombre de ligne adéquate.

J'essayerai de regarder ca après le taff, je doit avoir une distrib de linux (probablement ubuntu) qui traine ;)
Messages postés
11066
Date d'inscription
samedi 5 mai 2007
Statut
Contributeur
Dernière intervention
18 octobre 2016
1 720
de ce que j'en lit, non, mais vu que je ne peux pas tester c'est pas simple, mais je suis persuadé que ça existe,
Ben, relis ^^. Aucune ambigüité.
Je recopie ton lien même et graisse les éléments importants : Returns the next character from the keyboard buffer. Allegro game programming library.
Donc, c'est non posix et ça récupère les données du buffer clavier...

et d'autre part car de manière native,
Impossible. Cela va à l'encontre des bases du C.

chaque instruction clavier lève un évènement, et le fait d'attendre la touche 'enter' est une 'surcharge'
Oui, sauf qu'en C le matériel (clavier, etc.) est complètement inconnu du C. Impossible donc de récupérer ces événements. Il faut donc faire appel à des fonctions du système. Le plus portable consiste à utiliser une bibliothèque (attention portage n'est pas synonyme de portable) comme ncurses.

Pour ce qui est du clearscreen, j'avais pas fais gaffe, mais l'utilisateur peu remonter mais seulement un certain nombre de lignes il me semble (ou alors c'est que dans windows, j'ai un doute), mais si c'est bien ca, il faut juste passer le nombre de ligne adéquate.
Comme tu le remarques, cela dépend de l'OS. Ce n'est donc pas la bonne méthode. De plus, en faisant une redirection dans un fichier, ta méthode ne marche plus du tout.

Bref, mode raw est la seule façon et ce n'est pas si compliquée. Puis lecture avec getchar(). Ou alors bibliothèque (mais pas trop lourde comme allegro).
Messages postés
4242
Date d'inscription
samedi 8 septembre 2007
Statut
Membre
Dernière intervention
29 août 2018
194
ouaip j'ai récupéré le code, je testerai ca ^^ (c'est dingue ce qu'on peu zappé en qq mois sur windev ...)
Messages postés
5446
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
27 novembre 2020
914
Salut aadilove,

Sous Linux/Unix, tu dois suspendre l'écho à l'écran des caractères tapés.

Tu peux faire comme indiqué ici :

https://stackoverflow.com/questions/1196418/getting-a-password-in-c-without-using-getpass-3

Si tu tiens absolument à afficher des étoiles (pourquoi ?), c'est plus compliqué, et tu devrais sans doutes utiliser ncurses.

Comme cela :

http://www.cplusplus.com/articles/E6vU7k9E/#CURSES-e2

ncurses est une librairie en C, le code présenté sur ce lien mélange du C avec un style de programmation C++, mais cela devrait te donner une idée et c'est assez simple à corriger. Sinon, tu devrais trouver d'autres exemples programmés de façon plus orthodoxes en C.


Dal
Messages postés
11066
Date d'inscription
samedi 5 mai 2007
Statut
Contributeur
Dernière intervention
18 octobre 2016
1 720
Écrire une * n'est pas beaucoup plus compliqué que passer le terminal en raw.
Avec ton premier lien, tu passes le terminal en raw. Dès que tu lis le caractère entré par l'utilisateur, tu affiches une '*'. Rien de plus.
Messages postés
5446
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
27 novembre 2020
914
Salut fiddy,

Lorsqu'on permet à l'utilisateur de saisir quelque chose, il est aussi sympa de lui permettre d'effacer sa saisie :-), et donc de gérer la touche backspace, afin qu'elle efface le caractère (l'étoile) précédemment saisie, jusqu'à éventuellement l'étoile représentant la première, et gérer les données de façon correspondante... et gérer aussi la touche entrée, bien sûr.

Donc, si on veut correctement gérer ce type d'interface utilisateur, il faut aller un peu plus loin.

fgets qui est utilisée dans le premier lien ne permet pas de faire cela, car elle ne gère qu'un flux et attend ENTER (ou EOF).

Je pense que getchar pourrait être utilisé, avec le line buffering désactivé (en jouant avec ICANON) en plus de echo, et envoyer \b comme montré dans le 2ème lien pour effacer l'étoile affichée.

Bref, on peut se passer de ncurses, mais ce n'est de toutes façons pas trivial (avec ncurses ou pas, d'ailleurs), de gérer des "étoiles", au lieu de simplement ne rien renvoyer.


Dal
Messages postés
11066
Date d'inscription
samedi 5 mai 2007
Statut
Contributeur
Dernière intervention
18 octobre 2016
1 720
[Dal],
Tu oublies un détail.
Je suis d'accord pour gérer la touche backspace. Mais il faut le faire dans les deux cas (affichage des étoiles ou sans affichage). En effet, en mode raw, chaque backspace provoquera un caractère dans la chaîne de caractère.
Messages postés
5446
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
27 novembre 2020
914
Non, si seul l'écho est supprimé, le terminal fonctionne sans echo, mais avec le line buffering, et donc la touche backspace est gérée (comme la touche entrée) sans que tu aies à la gérer toi même (comme proposé dans le code sur SO, là https://stackoverflow.com/questions/1196418/getting-a-password-in-c-without-using-getpass-3).

Ce n'est que si tu veux "voir des étoiles", que tu dois supprimer le line buffering, en désactivant en plus le mode canonique, comme proposé dans mon code adapté là : https://forums.commentcamarche.net/forum/affich-27337373-masquer-mot-de-passe#13.


Dal
Messages postés
5446
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
27 novembre 2020
914
Salut aadilove, fiddy,

Voilà un exemple que j'ai pu tester sur une machine FreeBSD compilé avec gcc, à laquelle je me connecte avec un terminal émulé par Putty, adapté à la fois du premier lien posté dans mon message https://forums.commentcamarche.net/forum/affich-27337373-masquer-mot-de-passe#2 et du 2ème, mais sans utiliser ncurses.

Il devrait fonctionner sous Linux aussi. Voir cependant les remarques ci-après.

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

#define ENTER_KEY 10    
#define BACKSPACE_KEY 127    

int main(void)    
{    
    struct termios oflags, nflags;    
    char password[11];    
    char ch = ' ';    
    int n = 0;    

    /* disabling line buffering by disabling    
     * canonical mode, in addition to    
     * disabling echo */    
    tcgetattr(fileno(stdin), &oflags);    
    nflags = oflags;    
    nflags.c_lflag &= (~ICANON & ~ECHO);    
    nflags.c_lflag |= ECHONL;    

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

    printf("password (max len %lu): ",    
            sizeof(password) - 1);    

    do {    
        ch = getchar();    
        if ( (ch != BACKSPACE_KEY) &&    
                (ch != ENTER_KEY) &&    
                (n < sizeof(password) - 1) ) {    
            printf("*");    
            password[n] = ch;    
            password[n+1] = '\0';    
            n++;    
        } else if ( (ch == BACKSPACE_KEY) &&    
                (n > 0) ) {    
            printf("\b \b");    
            n--;    
            password[n] = '\0';    
        }    
    } while (ch != ENTER_KEY);    

    printf("You typed: %s\n", password);    

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

    return 0;    
}

La désactivation du line buffering permet de disposer de la touche pressée avec getchar() sans qu'il soit nécessaire de presser la touche entrée.

Le code proposé ci-dessus interdit aussi la saisie au delà de la capacité maximale de la chaîne password, gère backspace pour l'effacement des étoiles et entrée...

Note que le terminal peut être paramétré pour renvoyer autre chose que 127 (Ctrl-?) lorsque backspace est pressé. Ainsi, mon Putty me permet de paramétrer le terminal émulé en renvoyant Ctrl-H à la place.


Dal
Messages postés
5446
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
27 novembre 2020
914
Mais donc, c'est plus simple de se contenter d'annuler l'écho sur le terminal, pour ne pas avoir à afficher les étoiles et gérer tout ce qui en découle, et se contenter de faire comme décrit dans le premier lien posté :

https://stackoverflow.com/questions/1196418/getting-a-password-in-c-without-using-getpass-3

C'est aussi plus sûr, a priori, car une personne voyant l'écran ne pourra pas compter les étoiles, et en déduire le nombre de caractères composant le mot de passe.


Dal
Messages postés
11066
Date d'inscription
samedi 5 mai 2007
Statut
Contributeur
Dernière intervention
18 octobre 2016
1 720
c'est plus simple de se contenter d'annuler l'écho sur le terminal, pour ne pas avoir à afficher les étoiles et gérer tout ce qui en découle
En mode raw, le backspace affiche un caractère. Donc cela provoquera l'affichage d'une étoile. Mais cela reste cohérent avec l'entrée du caractère dans la chaîne de caractère. Si tu gères le backspace, tu devras le faire pour les deux variantes. Mais j'admets que cela sera un peu plus simple dans la variante sans affichage.

Pour la sûreté, je suis d'accord. Il n'y a pas photo :-).
Messages postés
5446
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
27 novembre 2020
914
En passant à la struct termios les paramètres appropriés, tu peux contrôler finement le comportement de la console, et définir dans le champ c_lflag que ECHO est retiré, tout en maintenant ICANON.

https://pubs.opengroup.org/onlinepubs/7908799/xsh/tcsetattr.html
https://pubs.opengroup.org/onlinepubs/7908799/xsh/termios.h.html

Cet extrait de man 3 tcflow est plus clair sur la question :

Canonical and noncanonical mode   
The  setting of the ICANON canon flag in c_lflag determines whether the   
terminal is operating in canonical mode (ICANON  set)  or  noncanonical   
mode (ICANON unset).  By default, ICANON set.   

In canonical mode:   

* Input  is  made  available  line by line.  An input line is available   
  when one of the line delimiters is typed (NL, EOL, EOL2;  or  EOF  at   
  the start of line).  Except in the case of EOF, the line delimiter is   
  included in the buffer returned by read(2).   

* Line editing is enabled (ERASE, KILL; and if the IEXTEN flag is  set:   
  WERASE,  REPRINT,  LNEXT).   A  read(2)  returns  at most one line of   
  input; if the read(2) requested fewer bytes than are available in the   
  current line of input, then only as many bytes as requested are read,   
  and the remaining characters will be available for a future read(2).   

In noncanonical mode input is available immediately (without  the  user   
having  to  type  a line-delimiter character), and line editing is disa   
abled.  

Donc, en conservant le "mode canonique", backspace, enter, etc., se comportent normalement, quand bien même l'écho est supprimé, car le terminal continue de traiter des lignes.

Sur la sécurité, c'est plus que de passer par la commande système stty (qui a le même degré de complexité), mais peut faire l'objet de tours de passe passe, comme montré dans ma proof of concept là https://forums.commentcamarche.net/forum/affich-27337373-masquer-mot-de-passe#24


Dal

... qui trouve que la lecture de ce topic commence à devenir compliquée.
Messages postés
25
Date d'inscription
dimanche 30 décembre 2012
Statut
Membre
Dernière intervention
20 juin 2013

Merci tout le monde pour vos propositions..Enfin de compte j'ai procédé de la manière suivante (sans afficher des '*') :
printf(" Passe : ");
system("stty -echo"); // aprés cette ligne tout caractère tapé sera caché
fgets(passe, sizeof(passe), stdin);
system("stty echo"); // on revient en mode normal
Messages postés
11066
Date d'inscription
samedi 5 mai 2007
Statut
Contributeur
Dernière intervention
18 octobre 2016
1 720
Bonne idée pour ne pas afficher les étoiles.
En revanche, l'utilisation de system("stty -echo"); est à bannir car cela pose des problèmes de sécurité et ce n'est même pas posix.
Mais si ces limites ne te dérangent pas, tu as encore plus simple avec la fonction getpass() qui fera ce que tu veux directement ;-).
Et pour info, attention avec fgets(), le '\n' sera stocké dans ta chaîne passe s'il y a la place.
Messages postés
5446
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
27 novembre 2020
914
Oui, comme dit fiddy faire appel à une commande externe n'est pas terrible.

Voilà ton code avec la correction sur la chaîne récupérée par fgets suggérée par fiddy :

$ cat aadilove.c 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main(void) 
{ 
    char passe[11]; 
    char *p; 

    printf(" Passe : "); 
    /* aprés cette ligne tout caractère tapé 
     * devrait être caché, sauf si un utilisateur 
     * a substitué la commande stty */ 
    system("stty -echo"); 
    fgets(passe, sizeof(passe), stdin); 
    if ((p = strchr(passe, '\n')) != NULL) 
        *p = '\0'; 
    /* retour en mode normal */ 
    system("stty echo"); 
    printf("\nVous avez tapé %s, mais rien " 
            "ne devais s'afficher à la saisie\n", passe); 

    return 0; 
}


Voilà une exécution "normale" de ce code :

$ gcc -Wall aadilove.c -o aadilove 
$ ./aadilove 
 Passe : 
Vous avez tapé toto, mais rien ne devais s'afficher à la saisie


Et voilà un exemple de ce qu'un utilisateur, même non privilégié, peut faire de ce code (ici, avec le shell sh - Bourne Shell, adapter pour un autre shell la façon dont les variables d'environnement sont manipulées) :

$ whereis stty 
stty: /bin/stty /usr/src/bin/stty 
$ echo $PATH 
/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin:/usr/X11R6/bin:/home/ccm/bin 
$ pwd 
/usr/home/ccm/temp/testcommandsub 
$ PATH=/usr/home/ccm/temp/testcommandsub:$PATH 
$ export PATH 
$ echo "echo 'coucou'" > stty ; chmod +x stty 
$ ./aadilove 
coucou 
 Passe : toto 
coucou 

Vous avez tapé toto, mais rien ne devais s'afficher à la saisie 

Il faudrait au minimum mettre le chemin complet de stty ("/bin/stty" dans mon cas) dans ta commande system. Ce n'est pas pratique, car, on pourrait imaginer qu'un système la place ailleurs. Ensuite, tu n'es pas à l'abri non plus que cette commande là soit remplacée par une autre qui fait des tours de passe-passe (cela sera plus difficile), ou des vulnérabilités éventuelles de cette commande.


Dal
Messages postés
11066
Date d'inscription
samedi 5 mai 2007
Statut
Contributeur
Dernière intervention
18 octobre 2016
1 720
Exactement la faille de sécurité à laquelle je pensais.

Il faudrait au minimum mettre le chemin complet de stty
Cela ne change rien ^^. Juste une 6 caractères à taper en plus (sans compter la touche entrée ^^) pour contourner l'appel à /bin/stty. Et on peut recommencer à jouer avec le PATH. Quoi que il me semble que cette ruse soit corrigée sur les noyaux supérieurs à 2.4. Il vaut mieux utiliser la famille exec().
Ou encore mieux, ton programme plus haut :-)