From 47a4a9992c59199bb55188c666eddce7895d884e Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 11:49:07 +0000 Subject: Allow the file descriptor received from the client to be -1. --- server-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'server-client.c') diff --git a/server-client.c b/server-client.c index 5f61f5c0..44119237 100644 --- a/server-client.c +++ b/server-client.c @@ -825,8 +825,6 @@ server_client_msg_dispatch(struct client *c) case MSG_IDENTIFY: if (datalen != sizeof identifydata) fatalx("bad MSG_IDENTIFY size"); - if (imsg.fd == -1) - fatalx("MSG_IDENTIFY missing fd"); memcpy(&identifydata, imsg.data, sizeof identifydata); server_client_msg_identify(c, &identifydata, imsg.fd); @@ -972,6 +970,8 @@ server_client_msg_identify( return; } + if (fd == -1) + return; if (!isatty(fd)) { close(fd); return; -- cgit From 10c38436aae90c61e1b43ffdbd4d10d3eb95fd6a Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:13:56 +0000 Subject: Similarly for MSG_COMMAND - allow full imsg limit not arbitrary 2048. --- server-client.c | 69 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 34 deletions(-) (limited to 'server-client.c') diff --git a/server-client.c b/server-client.c index 44119237..4bba5f7d 100644 --- a/server-client.c +++ b/server-client.c @@ -40,7 +40,7 @@ void server_client_reset_state(struct client *); int server_client_assume_paste(struct session *); int server_client_msg_dispatch(struct client *); -void server_client_msg_command(struct client *, struct msg_command_data *); +void server_client_msg_command(struct client *, struct imsg *); void server_client_msg_identify( struct client *, struct msg_identify_data *, int); void server_client_msg_shell(struct client *); @@ -695,8 +695,6 @@ server_client_repeat_timer(unused int fd, unused short events, void *data) void server_client_check_exit(struct client *c) { - struct msg_exit_data exitdata; - if (!(c->flags & CLIENT_EXIT)) return; @@ -707,9 +705,7 @@ server_client_check_exit(struct client *c) if (EVBUFFER_LENGTH(c->stderr_data) != 0) return; - exitdata.retcode = c->retcode; - server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata); - + server_write_client(c, MSG_EXIT, &c->retval, sizeof c->retval); c->flags &= ~CLIENT_EXIT; } @@ -790,10 +786,10 @@ int server_client_msg_dispatch(struct client *c) { struct imsg imsg; - struct msg_command_data commanddata; struct msg_identify_data identifydata; struct msg_environ_data environdata; struct msg_stdin_data stdindata; + const char *data; ssize_t n, datalen; if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) @@ -804,6 +800,8 @@ server_client_msg_dispatch(struct client *c) return (-1); if (n == 0) return (0); + + data = imsg.data; datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (imsg.hdr.peerid != PROTOCOL_VERSION) { @@ -815,13 +813,6 @@ server_client_msg_dispatch(struct client *c) log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd); switch (imsg.hdr.type) { - case MSG_COMMAND: - if (datalen != sizeof commanddata) - fatalx("bad MSG_COMMAND size"); - memcpy(&commanddata, imsg.data, sizeof commanddata); - - server_client_msg_command(c, &commanddata); - break; case MSG_IDENTIFY: if (datalen != sizeof identifydata) fatalx("bad MSG_IDENTIFY size"); @@ -829,10 +820,13 @@ server_client_msg_dispatch(struct client *c) server_client_msg_identify(c, &identifydata, imsg.fd); break; + case MSG_COMMAND: + server_client_msg_command(c, &imsg); + break; case MSG_STDIN: if (datalen != sizeof stdindata) fatalx("bad MSG_STDIN size"); - memcpy(&stdindata, imsg.data, sizeof stdindata); + memcpy(&stdindata, data, sizeof stdindata); if (c->stdin_callback == NULL) break; @@ -907,15 +901,26 @@ server_client_msg_dispatch(struct client *c) /* Handle command message. */ void -server_client_msg_command(struct client *c, struct msg_command_data *data) +server_client_msg_command(struct client *c, struct imsg *imsg) { - struct cmd_list *cmdlist = NULL; - int argc; - char **argv, *cause; - - argc = data->argc; - data->argv[(sizeof data->argv) - 1] = '\0'; - if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) { + struct msg_command_data data; + char *buf; + size_t len; + struct cmd_list *cmdlist = NULL; + int argc; + char **argv, *cause; + + if (imsg->hdr.len - IMSG_HEADER_SIZE < sizeof data) + fatalx("bad MSG_COMMAND size"); + memcpy(&data, imsg->data, sizeof data); + + buf = (char*)imsg->data + sizeof data; + len = imsg->hdr.len - IMSG_HEADER_SIZE - sizeof data; + if (len > 0 && buf[len - 1] != '\0') + fatalx("bad MSG_COMMAND string"); + + argc = data.argc; + if (cmd_unpack_argv(buf, len, argc, &argv) != 0) { cmdq_error(c->cmdq, "command too long"); goto error; } @@ -954,12 +959,12 @@ server_client_msg_identify( if (*data->cwd != '\0') c->cwd = xstrdup(data->cwd); - if (data->flags & IDENTIFY_CONTROL) { + if (data->flags & CLIENT_CONTROL) { c->stdin_callback = control_callback; evbuffer_free(c->stderr_data); c->stderr_data = c->stdout_data; c->flags |= CLIENT_CONTROL; - if (data->flags & IDENTIFY_TERMIOS) + if (data->flags & CLIENT_CONTROLCONTROL) evbuffer_add_printf(c->stdout_data, "\033P1000p"); server_write_client(c, MSG_STDIN, NULL, 0); @@ -978,14 +983,14 @@ server_client_msg_identify( } data->term[(sizeof data->term) - 1] = '\0'; tty_init(&c->tty, c, fd, data->term); - if (data->flags & IDENTIFY_UTF8) + if (data->flags & CLIENT_UTF8) c->tty.flags |= TTY_UTF8; - if (data->flags & IDENTIFY_256COLOURS) + if (data->flags & CLIENT_256COLOURS) c->tty.term_flags |= TERM_256COLOURS; tty_resize(&c->tty); - if (!(data->flags & IDENTIFY_CONTROL)) + if (!(data->flags & CLIENT_CONTROL)) c->flags |= CLIENT_TERMINAL; } @@ -993,16 +998,12 @@ server_client_msg_identify( void server_client_msg_shell(struct client *c) { - struct msg_shell_data data; - const char *shell; + const char *shell; shell = options_get_string(&global_s_options, "default-shell"); - if (*shell == '\0' || areshell(shell)) shell = _PATH_BSHELL; - if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell) - strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell); + server_write_client(c, MSG_SHELL, shell, strlen(shell) + 1); - server_write_client(c, MSG_SHELL, &data, sizeof data); c->flags |= CLIENT_BAD; /* it will die after exec */ } -- cgit From 282c5f9644ed262ee15efbd3d072f7acc577da15 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:26:34 +0000 Subject: Alter how tmux handles the working directory to internally use file descriptors rather than strings. - Each session still has a current working directory. - New sessions still get their working directory from the client that created them or its attached session if any. - New windows are created by default in the session working directory. - The -c flag to new, neww, splitw allows the working directory to be overridden. - The -c flag to attach let's the session working directory be changed. - The default-path option has been removed. To get the equivalent to default-path '.', do: bind c neww -c $PWD To get the equivalent of default-path '~', do: bind c neww -c ~ This also changes the client identify protocol to be a set of messages rather than one as well as some other changes that should make it easier to make backwards-compatible protocol changes in future. --- server-client.c | 123 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 83 insertions(+), 40 deletions(-) (limited to 'server-client.c') diff --git a/server-client.c b/server-client.c index 4bba5f7d..a39f56d8 100644 --- a/server-client.c +++ b/server-client.c @@ -41,8 +41,7 @@ int server_client_assume_paste(struct session *); int server_client_msg_dispatch(struct client *); void server_client_msg_command(struct client *, struct imsg *); -void server_client_msg_identify( - struct client *, struct msg_identify_data *, int); +void server_client_msg_identify(struct client *, struct imsg *); void server_client_msg_shell(struct client *); /* Create a new client. */ @@ -151,6 +150,8 @@ server_client_lost(struct client *c) */ if (c->flags & CLIENT_TERMINAL) tty_free(&c->tty); + free(c->ttyname); + free(c->term); evbuffer_free (c->stdin_data); evbuffer_free (c->stdout_data); @@ -162,6 +163,7 @@ server_client_lost(struct client *c) screen_free(&c->status); free(c->title); + close(c->cwd); evtimer_del(&c->repeat_timer); @@ -179,7 +181,6 @@ server_client_lost(struct client *c) free(c->prompt_string); free(c->prompt_buffer); - free(c->cwd); c->cmdq->dead = 1; cmdq_free(c->cmdq); @@ -786,8 +787,6 @@ int server_client_msg_dispatch(struct client *c) { struct imsg imsg; - struct msg_identify_data identifydata; - struct msg_environ_data environdata; struct msg_stdin_data stdindata; const char *data; ssize_t n, datalen; @@ -813,12 +812,14 @@ server_client_msg_dispatch(struct client *c) log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd); switch (imsg.hdr.type) { - case MSG_IDENTIFY: - if (datalen != sizeof identifydata) - fatalx("bad MSG_IDENTIFY size"); - memcpy(&identifydata, imsg.data, sizeof identifydata); - - server_client_msg_identify(c, &identifydata, imsg.fd); + case MSG_IDENTIFY_FLAGS: + case MSG_IDENTIFY_TERM: + case MSG_IDENTIFY_TTYNAME: + case MSG_IDENTIFY_CWD: + case MSG_IDENTIFY_STDIN: + case MSG_IDENTIFY_ENVIRON: + case MSG_IDENTIFY_DONE: + server_client_msg_identify(c, &imsg); break; case MSG_COMMAND: server_client_msg_command(c, &imsg); @@ -876,23 +877,12 @@ server_client_msg_dispatch(struct client *c) server_redraw_client(c); recalculate_sizes(); break; - case MSG_ENVIRON: - if (datalen != sizeof environdata) - fatalx("bad MSG_ENVIRON size"); - memcpy(&environdata, imsg.data, sizeof environdata); - - environdata.var[(sizeof environdata.var) - 1] = '\0'; - if (strchr(environdata.var, '=') != NULL) - environ_put(&c->environ, environdata.var); - break; case MSG_SHELL: if (datalen != 0) fatalx("bad MSG_SHELL size"); server_client_msg_shell(c); break; - default: - fatalx("unexpected message"); } imsg_free(&imsg); @@ -951,46 +941,99 @@ error: /* Handle identify message. */ void -server_client_msg_identify( - struct client *c, struct msg_identify_data *data, int fd) +server_client_msg_identify(struct client *c, struct imsg *imsg) { - c->cwd = NULL; - data->cwd[(sizeof data->cwd) - 1] = '\0'; - if (*data->cwd != '\0') - c->cwd = xstrdup(data->cwd); + const char *data; + size_t datalen; + int flags; + + if (c->flags & CLIENT_IDENTIFIED) + fatalx("out-of-order identify message"); + + data = imsg->data; + datalen = imsg->hdr.len - IMSG_HEADER_SIZE; + + switch (imsg->hdr.type) { + case MSG_IDENTIFY_FLAGS: + if (datalen != sizeof flags) + fatalx("bad MSG_IDENTIFY_FLAGS size"); + memcpy(&flags, data, sizeof flags); + c->flags |= flags; + break; + case MSG_IDENTIFY_TERM: + if (data[datalen - 1] != '\0') + fatalx("bad MSG_IDENTIFY_TERM string"); + c->term = xstrdup(data); + break; + case MSG_IDENTIFY_TTYNAME: + if (data[datalen - 1] != '\0') + fatalx("bad MSG_IDENTIFY_TTYNAME string"); + c->ttyname = xstrdup(data); + break; + case MSG_IDENTIFY_CWD: + if (datalen != 0) + fatalx("bad MSG_IDENTIFY_CWD size"); + c->cwd = imsg->fd; + break; + case MSG_IDENTIFY_STDIN: + if (datalen != 0) + fatalx("bad MSG_IDENTIFY_STDIN size"); + c->fd = imsg->fd; + break; + case MSG_IDENTIFY_ENVIRON: + if (data[datalen - 1] != '\0') + fatalx("bad MSG_IDENTIFY_ENVIRON string"); + if (strchr(data, '=') != NULL) + environ_put(&c->environ, data); + break; + default: + break; + } + + if (imsg->hdr.type != MSG_IDENTIFY_DONE) + return; + c->flags |= CLIENT_IDENTIFIED; - if (data->flags & CLIENT_CONTROL) { +#ifdef __CYGWIN__ + c->fd = open(c->ttyname, O_RDWR|O_NOCTTY); + c->cwd = open(".", O_RDONLY); +#endif + + if (c->flags & CLIENT_CONTROL) { c->stdin_callback = control_callback; + evbuffer_free(c->stderr_data); c->stderr_data = c->stdout_data; - c->flags |= CLIENT_CONTROL; - if (data->flags & CLIENT_CONTROLCONTROL) + + if (c->flags & CLIENT_CONTROLCONTROL) evbuffer_add_printf(c->stdout_data, "\033P1000p"); server_write_client(c, MSG_STDIN, NULL, 0); c->tty.fd = -1; c->tty.log_fd = -1; - close(fd); + close(c->fd); + c->fd = -1; + return; } - if (fd == -1) + if (c->fd == -1) return; - if (!isatty(fd)) { - close(fd); + if (!isatty(c->fd)) { + close(c->fd); + c->fd = -1; return; } - data->term[(sizeof data->term) - 1] = '\0'; - tty_init(&c->tty, c, fd, data->term); - if (data->flags & CLIENT_UTF8) + tty_init(&c->tty, c, c->fd, c->term); + if (c->flags & CLIENT_UTF8) c->tty.flags |= TTY_UTF8; - if (data->flags & CLIENT_256COLOURS) + if (c->flags & CLIENT_256COLOURS) c->tty.term_flags |= TERM_256COLOURS; tty_resize(&c->tty); - if (!(data->flags & CLIENT_CONTROL)) + if (!(c->flags & CLIENT_CONTROL)) c->flags |= CLIENT_TERMINAL; } -- cgit From b8b85fbb0c6cf4e9a3fa650ec7dc5036a1b0b01a Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:27:38 +0000 Subject: Don't look at string[length - 1] if length == 0. --- server-client.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'server-client.c') diff --git a/server-client.c b/server-client.c index a39f56d8..e202902e 100644 --- a/server-client.c +++ b/server-client.c @@ -961,12 +961,12 @@ server_client_msg_identify(struct client *c, struct imsg *imsg) c->flags |= flags; break; case MSG_IDENTIFY_TERM: - if (data[datalen - 1] != '\0') + if (datalen == 0 || data[datalen - 1] != '\0') fatalx("bad MSG_IDENTIFY_TERM string"); c->term = xstrdup(data); break; case MSG_IDENTIFY_TTYNAME: - if (data[datalen - 1] != '\0') + if (datalen == 0 || data[datalen - 1] != '\0') fatalx("bad MSG_IDENTIFY_TTYNAME string"); c->ttyname = xstrdup(data); break; @@ -981,7 +981,7 @@ server_client_msg_identify(struct client *c, struct imsg *imsg) c->fd = imsg->fd; break; case MSG_IDENTIFY_ENVIRON: - if (data[datalen - 1] != '\0') + if (datalen == 0 || data[datalen - 1] != '\0') fatalx("bad MSG_IDENTIFY_ENVIRON string"); if (strchr(data, '=') != NULL) environ_put(&c->environ, data); -- cgit From c1ccefc62d2a70c91ac31cff141031d61cc0a12c Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:29:35 +0000 Subject: We accidentally haven't been using $TMUX to work out the session for a while and in fact it is less useful that using the client ttyname. So don't bother and don't pass it from the client. If we need it in future it is in c->environ. --- server-client.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'server-client.c') diff --git a/server-client.c b/server-client.c index e202902e..6aa2a0fa 100644 --- a/server-client.c +++ b/server-client.c @@ -62,6 +62,8 @@ server_client_create(int fd) fatal("gettimeofday failed"); memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time); + environ_init(&c->environ); + c->cmdq = cmdq_new(c); c->cmdq->client_exit = 1; -- cgit From 4901d9ddc8d8c33ecdca363dcb67e66482745fa5 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 11 Oct 2013 08:07:12 +0000 Subject: Don't leak file descriptors in the rare MSG_VERSION case. From Chris Johnsen. --- server-client.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'server-client.c') diff --git a/server-client.c b/server-client.c index 6aa2a0fa..b6d4870d 100644 --- a/server-client.c +++ b/server-client.c @@ -808,6 +808,8 @@ server_client_msg_dispatch(struct client *c) if (imsg.hdr.peerid != PROTOCOL_VERSION) { server_write_client(c, MSG_VERSION, NULL, 0); c->flags |= CLIENT_BAD; + if (imsg.fd != -1) + close(imsg.fd); imsg_free(&imsg); continue; } -- cgit