From 642858f2bd8d4ba82c628fd80fc75a8b1e591033 Mon Sep 17 00:00:00 2001 From: Tristan Schmelcher Date: Tue, 18 Oct 2011 15:59:39 +0000 Subject: Hold the slave PTY open, so that SSH does not fail Optionally hold the slave PTY open in the parent. Needed to prevent EIO from read() on the master if exec'ing a program that enumerates and closes open fds before opening /dev/tty (ssh). Partially fixes bug 644432. --- diff --git a/vinagre/pty_open.c b/vinagre/pty_open.c index a535809..a299146 100644 --- a/vinagre/pty_open.c +++ b/vinagre/pty_open.c @@ -404,9 +404,10 @@ _pty_fork_on_pty_name(const char *path, int parent_fd, char **env_add, const char *directory, int columns, int rows, int *stdin_fd, int *stdout_fd, int *stderr_fd, + int *held_fd, pid_t *child, gboolean reapchild, gboolean login) { - int fd, i; + int fd, hold_fd, i; char c; int ready_a[2] = { 0, 0 }; int ready_b[2] = { 0, 0 }; @@ -416,6 +417,17 @@ _pty_fork_on_pty_name(const char *path, int parent_fd, char **env_add, int stdout_pipe[2]; int stderr_pipe[2]; + /* Optionally hold the slave PTY open in the parent. Needed to prevent + * EIO from read() on the master if exec'ing a program that enumerates + * and closes open fds before opening /dev/tty (ssh). Partially fixes + * bug 644432. */ + if (held_fd) { + hold_fd = open(path, O_RDWR|O_NOCTTY); + if (hold_fd == -1) { + return -1; + } + } + /* Open pipes for synchronizing between parent and child. */ if (_pty_pipe_open_bi(&ready_a[0], &ready_a[1], &ready_b[0], &ready_b[1]) == -1) { @@ -457,6 +469,7 @@ _pty_fork_on_pty_name(const char *path, int parent_fd, char **env_add, close(stdin_pipe[1]); close(stdout_pipe[0]); close(stderr_pipe[0]); + if (held_fd) close(hold_fd); if(reapchild) { close(pid_pipe[0]); @@ -575,6 +588,7 @@ _pty_fork_on_pty_name(const char *path, int parent_fd, char **env_add, *stdin_fd = stdin_pipe[1]; *stdout_fd = stdout_pipe[0]; *stderr_fd = stderr_pipe[0]; + if (held_fd) *held_fd = hold_fd; return 0; break; @@ -603,6 +617,7 @@ _pty_fork_on_pty_name(const char *path, int parent_fd, char **env_add, close(ready_b[1]); bail_ready: *child = -1; + if (held_fd) close(hold_fd); return -1; } @@ -716,7 +731,8 @@ static int _pty_open_unix98(pid_t *child, guint flags, char **env_add, const char *command, char **argv, const char *directory, int columns, int rows, - int *stdin_fd, int *stdout_fd, int *stderr_fd) + int *stdin_fd, int *stdout_fd, int *stderr_fd, + int *held_fd) { int fd; char *buf; @@ -736,6 +752,7 @@ _pty_open_unix98(pid_t *child, guint flags, char **env_add, argv, directory, columns, rows, stdin_fd, stdout_fd, stderr_fd, + held_fd, child, flags & PTY_REAP_CHILD, flags & PTY_LOGIN_TTY) != 0) { @@ -773,13 +790,15 @@ int pty_open(pid_t *child, guint flags, char **env_add, const char *command, char **argv, const char *directory, int columns, int rows, - int *stdin_fd, int *stdout_fd, int *stderr_fd) + int *stdin_fd, int *stdout_fd, int *stderr_fd, + int *held_fd) { int ret = -1; if (ret == -1) { ret = _pty_open_unix98(child, flags, env_add, command, argv, directory, columns, rows, - stdin_fd, stdout_fd, stderr_fd); + stdin_fd, stdout_fd, stderr_fd, + held_fd); } return ret; } diff --git a/vinagre/pty_open.h b/vinagre/pty_open.h index 2e482e1..9a3e026 100644 --- a/vinagre/pty_open.h +++ b/vinagre/pty_open.h @@ -59,7 +59,8 @@ enum { int pty_open(pid_t *child, guint flags, char **env_add, const char *command, char **argv, const char *directory, int columns, int rows, - int *stdin_fd, int *stdout_fd, int *stderr_fd); + int *stdin_fd, int *stdout_fd, int *stderr_fd, + int *held_fd); G_END_DECLS diff --git a/vinagre/vinagre-ssh.c b/vinagre/vinagre-ssh.c index c5b3427..8bfa507 100644 --- a/vinagre/vinagre-ssh.c +++ b/vinagre/vinagre-ssh.c @@ -173,13 +173,15 @@ spawn_ssh (char *args[], int *stdin_fd, int *stdout_fd, int *stderr_fd, + int *held_fd, GError **error) { #ifdef USE_PTY *tty_fd = pty_open(pid, PTY_REAP_CHILD, NULL, args[0], args, NULL, 300, 300, - stdin_fd, stdout_fd, stderr_fd); + stdin_fd, stdout_fd, stderr_fd, + held_fd); if (*tty_fd == -1) { g_set_error_literal (error, @@ -207,6 +209,7 @@ spawn_ssh (char *args[], return FALSE; } *pid = gpid; + if (held_fd) *held_fd = -1; /* Not applicable here. */ #endif return TRUE; @@ -728,7 +731,7 @@ vinagre_ssh_connect (GtkWindow *parent, gint *tty, GError **error) { - int tty_fd, stdin_fd, stdout_fd, stderr_fd; + int tty_fd, stdin_fd, stdout_fd, stderr_fd, held_fd; GPid pid; gchar *user, *host, **args; gboolean res; @@ -758,7 +761,7 @@ vinagre_ssh_connect (GtkWindow *parent, args = setup_ssh_commandline (host, port, user, extra_arguments, command); if (!spawn_ssh (args, &pid, - &tty_fd, &stdin_fd, &stdout_fd, &stderr_fd, + &tty_fd, &stdin_fd, &stdout_fd, &stderr_fd, &held_fd, error)) { g_strfreev (args); @@ -772,6 +775,9 @@ vinagre_ssh_connect (GtkWindow *parent, else res = handle_login (parent, host, port, user, tty_fd, stdout_fd, stderr_fd, error); + /* ssh has opened the PTY slave by now, so we can close it */ + if (held_fd != -1) close(held_fd); + g_strfreev (args); g_free (user); g_free (host); -- cgit v0.9.0.2