]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - unix/uxproxy.c
Merge branch 'pre-0.67'
[PuTTY.git] / unix / uxproxy.c
index 0399245d0c28bd8e7269390d991d835c66176bf5..f92c459be284ee341a35fda4c3e61b14690b75ec 100644 (file)
@@ -21,7 +21,7 @@ struct Socket_localproxy_tag {
     const struct socket_function_table *fn;
     /* the above variable absolutely *must* be the first in this structure */
 
-    int to_cmd, from_cmd;             /* fds */
+    int to_cmd, from_cmd, cmd_err;     /* fds */
 
     char *error;
 
@@ -29,6 +29,7 @@ struct Socket_localproxy_tag {
 
     bufchain pending_output_data;
     bufchain pending_input_data;
+    bufchain pending_error_data;
     enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof;
 };
 
@@ -37,7 +38,9 @@ static int localproxy_select_result(int fd, int event);
 /*
  * Trees to look up the pipe fds in.
  */
-static tree234 *localproxy_by_fromfd, *localproxy_by_tofd;
+static tree234 *localproxy_by_fromfd;
+static tree234 *localproxy_by_tofd;
+static tree234 *localproxy_by_errfd;
 static int localproxy_fromfd_cmp(void *av, void *bv)
 {
     Local_Proxy_Socket a = (Local_Proxy_Socket)av;
@@ -78,6 +81,26 @@ static int localproxy_tofd_find(void *av, void *bv)
        return +1;
     return 0;
 }
+static int localproxy_errfd_cmp(void *av, void *bv)
+{
+    Local_Proxy_Socket a = (Local_Proxy_Socket)av;
+    Local_Proxy_Socket b = (Local_Proxy_Socket)bv;
+    if (a->cmd_err < b->cmd_err)
+       return -1;
+    if (a->cmd_err > b->cmd_err)
+       return +1;
+    return 0;
+}
+static int localproxy_errfd_find(void *av, void *bv)
+{
+    int a = *(int *)av;
+    Local_Proxy_Socket b = (Local_Proxy_Socket)bv;
+    if (a < b->cmd_err)
+       return -1;
+    if (a > b->cmd_err)
+       return +1;
+    return 0;
+}
 
 /* basic proxy socket functions */
 
@@ -104,6 +127,14 @@ static void sk_localproxy_close (Socket s)
     uxsel_del(ps->from_cmd);
     close(ps->from_cmd);
 
+    del234(localproxy_by_errfd, ps);
+    uxsel_del(ps->cmd_err);
+    close(ps->cmd_err);
+
+    bufchain_clear(&ps->pending_input_data);
+    bufchain_clear(&ps->pending_output_data);
+    bufchain_clear(&ps->pending_error_data);
+
     sfree(ps);
 }
 
