X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=unix%2Fuxproxy.c;h=f92c459be284ee341a35fda4c3e61b14690b75ec;hb=6c9aa9be32a44d1b2ffd02d211e6e76ec328ee76;hp=def8a40aad42023368097d514335263b7d1e829a;hpb=947962e0b95e10151c186048a8b5cc2fb425838c;p=PuTTY.git diff --git a/unix/uxproxy.c b/unix/uxproxy.c index def8a40a..f92c459b 100644 --- a/unix/uxproxy.c +++ b/unix/uxproxy.c @@ -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,9 +29,8 @@ struct Socket_localproxy_tag { bufchain pending_output_data; bufchain pending_input_data; + bufchain pending_error_data; enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof; - - void *privptr; }; static int localproxy_select_result(int fd, int event); @@ -39,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; @@ -80,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 */ @@ -106,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); } @@ -186,18 +215,6 @@ static void sk_localproxy_flush (Socket s) /* do nothing */ } -static void sk_localproxy_set_private_ptr (Socket s, void *ptr) -{ - Local_Proxy_Socket ps = (Local_Proxy_Socket) s; - ps->privptr = ptr; -} - -static void * sk_localproxy_get_private_ptr (Socket s) -{ - Local_Proxy_Socket ps = (Local_Proxy_Socket) s; - return ps->privptr; -} - static void sk_localproxy_set_frozen (Socket s, int is_frozen) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; @@ -221,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)) @@ -244,7 +268,7 @@ 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, int keepalive, Plug plug, Conf *conf) @@ -258,20 +282,18 @@ Socket platform_new_connection(SockAddr addr, char *hostname, 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], 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; @@ -280,54 +302,111 @@ Socket platform_new_connection(SockAddr addr, 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)); - 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)); - 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]); - fcntl(0, F_SETFD, 0); - fcntl(1, F_SETFD, 0); - 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);