web-dev-qa-db-fra.com

Masquer la saisie du mot de passe sur le terminal

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

#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 n'inclut pas le fichier conio.h donc, getch() est inutile pour moi. Quelqu'un a-t-il une solution?

51
Hit's

Dans le monde Linux, le masquage ne se fait généralement pas avec des astérisques, normalement l'écho est simplement désactivé et le terminal affiche des blancs Par exemple. si vous utilisez su ou vous connectez à un terminal virtuel, etc.

Il existe une fonction de bibliothèque pour gérer l'obtention des mots de passe, elle ne masquera pas le mot de passe avec des astérisques mais désactivera l'écho du mot de passe sur le terminal. Je l'ai retiré d'un livre Linux que j'ai. Je crois que cela fait partie de la norme 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 d'abord l'écho et tout traitement des 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, renvoyant la chaîne d'entrée terminée par le null avec la nouvelle ligne de fin supprimée, comme résultat de sa fonction.

Une recherche Google pour getpass () a une référence à l'implémentation GNU (devrait être dans la plupart des distributions Linux) et un exemple de code pour implémenter la vôtre si besoin est

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

Leur exemple pour rouler le vôtre:

#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 l'utiliser comme base pour le modifier afin d'afficher des astérisques.

45
matt

Sans getch sur lequel s'appuyer et en évitant le getpass obsolète, l'approche recommandée consiste à désactiver le terminal ECHO via termios. Après quelques recherches pour trouver une routine de mot de passe flexible en conserve, j'ai été surpris que très peu pour une utilisation autonome avec C. Plutôt que de simplement recoder getch avec termios c_lflag options, l'approche légèrement plus généralisée ne nécessite que quelques ajouts. Au-delà du remplacement de getch, toute routine doit appliquer une longueur maximale spécifiée pour éviter le débordement, tronquer si l'utilisateur tente d'entrer au-delà du maximum et avertir si la troncature se produit d'une manière ou d'une autre.

Ci-dessous, les ajouts permettront la lecture de tout FILE * le flux d'entrée, limitant la longueur à une longueur spécifiée, offre une capacité d'édition minimale (retour arrière) lors de la prise de saisie, permet de spécifier ou de désactiver complètement le masque de caractères, et finalement de renvoyer la longueur du mot de passe entré. Un avertissement a été ajouté lorsque le mot de passe saisi a été tronqué à la longueur maximale ou spécifiée.

Espérons que cela se révélera utile aux autres avec cette question à la recherche d'une solution similaire:

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

#include <sys/time.h>
#include <termios.h>
#include <errno.h>   /* for errno */
#include <unistd.h>  /* for EINTR */

#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 = 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    */
}

Un programme simple montrant l'utilisation serait le suivant. Si vous utilisez un tableau statique de caractères pour conserver le mot de passe, assurez-vous simplement qu'un pointeur est passé à la fonction.

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

Exemple de sortie

$ ./bin/getpasswd2

 Enter password: ******
 you entered   : 123456  (6 chars)

 Enter password:
 you entered   : abcdef  (6 chars)
9
David C. Rankin

La fonctionnalité de getch (qui est une fonction Windows non standard) 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 vaut mieux utiliser quelque chose comme ncurses ou une autre bibliothèque de terminaux pour gérer ces choses.

9
Delan Azabani

Vous pouvez créer votre propre fonction getch() sous 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 de démonstration:

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;
}
6
Susam Pal

Votre méthode est correcte, mais vous devrez 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?

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

Copiez simplement ces extraits et utilisez-les. J'espère que cela a aidé

2
niko

Merci à vous tous dont l'aide et le soutien pour résoudre mon problème. Je trouve le meilleur moyen de cacher mon mot de passe sous Linux qui me convient le mieux. Pour utiliser la fonction getpass (). Il suffit d'inclure le fichier "unistd.h".

syntex de la fonction getpass:

char * getpass (const char * Prompt)

Paramètres: Invite: pointeur de chaîne à imprimer lors de la demande de mot de passe

Valeur de retour: pointeur de chaîne du mot de passe

Exemple:

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

sortie:

Entrer le mot de passe:

heet

2
Hit's

Vous pouvez utiliser ncurses.h s'il n'est pas nécessaire d'être portable sur Windows pour cela, mais voici une sorte de version plus "portable":

S'il n'est pas nécessaire d'être portable, indiquez-nous une solution ncurses

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

Et le fichier c

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

Cela devrait correspondre à votre problème.

J'espère que ça t'as aidé.

