Blame src/getpass.c

Packit Service 31306d
/*
Packit Service 31306d
 * getpass.c - platform independent getpass function.
Packit Service 31306d
 *
Packit Service 31306d
 * This file is part of the SSH Library
Packit Service 31306d
 *
Packit Service 31306d
 * Copyright (c) 2011-2013    by Andreas Schneider <mail@cryptomilk.org>
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is free software; you can redistribute it and/or modify
Packit Service 31306d
 * it under the terms of the GNU Lesser General Public License as published by
Packit Service 31306d
 * the Free Software Foundation; either version 2.1 of the License, or (at your
Packit Service 31306d
 * option) any later version.
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is distributed in the hope that it will be useful, but
Packit Service 31306d
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit Service 31306d
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
Packit Service 31306d
 * License for more details.
Packit Service 31306d
 *
Packit Service 31306d
 * You should have received a copy of the GNU Lesser General Public License
Packit Service 31306d
 * along with the SSH Library; see the file COPYING.  If not, write to
Packit Service 31306d
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
Packit Service 31306d
 * MA 02111-1307, USA.
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
#include "config.h"
Packit Service 31306d
Packit Service 31306d
#include <stdio.h>
Packit Service 31306d
#include <string.h>
Packit Service 31306d
#include <stdlib.h>
Packit Service 31306d
Packit Service 31306d
#include <libssh/priv.h>
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 *
Packit Service 31306d
 * @brief Get the password from the console.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  prompt   The prompt to display.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  buf      The buffer to fill.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  len      The length of the buffer.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  verify   Should the password be verified?
Packit Service 31306d
 *
Packit Service 31306d
 * @return              1 on success, 0 on error.
Packit Service 31306d
 */
