client ssh session CHANGE use generic way of learning stdin term
Also, handle correctly situation when stdin and stdout
do not use one terminal/device.
diff --git a/src/session_client_ssh.c b/src/session_client_ssh.c
index a68c39e..5b175db 100644
--- a/src/session_client_ssh.c
+++ b/src/session_client_ssh.c
@@ -67,6 +67,45 @@
.auth_privkey_passphrase = sshauth_privkey_passphrase
};
+static FILE *
+open_tty_noecho(const char *path, struct termios *oldterm)
+{
+ struct termios newterm;
+ FILE *ret;
+
+ if (!(ret = fopen(path, "r"))) {
+ ERR("Unable to open the current terminal (%s).", strerror(errno));
+ return NULL;
+ }
+
+ if (tcgetattr(fileno(ret), oldterm)) {
+ ERR("Unable to get terminal settings (%s).", strerror(errno));
+ fclose(ret);
+ return NULL;
+ }
+
+ newterm = *oldterm;
+ newterm.c_lflag &= ~ECHO;
+ newterm.c_lflag &= ~ICANON;
+ tcflush(fileno(ret), TCIFLUSH);
+ if (tcsetattr(fileno(ret), TCSANOW, &newterm)) {
+ ERR("Unable to change terminal settings for hiding password (%s).", strerror(errno));
+ fclose(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+static void
+restore_tty_close(FILE *tty, struct termios *oldterm)
+{
+ if (tcsetattr(fileno(tty), TCSANOW, oldterm) != 0) {
+ ERR("Unable to restore terminal settings (%s).", strerror(errno));
+ }
+ fclose(tty);
+}
+
static void
_nc_client_ssh_destroy_opts(struct nc_client_ssh_opts *opts)
{
@@ -307,55 +346,39 @@
sshauth_password(const char *username, const char *hostname)
{
char *buf;
- int buflen = 1024, len = 0;
+ int buflen = 1024, len, ret;
char c = 0;
- struct termios newterm, oldterm;
+ struct termios oldterm;
FILE *tty;
- if (!(tty = fopen("/dev/tty", "r+"))) {
- ERR("Unable to open the current terminal (%s).", strerror(errno));
- return NULL;
- }
-
- if (tcgetattr(fileno(tty), &oldterm)) {
- ERR("Unable to get terminal settings (%s).", strerror(errno));
- fclose(tty);
- return NULL;
- }
-
- fprintf(tty, "%s@%s password: ", username, hostname);
- fflush(tty);
-
- /* system("stty -echo"); */
- newterm = oldterm;
- newterm.c_lflag &= ~ECHO;
- newterm.c_lflag &= ~ICANON;
- tcflush(fileno(tty), TCIFLUSH);
- if (tcsetattr(fileno(tty), TCSANOW, &newterm)) {
- ERR("Unable to change terminal settings for hiding password (%s).", strerror(errno));
- fclose(tty);
- return NULL;
- }
-
buf = malloc(buflen * sizeof *buf);
if (!buf) {
ERRMEM;
- fclose(tty);
return NULL;
}
+ if ((ret = ttyname_r(STDIN_FILENO, buf, buflen))) {
+ ERR("ttyname_r failed (%s).", strerror(ret));
+ free(buf);
+ return NULL;
+ }
+
+ if (!(tty = open_tty_noecho(buf, &oldterm))) {
+ free(buf);
+ return NULL;
+ }
+
+ fprintf(stdout, "%s@%s password: ", username, hostname);
+ fflush(stdout);
+
+ len = 0;
while ((fread(&c, 1, 1, tty) == 1) && (c != '\n')) {
if (len >= buflen - 1) {
buflen *= 2;
buf = nc_realloc(buf, buflen * sizeof *buf);
if (!buf) {
ERRMEM;
-
- /* restore terminal settings */
- if (tcsetattr(fileno(tty), TCSANOW, &oldterm) != 0) {
- ERR("Unable to restore terminal settings (%s).", strerror(errno));
- }
- fclose(tty);
+ restore_tty_close(tty, &oldterm);
return NULL;
}
}
@@ -363,126 +386,19 @@
}
buf[len++] = 0; /* terminating null byte */
- /* system ("stty echo"); */
- if (tcsetattr(fileno(tty), TCSANOW, &oldterm)) {
- ERR("Unable to restore terminal settings (%s).", strerror(errno));
- /*
- * terminal probably still hides input characters, but we have password
- * and anyway we are unable to set terminal to the previous state, so
- * just continue
- */
- }
- fprintf(tty, "\n");
-
- fclose(tty);
+ fprintf(stdout, "\n");
+ restore_tty_close(tty, &oldterm);
return buf;
}
static char *
sshauth_interactive(const char *auth_name, const char *instruction, const char *prompt, int echo)
{
- unsigned int buflen = 8, response_len;
+ unsigned int buflen = 64, cur_len;
char c = 0;
- struct termios newterm, oldterm;
- char *response;
- FILE *tty;
-
- if (!(tty = fopen("/dev/tty", "r+"))) {
- ERR("Unable to open the current terminal (%s).", strerror(errno));
- return NULL;
- }
-
- if (tcgetattr(fileno(tty), &oldterm) != 0) {
- ERR("Unable to get terminal settings (%s).", strerror(errno));
- fclose(tty);
- return NULL;
- }
-
- if (auth_name && (!fwrite(auth_name, sizeof(char), strlen(auth_name), tty)
- || !fwrite("\n", sizeof(char), 1, tty))) {
- ERR("Writing the auth method name into stdout failed.");
- fclose(tty);
- return NULL;
- }
-
- if (instruction && (!fwrite(instruction, sizeof(char), strlen(instruction), tty)
- || !fwrite("\n", sizeof(char), 1, tty))) {
- ERR("Writing the instruction into stdout failed.");
- fclose(tty);
- return NULL;
- }
-
- if (!fwrite(prompt, sizeof(char), strlen(prompt), tty)) {
- ERR("Writing the authentication prompt into stdout failed.");
- fclose(tty);
- return NULL;
- }
- fflush(tty);
- if (!echo) {
- /* system("stty -echo"); */
- newterm = oldterm;
- newterm.c_lflag &= ~ECHO;
- tcflush(fileno(tty), TCIFLUSH);
- if (tcsetattr(fileno(tty), TCSANOW, &newterm)) {
- ERR("Unable to change terminal settings for hiding password (%s).", strerror(errno));
- fclose(tty);
- return NULL;
- }
- }
-
- response = malloc(buflen * sizeof *response);
- response_len = 0;
- if (!response) {
- ERRMEM;
- /* restore terminal settings */
- if (tcsetattr(fileno(tty), TCSANOW, &oldterm)) {
- ERR("Unable to restore terminal settings (%s).", strerror(errno));
- }
- fclose(tty);
- return NULL;
- }
-
- while ((fread(&c, 1, 1, tty) == 1) && (c != '\n')) {
- if (response_len >= buflen - 1) {
- buflen *= 2;
- response = nc_realloc(response, buflen * sizeof *response);
- if (!response) {
- ERRMEM;
-
- /* restore terminal settings */
- if (tcsetattr(fileno(tty), TCSANOW, &oldterm)) {
- ERR("Unable to restore terminal settings (%s).", strerror(errno));
- }
- fclose(tty);
- return NULL;
- }
- }
- response[response_len++] = c;
- }
- /* terminating null byte */
- response[response_len++] = '\0';
-
- /* system ("stty echo"); */
- if (tcsetattr(fileno(tty), TCSANOW, &oldterm)) {
- ERR("Unable to restore terminal settings (%s).", strerror(errno));
- /*
- * terminal probably still hides input characters, but we have password
- * and anyway we are unable to set terminal to the previous state, so
- * just continue
- */
- }
-
- fprintf(tty, "\n");
- fclose(tty);
- return response;
-}
-
-static char *
-sshauth_privkey_passphrase(const char* privkey_path)
-{
- char c, *buf;
- int buflen = 1024, len = 0;
- struct termios newterm, oldterm;
+ int ret;
+ struct termios oldterm;
+ char *buf;
FILE *tty;
buf = malloc(buflen * sizeof *buf);
@@ -491,65 +407,116 @@
return NULL;
}
- if (!(tty = fopen("/dev/tty", "r+"))) {
- ERR("Unable to open the current terminal (%s).", strerror(errno));
- goto fail;
+ if ((ret = ttyname_r(STDIN_FILENO, buf, buflen))) {
+ ERR("ttyname_r failed (%s).", strerror(ret));
+ free(buf);
+ return NULL;
}
- if (tcgetattr(fileno(tty), &oldterm)) {
- ERR("Unable to get terminal settings (%s).", strerror(errno));
- goto fail;
+ if (!echo) {
+ if (!(tty = open_tty_noecho(buf, &oldterm))) {
+ free(buf);
+ return NULL;
+ }
+ } else {
+ tty = stdin;
}
- fprintf(tty, "Enter passphrase for the key '%s':", privkey_path);
- fflush(tty);
- /* system("stty -echo"); */
- newterm = oldterm;
- newterm.c_lflag &= ~ECHO;
- newterm.c_lflag &= ~ICANON;
- tcflush(fileno(tty), TCIFLUSH);
- if (tcsetattr(fileno(tty), TCSANOW, &newterm)) {
- ERR("Unable to change terminal settings for hiding password (%s).", strerror(errno));
+ if (auth_name && (!fwrite(auth_name, sizeof *auth_name, strlen(auth_name), stdout)
+ || !fwrite("\n", sizeof(char), 1, stdout))) {
+ ERR("Writing the auth method name into stdout failed.");
goto fail;
}
+ if (instruction && (!fwrite(instruction, sizeof *auth_name, strlen(instruction), stdout)
+ || !fwrite("\n", sizeof(char), 1, stdout))) {
+ ERR("Writing the instruction into stdout failed.");
+ goto fail;
+ }
+ if (!fwrite(prompt, sizeof *prompt, strlen(prompt), stdout)) {
+ ERR("Writing the authentication prompt into stdout failed.");
+ goto fail;
+ }
+ fflush(stdout);
+ cur_len = 0;
+ while ((fread(&c, 1, 1, tty) == 1) && (c != '\n')) {
+ if (cur_len >= buflen - 1) {
+ buflen *= 2;
+ buf = nc_realloc(buf, buflen * sizeof *buf);
+ if (!buf) {
+ ERRMEM;
+ goto fail;
+ }
+ }
+ buf[cur_len++] = c;
+ }
+ /* terminating null byte */
+ buf[cur_len] = '\0';
+
+ fprintf(stdout, "\n");
+ if (!echo) {
+ restore_tty_close(tty, &oldterm);
+ }
+ return buf;
+
+fail:
+ if (!echo) {
+ restore_tty_close(tty, &oldterm);
+ }
+ free(buf);
+ return NULL;
+}
+
+static char *
+sshauth_privkey_passphrase(const char* privkey_path)
+{
+ char c, *buf;
+ int buflen = 1024, len, ret;
+ struct termios oldterm;
+ FILE *tty;
+
+ buf = malloc(buflen * sizeof *buf);
+ if (!buf) {
+ ERRMEM;
+ return NULL;
+ }
+
+ if ((ret = ttyname_r(STDIN_FILENO, buf, buflen))) {
+ ERR("ttyname_r failed (%s).", strerror(ret));
+ free(buf);
+ return NULL;
+ }
+
+ if (!(tty = open_tty_noecho(buf, &oldterm))) {
+ free(buf);
+ return NULL;
+ }
+
+ fprintf(stdout, "Enter passphrase for the key '%s':", privkey_path);
+ fflush(stdout);
+
+ len = 0;
while ((fread(&c, 1, 1, tty) == 1) && (c != '\n')) {
if (len >= buflen - 1) {
buflen *= 2;
buf = nc_realloc(buf, buflen * sizeof *buf);
if (!buf) {
ERRMEM;
- /* restore terminal settings */
- if (tcsetattr(fileno(tty), TCSANOW, &oldterm)) {
- ERR("Unable to restore terminal settings (%s).", strerror(errno));
- }
goto fail;
}
}
buf[len++] = (char)c;
}
- buf[len++] = 0; /* terminating null byte */
+ buf[len] = 0; /* terminating null byte */
- /* system ("stty echo"); */
- if (tcsetattr(fileno(tty), TCSANOW, &oldterm)) {
- ERR("Unable to restore terminal settings (%s).", strerror(errno));
- /*
- * terminal probably still hides input characters, but we have password
- * and anyway we are unable to set terminal to the previous state, so
- * just continue
- */
- }
- fprintf(tty, "\n");
-
- fclose(tty);
+ fprintf(stdout, "\n");
+ restore_tty_close(tty, &oldterm);
return buf;
fail:
+ restore_tty_close(tty, &oldterm);
free(buf);
- if (tty) {
- fclose(tty);
- }
return NULL;
}