. .

C: Passwortabfrage im Terminal


Ich beschreibe hier kurz, wie unter Linux in der Konsole ein Passwort abgefragt werden kann, ohne dass die Eingabe des Users im Terminal erscheint.

Hierzu Definitionen im Header-File passphrase.h:

#ifndef PRJ_PASSPHRASE_H
#define PRJ_PASSPHRASE_H 1

#if defined(__cplusplus)
extern "C" {
#endif

char *
prj_read_passphrase(size_t size);

int
prj_get_passphrase(size_t count, size_t size, char **passphrase);

#if defined(__cplusplus)
}
#endif

#endif /* !PRJ_PASSPHRASE_H */

Daraufhin der eigentliche Code in passphrase.c:

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

#include "passphrase.h"

/*
 * \brief   prj_read_passphrase
 *
 * reads from stdin input of user
 *
 * \param   size            maximum length of input
 *
 * \return                  a char array containing input of user
 */
char *
prj_read_passphrase(size_t size) {
    char password_input[size + 1]; 
    char *password = NULL;
    int ch, i;

    for (i = 0; (i < (int) size) && ((ch = getchar()) != EOF) && (ch != '\n') && (ch != '\r'); i++) {
        if (ch == 127 || ch == 8) { /* DEL or BS */
            if (i > 0)
                i = i - 2;
            else
                i = -1; 
        } else if (ch < 33) /* of course no control characters allowed */
            i--;
        else
            password_input[i] = (char) ch; 
    }   
    password_input[i] = '\0'; /* last given hidden character is broken */

    i++;

    password = (char *) malloc(sizeof(char) * i); 
    memcpy(password, password_input, (size_t) i); 
    memset(password_input, 0, (size_t) (i - 1));

    return password;
}

/*
 * \brief   prj_get_passphrase
 *
 * user interface for getting passphrase given by user on terminal
 *
 * \param   count           asking for passphrase one or two times
 * \param   size            maximum length of passphrase allowed
 * \param   passphrase      on success given passphrase is stored here, otherwise NULL
 *
 * \return                  on technical error -1, otherwise 0
 */
int
prj_get_passphrase(size_t count, size_t size, char **passphrase) {
    size_t j, x = 1;
    char *pass_first = NULL, *pass_second = NULL;
    size_t len_first = 0, len_second = 0;
    struct termios oldState, newState;

    if (tcgetattr(STDIN_FILENO, &oldState) == -1) {
        printf("\nError: could not hide terminal input!\n");
        return -1; 
    }   
    newState = oldState;
    newState.c_lflag &= ~(ICANON | ECHO);

    if (tcsetattr(STDIN_FILENO, TCSANOW, &newState) == -1) {
        printf("\nError: could not hide terminal input!\n");
        return -1; 
    }   

    if (count != 1) /* default is asking two times */
        count = 2;

retry:
    if (x > 3) /* three chances */
        goto failed;

    if (x > 1)
        printf("Passphrase mismatch. Please try it again.\n\n");

    x++;
    for (j = 0; j < count; j++) {
        if (j == 0) {
            printf("Please enter your passphrase: ");
            pass_first = prj_read_passphrase(size);
        } else {
            printf("Please re-enter your passphrase: ");
            pass_second = prj_read_passphrase(size);
        }
        printf("\n");
    }

    if (pass_first == NULL)
        goto retry;

    len_first = strlen(pass_first);

    if (pass_first != NULL && pass_second != NULL && count == 2) {
        len_second = strlen(pass_second);

        if (len_first != len_second)
            goto retry;

        if (memcmp(pass_first, pass_second, len_first) != 0)
            goto retry;
    }
    len_first++;

    *passphrase = (char *) malloc(sizeof(char) * len_first);
    memcpy(*passphrase, pass_first, len_first);

failed:
    if (tcsetattr(STDIN_FILENO, TCSANOW, &oldState) == -1) {
        printf("\nError: could not unhide terminal input!\n");
        printf("\nPlease try to reset your terminal by typing command 'reset -x'\n");
    }

    if (pass_first != NULL) {
        memset(pass_first, 0, len_first--);
        free(pass_first);
    }

    if (pass_second != NULL) {
        memset(pass_second, 0, len_second);
        free(pass_second);
    }

    return 0;
}

Jetzt kann die Funktionen prj_get_passphrase() wie in diesem Beispiel verwendet werden (get_passphrase.c):

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

#include "passphrase.h"

#define GPG_MAX_PASSPHRASE_LENGTH 100

/* ********************************************************************** */

int
main(int argc, char *argv[]) {
    (void) argc; /* avoid compiler warnings */
    (void) argv;

    char *passphrase = NULL;

    if (prj_get_passphrase(2, GPG_MAX_PASSPHRASE_LENGTH + 1, &passphrase) != 0) {
        printf("An error occured. Aborting.\n");
        return 1;
    }   

    if (passphrase == NULL) {
        printf("An error occured. Aborting.\n");
        return 1;
    }   

    printf("\nYour passphrase: '%s'\n", passphrase);

    memset(passphrase, 0, strlen(passphrase)); /* overwrite passphrase in memory */
    free(passphrase);

    return 0;
}

Danach kann wie gewohnt das Binary mit zum Beispiel gcc erstellt werden:

gcc -Wall -Wextra -Werror -o get_passphrase passphrase.c get_passphrase.c

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>