Saltar al contenido

Ocultar la entrada de contraseña en el terminal

Solución:

En el mundo de Linux, el enmascaramiento generalmente no se hace con asteriscos, normalmente el eco simplemente se apaga y el terminal muestra espacios en blanco. su o inicie sesión en una terminal virtual, etc.

Hay una función de biblioteca para manejar la obtención de contraseñas, no enmascarará la contraseña con asteriscos pero deshabilitará el eco de la contraseña en el terminal. Saqué esto de un libro de Linux que tengo. Creo que es parte del estándar posix.

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

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

La función getpass () primero deshabilita el eco y todo el procesamiento de los caracteres especiales del terminal (como el carácter de interrupción, normalmente Control-C).

Luego imprime la cadena apuntada por el indicador y lee una línea de entrada, devolviendo la cadena de entrada terminada en nulo con el salto de línea final eliminado, como resultado de su función.

Una búsqueda en Google de getpass () tiene una referencia a la implementación de GNU (debería estar en la mayoría de las distribuciones de Linux) y algún código de muestra para implementar el suyo si es necesario.

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

Su ejemplo para rodar el tuyo:

#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 es necesario, puede usar esto como base para modificarlo para mostrar asteriscos.

Sin getch en el que confiar y evitar lo obsoleto getpass, el enfoque recomendado es deshabilitar el terminal ECHO a través de termios usar. Después de algunas búsquedas para encontrar una rutina de contraseña flexible enlatada, me sorprendió que muy pocas para uso independiente con C. En lugar de simplemente recodificar getch con termios c_lflag opciones, un enfoque un poco más generalizado requiere solo algunas adiciones. Más allá de reemplazar getch cualquier rutina debe imponer una longitud máxima especificada para evitar el desbordamiento, truncar si el usuario intenta ingresar más allá del máximo y advertir si se produce un truncamiento de alguna manera.

A continuación, las adiciones permitirán leer desde cualquier FILE * flujo de entrada, que limita la longitud a una longitud especificada, proporciona una capacidad de edición mínima (retroceso) al tomar la entrada, permite que la máscara de caracteres se especifique o deshabilite por completo y, finalmente, devuelva la longitud de la contraseña ingresada. Se agregó una advertencia cuando la contraseña ingresada se truncó a la longitud máxima o especificada.

Con suerte, resultará útil para otros con esta pregunta que buscan una solución similar:

#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 programa simple que muestre el uso sería el siguiente. Si usa una matriz estática de caracteres para mantener la contraseña, solo asegúrese de que se pase un puntero a la función.

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)nn", p, nchr);

    return 0;
}

Salida de ejemplo

$ ./bin/getpasswd2

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

 Enter password:
 you entered   : abcdef  (6 chars)

La funcionalidad de getch (que es una función de Windows no estándar) se puede emular con este código:

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

Tenga en cuenta que su enfoque no es perfecto; es mejor usar algo como maldiciones u otra biblioteca de terminal para manejar estas cosas.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)


Tags : / /

Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *