diff options
author | Andreas Schneider <asn@cryptomilk.org> | 2011-01-23 20:08:17 +0100 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2011-01-24 13:55:05 +0100 |
commit | 50a119dd0ac55763f965ba1660c132c2f58ed167 (patch) | |
tree | b698203a7da30551f0a6fe44c76bdfe66fb81097 | |
parent | 8abdaa7abf64b67ac6ca04e2d5fee84ebec47691 (diff) | |
download | libssh-50a119dd0ac55763f965ba1660c132c2f58ed167.tar.gz libssh-50a119dd0ac55763f965ba1660c132c2f58ed167.tar.xz libssh-50a119dd0ac55763f965ba1660c132c2f58ed167.zip |
misc: Added multiplatform ssh_getpass() fuction.
-rw-r--r-- | include/libssh/libssh.h | 3 | ||||
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/getpass.c | 265 |
3 files changed, 269 insertions, 0 deletions
diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h index 2dbdb7e..93d6dba 100644 --- a/include/libssh/libssh.h +++ b/include/libssh/libssh.h @@ -468,6 +468,9 @@ LIBSSH_API ssh_string ssh_string_new(size_t size); LIBSSH_API char *ssh_string_to_char(ssh_string str); LIBSSH_API void ssh_string_free_char(char *s); +LIBSSH_API int ssh_getpass(const char *prompt, char *buf, size_t len, int echo, + int verify); + #ifndef LIBSSH_LEGACY_0_4 #include "libssh/legacy.h" #endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d9adb02..2b47853 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -86,6 +86,7 @@ set(libssh_SRCS crypt.c dh.c error.c + getpass.c gcrypt_missing.c gzip.c init.c diff --git a/src/getpass.c b/src/getpass.c new file mode 100644 index 0000000..f0b8283 --- /dev/null +++ b/src/getpass.c @@ -0,0 +1,265 @@ +/* + * getpass.c - platform independent getpass function. + * + * This file is part of the SSH Library + * + * Copyright (c) 2011 by Andreas Schneider <mail@cryptomilk.org> + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include <stdio.h> +#include <string.h> + +#include <libssh/priv.h> + +/** + * @internal + * + * @brief Get the password from the console. + * + * @param[in] prompt The prompt to display. + * + * @param[in] buf The buffer to fill. + * + * @param[in] len The length of the buffer. + * + * @param[in] verify Should the password be verified? + * + * @return 1 on success, 0 on error. + */ +static int ssh_gets(const char *prompt, char *buf, size_t len, int verify) { + char *tmp; + char *ptr = NULL; + int ok = 0; + + tmp = malloc(len); + if (tmp == NULL) { + return 0; + } + ZERO_STRUCT(tmp); + + /* read the password */ + while (!ok) { + if (buf[0] != '\0') { + fprintf(stdout, "%s[%s] ", prompt, buf); + } else { + fprintf(stdout, "%s", prompt); + } + fflush(stdout); + while (fgets(tmp, len, stdin) != NULL); + + if ((ptr = strchr(tmp, '\n'))) { + *ptr = '\0'; + } + fprintf(stdout, "\n"); + + if (*tmp) { + strncpy(buf, tmp, len); + } + + if (verify) { + char *key_string; + + key_string = (char *) malloc(len); + if (key_string == NULL) { + break; + } + ZERO_STRUCT(key_string); + + fprintf(stdout, "\nVerifying, please re-enter. %s", prompt); + fflush(stdout); + if (! fgets(key_string, len, stdin)) { + ZERO_STRUCT(key_string); + SAFE_FREE(key_string); + clearerr(stdin); + continue; + } + if ((ptr = strchr(key_string, '\n'))) { + *ptr = '\0'; + } + fprintf(stdout, "\n"); + if (strcmp(buf, key_string)) { + printf("\n\07\07Mismatch - try again\n"); + ZERO_STRUCT(key_string); + SAFE_FREE(key_string); + fflush(stdout); + continue; + } + ZERO_STRUCT(key_string); + SAFE_FREE(key_string); + } + ok = 1; + } + + ZERO_STRUCT(tmp); + free(tmp); + + return ok; +} + +#ifdef _WIN32 +#include <windows.h> + +int ssh_getpass(const char *prompt, + char *buf, + size_t len, + int echo, + int verify) { + HANDLE h; + DWORD mode = 0; + int ok; + + /* get stdin and mode */ + h = GetStdHandle(STD_INPUT_HANDLE); + if (!GetConsoleMode(h, &mode)) { + return -1; + } + + /* disable echo */ + if (!echo) { + if (!SetConsoleMode(h, mode & ~ENABLE_ECHO_INPUT)) { + return -1; + } + } + + ok = ssh_gets(prompt, buf, len, verify); + + /* reset echo */ + SetConsoleMode(h, mode); + + if (!ok) { + ZERO_STRUCT(buf); + return -1; + } + + /* force termination */ + buf[len - 1] = '\0'; + + return 0; +} + +#else + +#include <fcntl.h> +#include <termios.h> +#include <unistd.h> + +/** + * @ingroup libssh_misc + * + * @brief Get a password from the console. + * + * You should make sure that the buffer is an empty string! + * + * You can also use this function to ask for a username. Then you can fill the + * buffer with the username and it is shows to the users. If the users just + * presses enter the buffer will be untouched. + * + * @code + * char username[128]; + * + * snprintf(username, sizeof(username), "john"); + * + * ssh_getpass("Username:", username, sizeof(username), 1, 0); + * @endcode + * + * The prompt will look like this: + * + * Username: [john] + * + * If you press enter then john is used as the username, or you can type it in + * to change it. + * + * @param[in] prompt The prompt to show to ask for the password. + * + * @param[out] buf The buffer the password should be stored. It NEEDS to be + * empty or filled out. + * + * @param[in] len The length of the buffer. + * + * @param[in] echo Should we echo what you type. + * + * @param[in] verify Should we ask for the password twice. + * + * @return 0 on success, -1 on error. + */ +int ssh_getpass(const char *prompt, + char *buf, + size_t len, + int echo, + int verify) { + struct termios attr; + struct termios old_attr; + int ok = 0; + int fd = -1; + + ZERO_STRUCT(attr); + ZERO_STRUCT(old_attr); + + /* get local terminal attributes */ + if (tcgetattr(STDIN_FILENO, &attr) < 0) { + perror("tcgetattr"); + return -1; + } + + /* save terminal attributes */ + memcpy(&old_attr, &attr, sizeof(attr)); + if((fd = fcntl(0, F_GETFL, 0)) < 0) { + perror("fcntl"); + return -1; + } + + /* disable echo */ + if (!echo) { + attr.c_lflag &= ~(ECHO); + } + + /* write attributes to terminal */ + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) < 0) { + perror("tcsetattr"); + return -1; + } + + /* disable nonblocking I/O */ + if (fd & O_NDELAY) { + fcntl(0, F_SETFL, fd & ~O_NDELAY); + } + + ok = ssh_gets(prompt, buf, len, verify); + + /* reset terminal */ + tcsetattr(STDIN_FILENO, TCSANOW, &old_attr); + + /* close fd */ + if (fd & O_NDELAY) { + fcntl(0, F_SETFL, fd); + } + + if (!ok) { + ZERO_STRUCT(buf); + return -1; + } + + /* force termination */ + buf[len - 1] = '\0'; + + return 0; +} + +#endif + +/* vim: set ts=4 sw=4 et cindent syntax=c.doxygen: */ |