GNU/Linux >> Linux Esercitazione >  >> Linux

Nascondi l'immissione della password sul terminale

Senza getch fare affidamento ed evitare l'obsoleto getpass , l'approccio consigliato è disabilitare il terminale ECHO tramite termios uso. Dopo alcune ricerche per trovare una routine di password flessibile predefinita, sono rimasto sorpreso dal fatto che pochissimi per l'uso autonomo con C. Piuttosto che semplicemente ricodificare getch con termios c_lflag opzioni, un approccio leggermente più generalizzato richiede solo alcune aggiunte. Oltre a sostituire getch qualsiasi routine dovrebbe imporre una lunghezza massima specificata per impedire l'overflow, troncare se l'utente tenta di entrare oltre il massimo e avvisare se il troncamento si verifica in qualche modo.

Di seguito, le aggiunte consentiranno la lettura da qualsiasi FILE * flusso di input, limitando la lunghezza a una lunghezza specificata, fornisce una capacità di modifica minima (backspace) durante l'acquisizione dell'input, consente di specificare o disabilitare completamente la maschera dei caratteri e infine restituisce la lunghezza della password immessa. È stato aggiunto un avviso quando la password immessa è stata troncata alla lunghezza massima o specificata.

Si spera che si dimostri utile ad altri con questa domanda alla ricerca di una soluzione simile:

#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 semplice programma che mostra l'uso sarebbe il seguente. Se utilizzi un array statico di caratteri per contenere la password, assicurati solo che venga passato un puntatore alla funzione.

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

Risultato di esempio

$ ./bin/getpasswd2

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

 Enter password:
 you entered   : abcdef  (6 chars)

Nel mondo Linux, il mascheramento di solito non viene eseguito con asterischi, normalmente l'eco viene semplicemente disattivato e il terminale visualizza spazi vuoti, ad es. se usi su o accedere a un terminale virtuale ecc.

C'è una funzione di libreria per gestire l'ottenimento delle password, non maschererà la password con asterischi ma disabiliterà l'eco della password al terminale. L'ho estratto da un libro su Linux che ho. Credo che faccia parte dello standard posix

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

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

La funzione getpass() prima disabilita l'eco e tutta l'elaborazione dei caratteri speciali del terminale (come il carattere di interruzione, normalmente Control-C).

Quindi stampa la stringa puntata dal prompt e legge una riga di input, restituendo la stringa di input con terminazione null con il newline finale rimosso, come risultato della funzione.

Una ricerca su Google per getpass() ha un riferimento all'implementazione GNU (dovrebbe essere presente nella maggior parte delle distribuzioni Linux) e alcuni esempi di codice per implementare la tua, se necessario

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

Il loro esempio per rotolare il tuo:

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

Se necessario, puoi usarlo come base per modificarlo per visualizzare gli asterischi.


Linux
  1. Bash può scrivere sul proprio flusso di input?

  2. Come nascondere l'output del terminale durante l'esecuzione di un comando?

  3. | In Comando Terminale?

  4. Accedere a Mysql utilizzando il terminale in Ubuntu 13.04?

  5. Terminale Ubuntu

Gestisci le tue password nel terminale Linux

Come visualizzare gli asterischi quando si digita la password nel terminale

Come rendere visibili gli asterischi delle password nel terminale di Ubuntu

Come trovare la password WiFi salvata in Linux Mint utilizzando la GUI o il terminale

Terminale di compensazione

Come nascondere una password passata come argomento della riga di comando?