diff options
author | Martin Pieuchot <mpi@openbsd.org> | 2012-07-13 16:51:39 +0200 |
---|---|---|
committer | Tomas Bzatek <tbzatek@redhat.com> | 2012-07-13 16:51:39 +0200 |
commit | 2fec402d6523e4cf416d754f69d012dc67a58a2e (patch) | |
tree | 67b022d0879405b769d993820d3aed61dba7c109 /daemon/pty_open.c | |
parent | e3890ddd806a7e2f89ac17d61a4aac0fa4eb7006 (diff) | |
download | gvfs-2fec402d6523e4cf416d754f69d012dc67a58a2e.tar.gz |
daemon: Support allocating PTYs through openpty on BSD
Allows systems supporting the BSD openpty(3) utily function but not
the Unix98 PTY function family (grantpt(3), unlockpt(3), ...) to
allocate a pseudo-tty required for the ssh authentication.
https://bugzilla.gnome.org/show_bug.cgi?id=679790
Signed-off-by: Tomas Bzatek <tbzatek@redhat.com>
Diffstat (limited to 'daemon/pty_open.c')
-rw-r--r-- | daemon/pty_open.c | 132 |
1 files changed, 127 insertions, 5 deletions
diff --git a/daemon/pty_open.c b/daemon/pty_open.c index 22fa6b9a..e822189f 100644 --- a/daemon/pty_open.c +++ b/daemon/pty_open.c @@ -72,6 +72,12 @@ #include <glib.h> #include "pty_open.h" +#if defined(HAVE_PTSNAME_R) || defined(HAVE_PTSNAME) || defined(TIOCGPTN) +#define HAVE_UNIX98_PTY +#else +#undef HAVE_UNIX98_PTY +#endif + int _pty_set_size(int master, int columns, int rows); /* Solaris does not have the login_tty() function so implement locally. */ @@ -710,6 +716,8 @@ _pty_unlockpt(int fd) #endif } +#if defined(HAVE_UNIX98_PTY) + static int _pty_open_unix98(pid_t *child, guint flags, char **env_add, const char *command, char **argv, @@ -746,6 +754,114 @@ _pty_open_unix98(pid_t *child, guint flags, char **env_add, return fd; } +#elif defined(HAVE_OPENPTY) + +static int +_pty_open_bsd(pid_t *child, const char *command, char **argv, + int *stdin_fd, int *stdout_fd, int *stderr_fd) +{ + int master, slave; + char **args, *arg; + int stdin_pipe[2]; + int stdout_pipe[2]; + int stderr_pipe[2]; + pid_t pid; + int i; + + if (pipe(stdin_pipe)) + goto bail_stdin; + if (pipe(stdout_pipe)) + goto bail_stdout; + if (pipe(stderr_pipe)) + goto bail_stderr; + + if (openpty(&master, &slave, NULL, NULL, NULL) == -1) + return (-1); + + switch(pid = fork()) { + case -1: + goto bail_fork; + case 0: + /* + * Child + */ + close(master); + close(stdin_pipe[1]); + close(stdout_pipe[0]); + close(stderr_pipe[0]); + + setsid(); + if (ioctl(slave, TIOCSCTTY, (char *)NULL) == -1) + _exit(0); + + /* Set up stdin/out/err */ + dup2(stdin_pipe[0], STDIN_FILENO); + dup2(stdout_pipe[1], STDOUT_FILENO); + dup2(stderr_pipe[1], STDERR_FILENO); + close(stdin_pipe[0]); + close(stdout_pipe[1]); + close(stderr_pipe[1]); + + /* Reset our signals -- our parent may have done any number of + * weird things to them. */ + _pty_reset_signal_handlers(); + + /* Outta here. */ + if (argv != NULL) { + for (i = 0; (argv[i] != NULL); i++) ; + args = g_malloc0(sizeof(char*) * (i + 1)); + for (i = 0; (argv[i] != NULL); i++) { + args[i] = g_strdup(argv[i]); + } + execvp(command, args); + } else { + arg = g_strdup(command); + execlp(command, arg, NULL); + } + + /* Avoid calling any atexit() code. */ + _exit(0); + g_assert_not_reached(); + } + + /* + * Parent + */ + + /* XXX Don't close the slave pty, it's now the control + * terminal of the child and ssh needs it to authenticate. + close(slave); + */ + close(stdin_pipe[0]); + close(stdout_pipe[1]); + close(stderr_pipe[1]); + + *child = pid; + *stdin_fd = stdin_pipe[1]; + *stdout_fd = stdout_pipe[0]; + *stderr_fd = stderr_pipe[0]; + + return (master); + + bail_fork: + close(stderr_pipe[0]); + close(stderr_pipe[1]); + bail_stderr: + close(stdout_pipe[0]); + close(stdout_pipe[1]); + bail_stdout: + close(stdin_pipe[0]); + close(stdin_pipe[1]); + bail_stdin: + + *child = -1; + return -1; +} + +#else +#error Have neither UNIX98 PTY nor BSD openpty! +#endif /* HAVE_UNIX98_PTY */ + /** * pty_open: * @child: location to store the new process's ID @@ -774,11 +890,17 @@ pty_open(pid_t *child, guint flags, char **env_add, int *stdin_fd, int *stdout_fd, int *stderr_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); - } + +#if defined(HAVE_UNIX98_PTY) + ret = _pty_open_unix98(child, flags, env_add, command, argv, directory, + columns, rows, stdin_fd, stdout_fd, stderr_fd); +#elif defined(HAVE_OPENPTY) + ret = _pty_open_bsd(child, command, argv, + stdin_fd, stdout_fd, stderr_fd); +#else +#error Have neither UNIX98 PTY nor BSD openpty! +#endif + return ret; } |