@@ -207,19 +238,26 @@ static int localproxy_select_result(int fd, int event)
     int ret;
 
     if (!(s = find234(localproxy_by_fromfd, &fd, localproxy_fromfd_find)) &&
+       !(s = find234(localproxy_by_fromfd, &fd, localproxy_errfd_find)) &&
        !(s = find234(localproxy_by_tofd, &fd, localproxy_tofd_find)) )
        return 1;                      /* boggle */
 
     if (event == 1) {
-       assert(fd == s->from_cmd);
-       ret = read(fd, buf, sizeof(buf));
-       if (ret < 0) {
-           return plug_closing(s->plug, strerror(errno), errno, 0);
-       } else if (ret == 0) {
-           return plug_closing(s->plug, NULL, 0, 0);
-       } else {
-           return plug_receive(s->plug, 0, buf, ret);
-       }
+        if (fd == s->cmd_err) {
+            ret = read(fd, buf, sizeof(buf));
+            if (ret > 0)
+                log_proxy_stderr(s->plug, &s->pending_error_data, buf, ret);
+        } else {
+            assert(fd == s->from_cmd);
+            ret = read(fd, buf, sizeof(buf));
+            if (ret < 0) {
+                return plug_closing(s->plug, strerror(errno), errno, 0);
+            } else if (ret == 0) {
+                return plug_closing(s->plug, NULL, 0, 0);
+            } else {
+                return plug_receive(s->plug, 0, buf, ret);
+            }
+        }
     } else if (event == 2) {
        assert(fd == s->to_cmd);
        if (localproxy_try_send(s))
@@ -250,13 +288,12 @@ Socket platform_new_connection(SockAddr addr, const char *hostname,
     };
 
     Local_Proxy_Socket ret;
-    int to_cmd_pipe[2], from_cmd_pipe[2], pid;
+    int to_cmd_pipe[2], from_cmd_pipe[2], cmd_err_pipe[2], pid, proxytype;
 
-    if (conf_get_int(conf, CONF_proxy_type) != PROXY_CMD)
+    proxytype = conf_get_int(conf, CONF_proxy_type);
+    if (proxytype != PROXY_CMD && proxytype != PROXY_FUZZ)
        return NULL;
 
-    cmd = format_telnet_command(addr, port, conf);
-
     ret = snew(struct Socket_localproxy_tag);
     ret->fn = &socket_fn_table;
     ret->plug = plug;
@@ -265,56 +302,111 @@ Socket platform_new_connection(SockAddr addr, const char *hostname,
 
     bufchain_init(&ret->pending_input_data);
     bufchain_init(&ret->pending_output_data);
+    bufchain_init(&ret->pending_error_data);
+
+    if (proxytype == PROXY_CMD) {
+       cmd = format_telnet_command(addr, port, conf);
+
+        if (flags & FLAG_STDERR) {
+            /* If we have a sensible stderr, the proxy command can
+             * send its own standard error there, so we won't
+             * interfere. */
+            cmd_err_pipe[0] = cmd_err_pipe[1] = -1;
+        } else {
+            /* If we don't have a sensible stderr, we should catch the
+             * proxy command's standard error to put in our event
+             * log. */
+            cmd_err_pipe[0] = cmd_err_pipe[1] = 0;
+        }
+
+        {
+            char *logmsg = dupprintf("Starting local proxy command: %s", cmd);
+            plug_log(plug, 2, NULL, 0, logmsg, 0);
+            sfree(logmsg);
+        }
+
+       /*
+        * Create the pipes to the proxy command, and spawn the proxy
+        * command process.
+        */
+       if (pipe(to_cmd_pipe) < 0 ||
+           pipe(from_cmd_pipe) < 0 ||
+            (cmd_err_pipe[0] == 0 && pipe(cmd_err_pipe) < 0)) {
+           ret->error = dupprintf("pipe: %s", strerror(errno));
+           sfree(cmd);
+           return (Socket)ret;
+       }
+       cloexec(to_cmd_pipe[1]);
+       cloexec(from_cmd_pipe[0]);
+       if (cmd_err_pipe[0] >= 0)
+            cloexec(cmd_err_pipe[0]);
+
+       pid = fork();
+
+       if (pid < 0) {
+           ret->error = dupprintf("fork: %s", strerror(errno));
+           sfree(cmd);
+           return (Socket)ret;
+       } else if (pid == 0) {
+           close(0);
+           close(1);
+           dup2(to_cmd_pipe[0], 0);
+           dup2(from_cmd_pipe[1], 1);
+           close(to_cmd_pipe[0]);
+           close(from_cmd_pipe[1]);
+           if (cmd_err_pipe[0] >= 0) {
+                dup2(cmd_err_pipe[1], 2);
+                close(cmd_err_pipe[1]);
+            }
+           noncloexec(0);
+           noncloexec(1);
+           execl("/bin/sh", "sh", "-c", cmd, (void *)NULL);
+           _exit(255);
+       }
+
+       sfree(cmd);
 
-    /*
-     * Create the pipes to the proxy command, and spawn the proxy
-     * command process.
-     */
-    if (pipe(to_cmd_pipe) < 0 ||
-       pipe(from_cmd_pipe) < 0) {
-       ret->error = dupprintf("pipe: %s", strerror(errno));
-        sfree(cmd);
-       return (Socket)ret;
-    }
-    cloexec(to_cmd_pipe[1]);
-    cloexec(from_cmd_pipe[0]);
-
-    pid = fork();
-
-    if (pid < 0) {
-       ret->error = dupprintf("fork: %s", strerror(errno));
-        sfree(cmd);
-       return (Socket)ret;
-    } else if (pid == 0) {
-       close(0);
-       close(1);
-       dup2(to_cmd_pipe[0], 0);
-       dup2(from_cmd_pipe[1], 1);
        close(to_cmd_pipe[0]);
        close(from_cmd_pipe[1]);
-       noncloexec(0);
-       noncloexec(1);
-       execl("/bin/sh", "sh", "-c", cmd, (void *)NULL);
-       _exit(255);
+        if (cmd_err_pipe[0] >= 0)
+            close(cmd_err_pipe[1]);
+
+       ret->to_cmd = to_cmd_pipe[1];
+       ret->from_cmd = from_cmd_pipe[0];
+       ret->cmd_err = cmd_err_pipe[0];
+    } else {
+       cmd = format_telnet_command(addr, port, conf);
+       ret->to_cmd = open("/dev/null", O_WRONLY);
+       if (ret->to_cmd == -1) {
+           ret->error = dupprintf("/dev/null: %s", strerror(errno));
+           sfree(cmd);
+           return (Socket)ret;
+       }
+       ret->from_cmd = open(cmd, O_RDONLY);
+       if (ret->from_cmd == -1) {
+           ret->error = dupprintf("%s: %s", cmd, strerror(errno));
+           sfree(cmd);
+           return (Socket)ret;
+       }
+       sfree(cmd);
+       ret->cmd_err = -1;
     }
 
-    sfree(cmd);
-
-    close(to_cmd_pipe[0]);
-    close(from_cmd_pipe[1]);
-
-    ret->to_cmd = to_cmd_pipe[1];
-    ret->from_cmd = from_cmd_pipe[0];
-
     if (!localproxy_by_fromfd)
        localproxy_by_fromfd = newtree234(localproxy_fromfd_cmp);
     if (!localproxy_by_tofd)
        localproxy_by_tofd = newtree234(localproxy_tofd_cmp);
+    if (!localproxy_by_errfd)
+       localproxy_by_errfd = newtree234(localproxy_errfd_cmp);
 
     add234(localproxy_by_fromfd, ret);
     add234(localproxy_by_tofd, ret);
+    if (ret->cmd_err >= 0)
+        add234(localproxy_by_errfd, ret);
 
     uxsel_set(ret->from_cmd, 1, localproxy_select_result);
+    if (ret->cmd_err >= 0)
+        uxsel_set(ret->cmd_err, 1, localproxy_select_result);
 
     /* We are responsible for this and don't need it any more */
     sk_addr_free(addr);