GNU/Linux >> Tutoriales Linux >  >> Linux

Ocultar entrada de contraseña en la terminal

Sin getch confiar y evitar el 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 fueran 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 específica para evitar el desbordamiento, truncar si el usuario intenta ingresar más allá del máximo y advertir si se produce el truncamiento de alguna manera.

A continuación, las adiciones permitirán leer desde cualquier FILE * el flujo de entrada, que limita la longitud a una longitud específica, proporciona una capacidad de edición mínima (retroceso) al ingresar, permite que la máscara de caracteres se especifique o deshabilite por completo y, finalmente, devuelve 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, será ú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 guardar la contraseña, solo asegúrese de pasar 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)\n\n", p, nchr);

    return 0;
}

Ejemplo de salida

$ ./bin/getpasswd2

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

 Enter password:
 you entered   : abcdef  (6 chars)

En el mundo de Linux, el enmascaramiento generalmente no se realiza con asteriscos, normalmente el eco simplemente se desactiva y la terminal muestra espacios en blanco, p. si usas 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 la 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 caracteres especiales terminales (como el carácter de interrupción, normalmente Control-C).

Luego imprime la cadena a la que apunta el indicador y lee una línea de entrada, devolviendo la cadena de entrada terminada en nulo con la nueva línea final eliminada, 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 un código de muestra para implementar el suyo propio 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 y modificarlo para mostrar asteriscos.


Linux
  1. ¿Puede Bash escribir en su propio flujo de entrada?

  2. | ¿En Comando Terminal?

  3. ¿Accediendo a Mysql usando Terminal en Ubuntu 13.04?

  4. Terminal de Ubuntu

  5. Eliminar el historial de terminales en Linux

Administra tus contraseñas en la terminal de Linux

Cómo mostrar asteriscos cuando escribe una contraseña en la terminal

Cómo hacer visibles los asteriscos de contraseña en la terminal de Ubuntu

Cómo encontrar la contraseña WiFi guardada en Linux Mint usando GUI o terminal

Terminal de compensación

¿Cómo ocultar una contraseña pasada como argumento de línea de comando?