GNU/Linux >> Tutoriels Linux >  >> Linux

Masquer la saisie du mot de passe sur le terminal

Sans getch s'appuyer et éviter l'obsolète getpass , l'approche recommandée consiste à désactiver le terminal ECHO via termios utilisation. Après quelques recherches pour trouver une routine de mot de passe flexible prédéfinie, j'ai été surpris qu'il y en ait très peu pour une utilisation autonome avec C. Plutôt que de simplement recoder getch avec les termes c_lflag options, une 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 troncation se produit d'une manière ou d'une autre.

Ci-dessous, les ajouts permettront de lire à partir de n'importe quel FILE * flux d'entrée, limitant la longueur à une longueur spécifiée, fournir une capacité d'édition minimale (retour arrière) lors de la prise d'entrée, permettre au masque de caractères d'être spécifié ou désactivé complètement, et enfin renvoyer la longueur du mot de passe saisi. Un avertissement a été ajouté lorsque le mot de passe saisi a été tronqué à la longueur maximale ou spécifiée.

J'espère que cela s'avérera utile à d'autres avec cette question à la recherche d'une solution similaire :

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

Un programme simple montrant l'utilisation serait le suivant. Si vous utilisez un tableau statique de caractères pour contenir 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)

Dans le monde Linux, le masquage n'est généralement pas fait avec des astérisques, normalement l'écho est simplement désactivé et le terminal affiche des blancs. si vous utilisez su ou connectez-vous à 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 au terminal. J'ai tiré cela 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 l'invite et lit une ligne d'entrée, renvoyant la chaîne d'entrée terminée par un caractère nul avec la nouvelle ligne de fin supprimée, comme résultat de sa fonction.

Une recherche Google pour getpass() contient une référence à l'implémentation GNU (devrait être dans la plupart des distributions Linux) et un exemple 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 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 besoin est, vous pouvez l'utiliser comme base en le modifiant pour afficher des astérisques.


Linux
  1. Connectez-vous à Linux à partir de Mac OS X en utilisant Terminal

  2. Terminal Ubuntu

  3. Supprimer l'historique du terminal sous Linux

  4. Récupération du mot de passe racine

  5. Comment masquer un mot de passe passé en argument de ligne de commande ?

Gérez vos mots de passe dans le terminal Linux

Comment afficher des astérisques lorsque vous tapez un mot de passe dans un terminal

Comment rendre les astérisques de mot de passe visibles dans le terminal Ubuntu

Comment trouver un mot de passe WiFi enregistré dans Linux Mint à l'aide d'une interface graphique ou d'un terminal

Borne de dédouanement

Serveur Ubuntu :Je ne vois pas mon entrée dans le terminal