Last active
December 9, 2021 12:15
-
-
Save konsolebox/ed71274d4dfe7c809a597d08770d89f1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/utils_password.c b/src/utils_password.c | |
index 58f3a7b..5a055a8 100644 | |
--- a/src/utils_password.c | |
+++ b/src/utils_password.c | |
@@ -106,33 +106,60 @@ static int tools_check_password(const char *password) | |
/* Password reading helpers */ | |
-static ssize_t read_tty_eol(int fd, char *pass, size_t maxlen) | |
+static ssize_t read_tty_eol(int fd, int ofd, char *pass, size_t maxlen) | |
{ | |
bool eol = false; | |
size_t read_size = 0; | |
ssize_t r; | |
+ const char *p; | |
+ | |
+ if (maxlen < 1) | |
+ return -1; | |
do { | |
- r = read(fd, pass, maxlen - read_size); | |
+ r = read(fd, pass + read_size, maxlen - read_size); | |
+ | |
if ((r == -1 && errno != EINTR) || quit) | |
return -1; | |
- if (r >= 0) { | |
- if (!r || pass[r-1] == '\n') | |
+ | |
+ if (r == 0) | |
+ break; | |
+ | |
+ for (p = pass + read_size; r > 0 && read_size < maxlen && !eol; --r, | |
+ ++p) { | |
+ switch (*p) { | |
+ case '\n': | |
+ pass[read_size++] = '\n'; | |
+ case '\0': | |
eol = true; | |
- read_size += (size_t)r; | |
- pass = pass + r; | |
+ break; | |
+ case '\b': | |
+ case CERASE: | |
+ if (read_size > 0) { | |
+ --read_size; | |
+ if (write(ofd, "\b \b", 3) == -1) | |
+ return -1; | |
+ } | |
+ | |
+ break; | |
+ default: | |
+ pass[read_size++] = *p; | |
+ if (write(ofd, "*", 1) == -1) | |
+ return -1; | |
+ }; | |
} | |
- } while (!eol && read_size != maxlen); | |
+ } while (read_size < maxlen && !eol); | |
+ pass[read_size] = '\0'; | |
return (ssize_t)read_size; | |
} | |
/* The pass buffer is zeroed and has trailing \0 already " */ | |
-static int untimed_read(int fd, char *pass, size_t maxlen) | |
+static int untimed_read(int fd, int ofd, char *pass, size_t maxlen) | |
{ | |
ssize_t i; | |
- i = read_tty_eol(fd, pass, maxlen); | |
+ i = read_tty_eol(fd, ofd, pass, maxlen); | |
if (i > 0) { | |
if (pass[i-1] == '\n') | |
pass[i-1] = '\0'; | |
@@ -143,7 +170,7 @@ static int untimed_read(int fd, char *pass, size_t maxlen) | |
return i; | |
} | |
-static int timed_read(int fd, char *pass, size_t maxlen, long timeout) | |
+static int timed_read(int fd, int ofd, char *pass, size_t maxlen, long timeout) | |
{ | |
struct timeval t; | |
fd_set fds = {}; /* Just to avoid scan-build false report for FD_SET */ | |
@@ -155,11 +182,30 @@ static int timed_read(int fd, char *pass, size_t maxlen, long timeout) | |
t.tv_usec = 0; | |
if (select(fd+1, &fds, NULL, NULL, &t) > 0) | |
- failed = untimed_read(fd, pass, maxlen); | |
+ failed = untimed_read(fd, ofd, pass, maxlen); | |
return failed; | |
} | |
+/* Copied from bash's shtty.c | |
+ * Copyright (C) 1999 Free Software Foundation, Inc. | |
+ * Licensed under GPL v2 or later version */ | |
+static void tt_setonechar(struct termios *ttp) | |
+{ | |
+ ttp->c_lflag &= ~ICANON; | |
+ ttp->c_lflag |= ISIG; | |
+ ttp->c_lflag |= IEXTEN; | |
+ ttp->c_iflag |= ICRNL; | |
+ ttp->c_iflag &= ~INLCR; | |
+ ttp->c_oflag |= OPOST; | |
+ ttp->c_oflag |= ONLCR; | |
+ ttp->c_oflag &= ~OCRNL; | |
+ ttp->c_oflag &= ~ONOCR; | |
+ ttp->c_oflag &= ~ONLRET; | |
+ ttp->c_cc[VMIN] = 1; | |
+ ttp->c_cc[VTIME] = 0; | |
+} | |
+ | |
static int interactive_pass(const char *prompt, char *pass, size_t maxlen, | |
long timeout) | |
{ | |
@@ -182,6 +228,7 @@ static int interactive_pass(const char *prompt, char *pass, size_t maxlen, | |
goto out; | |
memcpy(&tmp, &orig, sizeof(tmp)); | |
+ tt_setonechar(&tmp); | |
tmp.c_lflag &= ~ECHO; | |
if (prompt && write(outfd, prompt, strlen(prompt)) < 0) | |
@@ -189,9 +236,9 @@ static int interactive_pass(const char *prompt, char *pass, size_t maxlen, | |
tcsetattr(infd, TCSAFLUSH, &tmp); | |
if (timeout) | |
- failed = timed_read(infd, pass, maxlen, timeout); | |
+ failed = timed_read(infd, outfd, pass, maxlen, timeout); | |
else | |
- failed = untimed_read(infd, pass, maxlen); | |
+ failed = untimed_read(infd, outfd, pass, maxlen); | |
tcsetattr(infd, TCSAFLUSH, &orig); | |
out: | |
if (!failed && write(outfd, "\n", 1)) {}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment