summaryrefslogtreecommitdiff
path: root/daemon/pty_open.c
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@openbsd.org>2012-07-13 16:51:39 +0200
committerTomas Bzatek <tbzatek@redhat.com>2012-07-13 16:51:39 +0200
commit2fec402d6523e4cf416d754f69d012dc67a58a2e (patch)
tree67b022d0879405b769d993820d3aed61dba7c109 /daemon/pty_open.c
parente3890ddd806a7e2f89ac17d61a4aac0fa4eb7006 (diff)
downloadgvfs-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.c132
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;
}