Packit Service 31306d
static int ssh_gets(const char *prompt, char *buf, size_t len, int verify) {
Packit Service 31306d
    char *tmp;
Packit Service 31306d
    char *ptr = NULL;
Packit Service 31306d
    int ok = 0;
Packit Service 31306d
Packit Service 31306d
    tmp = calloc(1, len);
Packit Service 31306d
    if (tmp == NULL) {
Packit Service 31306d
        return 0;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* read the password */
Packit Service 31306d
    while (!ok) {
Packit Service 31306d
        if (buf[0] != '\0') {
Packit Service 31306d
            fprintf(stdout, "%s[%s] ", prompt, buf);
Packit Service 31306d
        } else {
Packit Service 31306d
            fprintf(stdout, "%s", prompt);
Packit Service 31306d
        }
Packit Service 31306d
        fflush(stdout);
Packit Service 31306d
        if (fgets(tmp, len, stdin) == NULL) {
Packit Service 31306d
            free(tmp);
Packit Service 31306d
            return 0;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if ((ptr = strchr(tmp, '\n'))) {
Packit Service 31306d
            *ptr = '\0';
Packit Service 31306d
        }
Packit Service 31306d
        fprintf(stdout, "\n");
Packit Service 31306d
Packit Service 31306d
        if (*tmp) {
Packit Service 31306d
            strncpy(buf, tmp, len);
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (verify) {
Packit Service 31306d
            char *key_string;
Packit Service 31306d
Packit Service 31306d
            key_string = calloc(1, len);
Packit Service 31306d
            if (key_string == NULL) {
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            fprintf(stdout, "\nVerifying, please re-enter. %s", prompt);
Packit Service 31306d
            fflush(stdout);
Packit Service 31306d
            if (! fgets(key_string, len, stdin)) {
Packit Service 31306d
                explicit_bzero(key_string, len);
Packit Service 31306d
                SAFE_FREE(key_string);
Packit Service 31306d
                clearerr(stdin);
Packit Service 31306d
                continue;
Packit Service 31306d
            }
Packit Service 31306d
            if ((ptr = strchr(key_string, '\n'))) {
Packit Service 31306d
                *ptr = '\0';
Packit Service 31306d
            }
Packit Service 31306d
            fprintf(stdout, "\n");
Packit Service 31306d
            if (strcmp(buf, key_string)) {
Packit Service 31306d
                printf("\n\07\07Mismatch - try again\n");
Packit Service 31306d
                explicit_bzero(key_string, len);
Packit Service 31306d
                SAFE_FREE(key_string);
Packit Service 31306d
                fflush(stdout);
Packit Service 31306d
                continue;
Packit Service 31306d
            }
Packit Service 31306d
            explicit_bzero(key_string, len);
Packit Service 31306d
            SAFE_FREE(key_string);
Packit Service 31306d
        }
Packit Service 31306d
        ok = 1;
Packit Service 31306d
    }
Packit Service 31306d
    explicit_bzero(tmp, len);
Packit Service 31306d
    free(tmp);
Packit Service 31306d
Packit Service 31306d
    return ok;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#ifdef _WIN32
Packit Service 31306d
#include <windows.h>
Packit Service 31306d
Packit Service 31306d
int ssh_getpass(const char *prompt,
Packit Service 31306d
                char *buf,
Packit Service 31306d
                size_t len,
Packit Service 31306d
                int echo,
Packit Service 31306d
                int verify) {
Packit Service 31306d
    HANDLE h;
Packit Service 31306d
    DWORD mode = 0;
Packit Service 31306d
    int ok;
Packit Service 31306d
Packit Service 31306d
    /* fgets needs at least len - 1 */
Packit Service 31306d
    if (prompt == NULL || buf == NULL || len < 2) {
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* get stdin and mode */
Packit Service 31306d
    h = GetStdHandle(STD_INPUT_HANDLE);
Packit Service 31306d
    if (!GetConsoleMode(h, &mode)) {
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* disable echo */
Packit Service 31306d
    if (!echo) {
Packit Service 31306d
        if (!SetConsoleMode(h, mode & ~ENABLE_ECHO_INPUT)) {
Packit Service 31306d
            return -1;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    ok = ssh_gets(prompt, buf, len, verify);
Packit Service 31306d
Packit Service 31306d
    /* reset echo */
Packit Service 31306d
    SetConsoleMode(h, mode);
Packit Service 31306d
Packit Service 31306d
    if (!ok) {
Packit Service 31306d
        explicit_bzero(buf, len);
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* force termination */
Packit Service 31306d
    buf[len - 1] = '\0';
Packit Service 31306d
Packit Service 31306d
    return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#else
Packit Service 31306d
Packit Service 31306d
#include <fcntl.h>
Packit Service 31306d
#ifdef HAVE_TERMIOS_H
Packit Service 31306d
#include <termios.h>
Packit Service 31306d
#endif
Packit Service 31306d
#ifdef HAVE_UNISTD_H
Packit Service 31306d
#include <unistd.h>
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @ingroup libssh_misc
Packit Service 31306d
 *
Packit Service 31306d
 * @brief Get a password from the console.
Packit Service 31306d
 *
Packit Service 31306d
 * You should make sure that the buffer is an empty string!
Packit Service 31306d
 *
Packit Service 31306d
 * You can also use this function to ask for a username. Then you can fill the
Packit Service 31306d
 * buffer with the username and it is shows to the users. If the users just
Packit Service 31306d
 * presses enter the buffer will be untouched.
Packit Service 31306d
 *
Packit Service 31306d
 * @code
Packit Service 31306d
 *   char username[128];
Packit Service 31306d
 *
Packit Service 31306d
 *   snprintf(username, sizeof(username), "john");
Packit Service 31306d
 *
Packit Service 31306d
 *   ssh_getpass("Username:", username, sizeof(username), 1, 0);
Packit Service 31306d
 * @endcode
Packit Service 31306d
 *
Packit Service 31306d
 * The prompt will look like this:
Packit Service 31306d
 *
Packit Service 31306d
 *   Username: [john]
Packit Service 31306d
 *
Packit Service 31306d
 * If you press enter then john is used as the username, or you can type it in
Packit Service 31306d
 * to change it.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  prompt   The prompt to show to ask for the password.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] buf    The buffer the password should be stored. It NEEDS to be
Packit Service 31306d
 *                      empty or filled out.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  len      The length of the buffer.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  echo     Should we echo what you type.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  verify   Should we ask for the password twice.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              0 on success, -1 on error.
Packit Service 31306d
 */
Packit Service 31306d
int ssh_getpass(const char *prompt,
Packit Service 31306d
                char *buf,
Packit Service 31306d
                size_t len,
Packit Service 31306d
                int echo,
Packit Service 31306d
                int verify) {
Packit Service 31306d
    struct termios attr;
Packit Service 31306d
    struct termios old_attr;
Packit Service 31306d
    int ok = 0;
Packit Service 31306d
    int fd = -1;
Packit Service 31306d
Packit Service 31306d
    /* fgets needs at least len - 1 */
Packit Service 31306d
    if (prompt == NULL || buf == NULL || len < 2) {
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (isatty(STDIN_FILENO)) {
Packit Service 31306d
        ZERO_STRUCT(attr);
Packit Service 31306d
        ZERO_STRUCT(old_attr);
Packit Service 31306d
Packit Service 31306d
        /* get local terminal attributes */
Packit Service 31306d
        if (tcgetattr(STDIN_FILENO, &attr) < 0) {
Packit Service 31306d
            perror("tcgetattr");
Packit Service 31306d
            return -1;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /* save terminal attributes */
Packit Service 31306d
        memcpy(&old_attr, &attr, sizeof(attr));
Packit Service 31306d
        if((fd = fcntl(0, F_GETFL, 0)) < 0) {
Packit Service 31306d
            perror("fcntl");
Packit Service 31306d
            return -1;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /* disable echo */
Packit Service 31306d
        if (!echo) {
Packit Service 31306d
            attr.c_lflag &= ~(ECHO);
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /* write attributes to terminal */
Packit Service 31306d
        if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) < 0) {
Packit Service 31306d
            perror("tcsetattr");
Packit Service 31306d
            return -1;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* disable nonblocking I/O */
Packit Service 31306d
    if (fd & O_NDELAY) {
Packit Service 31306d
        fcntl(0, F_SETFL, fd & ~O_NDELAY);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    ok = ssh_gets(prompt, buf, len, verify);
Packit Service 31306d
Packit Service 31306d
    if (isatty(STDIN_FILENO)) {
Packit Service 31306d
        /* reset terminal */
Packit Service 31306d
        tcsetattr(STDIN_FILENO, TCSANOW, &old_attr);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* close fd */
Packit Service 31306d
    if (fd & O_NDELAY) {
Packit Service 31306d
        fcntl(0, F_SETFL, fd);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (!ok) {
Packit Service 31306d
        explicit_bzero(buf, len);
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* force termination */
Packit Service 31306d
    buf[len - 1] = '\0';
Packit Service 31306d
Packit Service 31306d
    return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#endif