2
Daniel Leschkowski

Malheureusement, dans la bibliothèque standard C, il n'y a pas une telle fonction prête à l'emploi. Peut-être dans une bibliothèque tierce.

Une option consiste à utiliser des séquences d'échappement ANSI pour définir la couleur d'arrière-plan sur la couleur de premier plan dans la console pour masquer le mot de passe. Essayez ce lien .

0
Constantinius

En C, vous pouvez utiliser la fonction getpasswd() qui fait à peu près la même chose que stty dans Shell, exemple:

#include <stdio.h>
#include <string.h>
#include <pwd.h>
#include <unistd.h>

int main()
{
    char acct[80], password[80];

    printf(“Account: “);
    fgets(acct, 80, stdin);

    acct[strlen(acct)-1] = 0; /* remove carriage return */

    strncpy(password, getpass(“Password: “), 80);
    printf(“You entered acct %s and pass %s\n”, acct, password);

    return 0;
}

Voici un script Shell équivalent qui utilise stty (qui modifie les paramètres de votre tty):

save_state=$(stty -g)
/bin/echo -n “Account: “
read acct
/bin/echo -n “Password: “
stty -echo
read password # this won’t echo
stty “$save_state”
echo “”
echo account = $acct and password = $password

Source: Comment puis-je lire un mot de passe sans l'écho en C?

0
kenorb

homme getpass

Cette fonction est obsolète. Ne l'utilise pas. Si vous souhaitez lire l'entrée sans que l'écho du terminal ne soit activé, consultez la description de l'indicateur ECHO dans termios (3)

# include <termios.h>
# include <unistd.h>   /* needed for STDIN_FILENO which is an int file descriptor */

struct termios tp, save;

tcgetattr( STDIN_FILENO, &tp);              /* get existing terminal properties */
save = tp;                                  /* save existing terminal properties */

tp.c_lflag &= ~ECHO;                        /* only cause terminal echo off */

tcsetattr( STDIN_FILENO, TCSAFLUSH, &tp );  /* set terminal settings */

/*
   now input by user in terminal will not be displayed
   and cursor will not move
*/

tcsetattr( STDIN_FILENO, TCSANOW, &save);   /* restore original terminal settings */

Si vous remarquez, la plupart des distributions Linux actuelles ne masquent pas un mot de passe avec des astérisques. Cela divulgue la longueur du mot de passe, ce qui n'est aucunement bénéfique. Il est plus facile et préférable de simplement faire en sorte que le curseur ne bouge pas lorsqu'un mot de passe est saisi. Si, pour une raison quelconque, vous avez besoin d'un * pour être imprimé pour chaque caractère tapé, vous devrez alors saisir chaque pression de touche avant de frapper Enter et cela a toujours été problématique.

0
ron

En scannant les personnages, vous pouvez les mettre dans un tampon. Vous devez également écrire du code si vous appuyez sur la touche de retour arrière et corriger correctement le mot de passe inséré.

Voici un code que j'ai écrit avec les malédictions. Compiler avec gcc file.c -o pass_prog -lcurses

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

#define ENOUGH_SIZE 256

#define ECHO_ON 1
#define ECHO_OFF 0

#define BACK_SPACE 127

char *my_getpass (int echo_state);

int main (void)
{
  char *pass;

  initscr ();

  printw ("Enter Password: ");
  pass = my_getpass (ECHO_ON);

  printw ("\nEntered Password: %s", pass);
  refresh ();
  getch ();
  endwin ();
  return 0;
}


char *my_getpass (int echo_state)
{
  char *pass, c;
  int i=0;

  pass = malloc (sizeof (char) * ENOUGH_SIZE);
  if (pass == NULL)
  {
    perror ("Exit");
    exit (1);
  }

  cbreak ();
  noecho ();

  while ((c=getch()) != '\n')
  {
    if (c == BACK_SPACE)
    {
      /* Do not let the buffer underflow */
      if (i > 0)
      { 
        i--;
        if (echo_state == ECHO_ON)
               printw ("\b \b");
      }
    }
    else if (c == '\t')
      ; /* Ignore tabs */
    else
    {
      pass[i] = c;
      i = (i >= ENOUGH_SIZE) ? ENOUGH_SIZE - 1 : i+1;
      if (echo_state == ECHO_ON)
        printw ("*");
    }
  }
  echo ();
  nocbreak ();
  /* Terminate the password string with NUL */
  pass[i] = '\0';
  endwin ();
  return pass;
}
0
phoxis