]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - unix/uxproxy.c
Merge Ben's branch on which he's been fuzzing PuTTY.
[PuTTY.git] / unix / uxproxy.c
index b3f75e813fabfa09fd6ff5bad6a2f984c20d6d88..8c916dc99d7111eb8b898b4b14827555c048c0f5 100644 (file)
@@ -29,8 +29,7 @@ struct Socket_localproxy_tag {
 
     bufchain pending_output_data;
     bufchain pending_input_data;
-
-    void *privptr;
+    enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof;
 };
 
 static int localproxy_select_result(int fd, int event);
@@ -95,10 +94,14 @@ static void sk_localproxy_close (Socket s)
 {
     Local_Proxy_Socket ps = (Local_Proxy_Socket) s;
 
-    del234(localproxy_by_fromfd, ps);
-    del234(localproxy_by_tofd, ps);
+    if (ps->to_cmd >= 0) {
+        del234(localproxy_by_tofd, ps);
+        uxsel_del(ps->to_cmd);
+        close(ps->to_cmd);
+    }
 
-    close(ps->to_cmd);
+    del234(localproxy_by_fromfd, ps);
+    uxsel_del(ps->from_cmd);
     close(ps->from_cmd);
 
     sfree(ps);
@@ -127,6 +130,14 @@ static int localproxy_try_send(Local_Proxy_Socket ps)
        }
     }
 
+    if (ps->outgoingeof == EOF_PENDING) {
+        del234(localproxy_by_tofd, ps);
+        close(ps->to_cmd);
+        uxsel_del(ps->to_cmd);
+        ps->to_cmd = -1;
+        ps->outgoingeof = EOF_SENT;
+    }
+
     if (bufchain_size(&ps->pending_output_data) == 0)
        uxsel_del(ps->to_cmd);
     else
@@ -139,6 +150,8 @@ static int sk_localproxy_write (Socket s, const char *data, int len)
 {
     Local_Proxy_Socket ps = (Local_Proxy_Socket) s;
 
+    assert(ps->outgoingeof == EOF_NO);
+
     bufchain_add(&ps->pending_output_data, data, len);
 
     localproxy_try_send(ps);
@@ -155,22 +168,20 @@ static int sk_localproxy_write_oob (Socket s, const char *data, int len)
     return sk_localproxy_write(s, data, len);
 }
 
-static void sk_localproxy_flush (Socket s)
-{
-    /* Local_Proxy_Socket ps = (Local_Proxy_Socket) s; */
-    /* do nothing */
-}
-
-static void sk_localproxy_set_private_ptr (Socket s, void *ptr)
+static void sk_localproxy_write_eof (Socket s)
 {
     Local_Proxy_Socket ps = (Local_Proxy_Socket) s;
-    ps->privptr = ptr;
+
+    assert(ps->outgoingeof == EOF_NO);
+    ps->outgoingeof = EOF_PENDING;
+
+    localproxy_try_send(ps);
 }
 
-static void * sk_localproxy_get_private_ptr (Socket s)
+static void sk_localproxy_flush (Socket s)
 {
-    Local_Proxy_Socket ps = (Local_Proxy_Socket) s;
-    return ps->privptr;
+    /* Local_Proxy_Socket ps = (Local_Proxy_Socket) s; */
+    /* do nothing */
 }
 
 static void sk_localproxy_set_frozen (Socket s, int is_frozen)
@@ -207,7 +218,7 @@ static int localproxy_select_result(int fd, int event)
        } else if (ret == 0) {
            return plug_closing(s->plug, NULL, 0, 0);
        } else {
-           return plug_receive(s->plug, 1, buf, ret);
+           return plug_receive(s->plug, 0, buf, ret);
        }
     } else if (event == 2) {
        assert(fd == s->to_cmd);
@@ -219,10 +230,10 @@ static int localproxy_select_result(int fd, int event)
     return 1;
 }
 
-Socket platform_new_connection(SockAddr addr, char *hostname,
+Socket platform_new_connection(SockAddr addr, const char *hostname,
                               int port, int privport,
-                              int oobinline, int nodelay, Plug plug,
-                              const Config *cfg)
+                              int oobinline, int nodelay, int keepalive,
+                              Plug plug, Conf *conf)
 {
     char *cmd;
 
@@ -231,63 +242,87 @@ Socket platform_new_connection(SockAddr addr, char *hostname,
        sk_localproxy_close,
        sk_localproxy_write,
        sk_localproxy_write_oob,
+       sk_localproxy_write_eof,
        sk_localproxy_flush,
-       sk_localproxy_set_private_ptr,
-       sk_localproxy_get_private_ptr,
        sk_localproxy_set_frozen,
-       sk_localproxy_socket_error
+       sk_localproxy_socket_error,
+        NULL, /* peer_info */
     };
 
     Local_Proxy_Socket ret;
-    int to_cmd_pipe[2], from_cmd_pipe[2], pid;
+    int to_cmd_pipe[2], from_cmd_pipe[2], pid, proxytype;
 
-    if (cfg->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, cfg);
-
     ret = snew(struct Socket_localproxy_tag);
     ret->fn = &socket_fn_table;
     ret->plug = plug;
     ret->error = NULL;
+    ret->outgoingeof = EOF_NO;
 
     bufchain_init(&ret->pending_input_data);
     bufchain_init(&ret->pending_output_data);
 
-    /*
-     * 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));
-       return (Socket)ret;
-    }
+    if (proxytype == PROXY_CMD) {
+       cmd = format_telnet_command(addr, port, conf);
+
+       /*
+        * 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);
+       }
 
-    pid = fork();
-
-    if (pid < 0) {
-       ret->error = dupprintf("fork: %s", strerror(errno));
-       return (Socket)ret;
-    } else if (pid == 0) {
-       int i;
-       close(0);
-       close(1);
-       dup2(to_cmd_pipe[0], 0);
-       dup2(from_cmd_pipe[1], 1);
-       for (i = 3; i < 127; i++)
-           close(i);
-       fcntl(0, F_SETFD, 0);
-       fcntl(1, F_SETFD, 0);
-       execl("/bin/sh", "sh", "-c", cmd, NULL);
-       _exit(255);
-    }
+       sfree(cmd);
 
-    close(to_cmd_pipe[0]);
-    close(from_cmd_pipe[1]);
+       close(to_cmd_pipe[0]);
+       close(from_cmd_pipe[1]);
 
-    ret->to_cmd = to_cmd_pipe[1];
-    ret->from_cmd = from_cmd_pipe[0];
+       ret->to_cmd = to_cmd_pipe[1];
+       ret->from_cmd = from_cmd_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);
+    }
 
     if (!localproxy_by_fromfd)
        localproxy_by_fromfd = newtree234(localproxy_fromfd_cmp);