From 10c38436aae90c61e1b43ffdbd4d10d3eb95fd6a Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:13:56 +0000 Subject: [PATCH] Similarly for MSG_COMMAND - allow full imsg limit not arbitrary 2048. --- client.c | 148 ++++++++++++++++++++++++++++-------------------- server-client.c | 67 +++++++++++----------- server-fn.c | 9 +-- tmux.h | 82 +++++++++++++-------------- 4 files changed, 163 insertions(+), 143 deletions(-) diff --git a/client.c b/client.c index 0101fc0b..5be747dd 100644 --- a/client.c +++ b/client.c @@ -54,7 +54,8 @@ int client_get_lock(char *); int client_connect(char *, int); void client_send_identify(int); void client_send_environ(void); -void client_write_server(enum msgtype, void *, size_t); +int client_write_one(enum msgtype, int, const void *, size_t); +int client_write_server(enum msgtype, const void *, size_t); void client_update_event(void); void client_signal(int, short, void *); void client_stdin_callback(int, short, void *); @@ -165,12 +166,13 @@ client_main(int argc, char **argv, int flags) { struct cmd *cmd; struct cmd_list *cmdlist; - struct msg_command_data cmddata; - int cmdflags, fd; + struct msg_command_data *data; + int cmdflags, fd, i; pid_t ppid; enum msgtype msg; char *cause; struct termios tio, saved_tio; + size_t size; /* Set up the initial command. */ cmdflags = 0; @@ -234,7 +236,7 @@ client_main(int argc, char **argv, int flags) setblocking(STDIN_FILENO, 0); event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST, client_stdin_callback, NULL); - if (flags & IDENTIFY_TERMIOS) { + if (flags & CLIENT_CONTROLCONTROL) { if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) { fprintf(stderr, "tcgetattr failed: %s\n", strerror(errno)); @@ -261,19 +263,32 @@ client_main(int argc, char **argv, int flags) /* Send first command. */ if (msg == MSG_COMMAND) { + /* How big is the command? */ + size = 0; + for (i = 0; i < argc; i++) + size += strlen(argv[i]) + 1; + data = xmalloc((sizeof *data) + size); + /* Fill in command line arguments. */ - cmddata.pid = environ_pid; - cmddata.session_id = environ_session_id; + data->pid = environ_pid; + data->session_id = environ_session_id; /* Prepare command for server. */ - cmddata.argc = argc; - if (cmd_pack_argv( - argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) { + data->argc = argc; + if (cmd_pack_argv(argc, argv, (char*)(data + 1), size) != 0) { fprintf(stderr, "command too long\n"); + free(data); return (1); } + size += sizeof *data; - client_write_server(msg, &cmddata, sizeof cmddata); + /* Send the command. */ + if (client_write_server(msg, data, size) != 0) { + fprintf(stderr, "failed to send command\n"); + free(data); + return (1); + } + free(data); } else if (msg == MSG_SHELL) client_write_server(msg, NULL, 0); @@ -289,14 +304,12 @@ client_main(int argc, char **argv, int flags) ppid = getppid(); if (client_exittype == MSG_DETACHKILL && ppid > 1) kill(ppid, SIGHUP); - } else if (flags & IDENTIFY_TERMIOS) { - if (flags & IDENTIFY_CONTROL) { - if (client_exitreason != CLIENT_EXIT_NONE) - printf("%%exit %s\n", client_exit_message()); - else - printf("%%exit\n"); - printf("\033\\"); - } + } else if (flags & CLIENT_CONTROLCONTROL) { + if (client_exitreason != CLIENT_EXIT_NONE) + printf("%%exit %s\n", client_exit_message()); + else + printf("%%exit\n"); + printf("\033\\"); tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio); } setblocking(STDIN_FILENO, 1); @@ -342,12 +355,29 @@ client_send_environ(void) } } -/* Write a message to the server without a file descriptor. */ -void -client_write_server(enum msgtype type, void *buf, size_t len) +/* Helper to send one message. */ +int +client_write_one(enum msgtype type, int fd, const void *buf, size_t len) { - imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); - client_update_event(); + int retval; + + retval = imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, fd, + (void*)buf, len); + if (retval != 1) + return (-1); + return (0); +} + +/* Write a message to the server without a file descriptor. */ +int +client_write_server(enum msgtype type, const void *buf, size_t len) +{ + int retval; + + retval = client_write_one(type, -1, buf, len); + if (retval == 0) + client_update_event(); + return (retval); } /* Update client event based on whether it needs to read or read and write. */ @@ -481,33 +511,33 @@ client_write(int fd, const char *data, size_t size) /* Dispatch imsgs when in wait state (before MSG_READY). */ int -client_dispatch_wait(void *data) +client_dispatch_wait(void *data0) { - struct imsg imsg; - ssize_t n, datalen; - struct msg_shell_data shelldata; - struct msg_exit_data exitdata; - struct msg_stdout_data stdoutdata; - struct msg_stderr_data stderrdata; - const char *shellcmd = data; + struct imsg imsg; + char *data; + ssize_t n, datalen; + struct msg_stdout_data stdoutdata; + struct msg_stderr_data stderrdata; + int retval; for (;;) { if ((n = imsg_get(&client_ibuf, &imsg)) == -1) fatalx("imsg_get failed"); if (n == 0) return (0); + + data = imsg.data; datalen = imsg.hdr.len - IMSG_HEADER_SIZE; log_debug("got %d from server", imsg.hdr.type); switch (imsg.hdr.type) { case MSG_EXIT: case MSG_SHUTDOWN: - if (datalen != sizeof exitdata) { - if (datalen != 0) - fatalx("bad MSG_EXIT size"); - } else { - memcpy(&exitdata, imsg.data, sizeof exitdata); - client_exitval = exitdata.retcode; + if (datalen != sizeof retval && datalen != 0) + fatalx("bad MSG_EXIT size"); + if (datalen == sizeof retval) { + memcpy(&retval, data, sizeof retval); + client_exitval = retval; } imsg_free(&imsg); return (-1); @@ -527,17 +557,19 @@ client_dispatch_wait(void *data) break; case MSG_STDOUT: if (datalen != sizeof stdoutdata) - fatalx("bad MSG_STDOUT"); - memcpy(&stdoutdata, imsg.data, sizeof stdoutdata); + fatalx("bad MSG_STDOUT size"); + memcpy(&stdoutdata, data, sizeof stdoutdata); - client_write(STDOUT_FILENO, stdoutdata.data, stdoutdata.size); + client_write(STDOUT_FILENO, stdoutdata.data, + stdoutdata.size); break; case MSG_STDERR: if (datalen != sizeof stderrdata) - fatalx("bad MSG_STDERR"); - memcpy(&stderrdata, imsg.data, sizeof stderrdata); + fatalx("bad MSG_STDERR size"); + memcpy(&stderrdata, data, sizeof stderrdata); - client_write(STDERR_FILENO, stderrdata.data, stderrdata.size); + client_write(STDERR_FILENO, stderrdata.data, + stderrdata.size); break; case MSG_VERSION: if (datalen != 0) @@ -551,14 +583,11 @@ client_dispatch_wait(void *data) imsg_free(&imsg); return (-1); case MSG_SHELL: - if (datalen != sizeof shelldata) - fatalx("bad MSG_SHELL size"); - memcpy(&shelldata, imsg.data, sizeof shelldata); - shelldata.shell[(sizeof shelldata.shell) - 1] = '\0'; + if (data[datalen - 1] != '\0') + fatalx("bad MSG_SHELL string"); clear_signals(0); - - shell_exec(shelldata.shell, shellcmd); + shell_exec(data, data0); /* NOTREACHED */ case MSG_DETACH: client_write_server(MSG_EXITING, NULL, 0); @@ -578,16 +607,18 @@ client_dispatch_wait(void *data) int client_dispatch_attached(void) { - struct imsg imsg; - struct msg_lock_data lockdata; - struct sigaction sigact; - ssize_t n, datalen; + struct imsg imsg; + struct sigaction sigact; + char *data; + ssize_t n, datalen; for (;;) { if ((n = imsg_get(&client_ibuf, &imsg)) == -1) fatalx("imsg_get failed"); if (n == 0) return (0); + + data = imsg.data; datalen = imsg.hdr.len - IMSG_HEADER_SIZE; log_debug("got %d from server", imsg.hdr.type); @@ -605,8 +636,7 @@ client_dispatch_attached(void) client_write_server(MSG_EXITING, NULL, 0); break; case MSG_EXIT: - if (datalen != 0 && - datalen != sizeof (struct msg_exit_data)) + if (datalen != 0 && datalen != sizeof (int)) fatalx("bad MSG_EXIT size"); client_write_server(MSG_EXITING, NULL, 0); @@ -639,12 +669,10 @@ client_dispatch_attached(void) kill(getpid(), SIGTSTP); break; case MSG_LOCK: - if (datalen != sizeof lockdata) - fatalx("bad MSG_LOCK size"); - memcpy(&lockdata, imsg.data, sizeof lockdata); + if (data[datalen - 1] != '\0') + fatalx("bad MSG_LOCK string"); - lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0'; - system(lockdata.cmd); + system(data); client_write_server(MSG_UNLOCK, NULL, 0); break; default: 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; + struct msg_command_data data; + char *buf; + size_t len; + 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) { + 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 */ } diff --git a/server-fn.c b/server-fn.c index fb0eadd6..f6485b49 100644 --- a/server-fn.c +++ b/server-fn.c @@ -235,9 +235,7 @@ server_lock_session(struct session *s) void server_lock_client(struct client *c) { - const char *cmd; - size_t cmdlen; - struct msg_lock_data lockdata; + const char *cmd; if (c->flags & CLIENT_CONTROL) return; @@ -246,8 +244,7 @@ server_lock_client(struct client *c) return; cmd = options_get_string(&c->session->options, "lock-command"); - cmdlen = strlcpy(lockdata.cmd, cmd, sizeof lockdata.cmd); - if (cmdlen >= sizeof lockdata.cmd) + if (strlen(cmd) + 1 > MAX_IMSGSIZE - IMSG_HEADER_SIZE) return; tty_stop_tty(&c->tty); @@ -256,7 +253,7 @@ server_lock_client(struct client *c) tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_E3)); c->flags |= CLIENT_SUSPENDED; - server_write_client(c, MSG_LOCK, &lockdata, sizeof lockdata); + server_write_client(c, MSG_LOCK, cmd, strlen(cmd) + 1); } void diff --git a/tmux.h b/tmux.h index 891f6233..2d631a17 100644 --- a/tmux.h +++ b/tmux.h @@ -19,7 +19,7 @@ #ifndef TMUX_H #define TMUX_H -#define PROTOCOL_VERSION 7 +#define PROTOCOL_VERSION 8 #include #include @@ -62,7 +62,6 @@ extern char **environ; * Maximum sizes of strings in message data. Don't forget to bump * PROTOCOL_VERSION if any of these change! */ -#define COMMAND_LENGTH 2048 /* packed argv size */ #define TERMINAL_LENGTH 128 /* length of TERM environment variable */ #define ENVIRON_LENGTH 1024 /* environment variable length */ @@ -437,27 +436,36 @@ ARRAY_DECL(causelist, char *); /* Message codes. */ enum msgtype { - MSG_COMMAND, + MSG_VERSION = 12, + + MSG_IDENTIFY_FLAGS = 100, + MSG_IDENTIFY_TERM, + MSG_IDENTIFY_TTYNAME, + MSG_IDENTIFY_CWD, + MSG_IDENTIFY_STDIN, + MSG_IDENTIFY_ENVIRON, + MSG_IDENTIFY_DONE, + + MSG_COMMAND = 200, MSG_DETACH, - MSG_ERROR, + MSG_DETACHKILL, MSG_EXIT, MSG_EXITED, MSG_EXITING, - MSG_IDENTIFY, - MSG_STDIN, + MSG_LOCK, MSG_READY, MSG_RESIZE, - MSG_SHUTDOWN, - MSG_SUSPEND, - MSG_VERSION, - MSG_WAKEUP, - MSG_ENVIRON, - MSG_UNLOCK, - MSG_LOCK, MSG_SHELL, + MSG_SHUTDOWN, MSG_STDERR, + MSG_STDIN, MSG_STDOUT, - MSG_DETACHKILL + MSG_SUSPEND, + MSG_UNLOCK, + MSG_WAKEUP, + + MSG_IDENTIFY = 300, + MSG_ENVIRON }; /* @@ -466,42 +474,23 @@ enum msgtype { * Don't forget to bump PROTOCOL_VERSION if any of these change! */ struct msg_command_data { - pid_t pid; /* from $TMUX or -1 */ - int session_id; /* from $TMUX or -1 */ + pid_t pid; /* from $TMUX or -1 */ + int session_id; /* from $TMUX or -1 */ - int argc; - char argv[COMMAND_LENGTH]; -}; + int argc; +}; /* followed by packed argv */ struct msg_identify_data { char cwd[MAXPATHLEN]; - char term[TERMINAL_LENGTH]; -#define IDENTIFY_UTF8 0x1 -#define IDENTIFY_256COLOURS 0x2 -/* 0x4 unused */ -#define IDENTIFY_CONTROL 0x8 -#define IDENTIFY_TERMIOS 0x10 int flags; }; -struct msg_lock_data { - char cmd[COMMAND_LENGTH]; -}; - struct msg_environ_data { char var[ENVIRON_LENGTH]; }; -struct msg_shell_data { - char shell[MAXPATHLEN]; -}; - -struct msg_exit_data { - int retcode; -}; - struct msg_stdin_data { ssize_t size; char data[BUFSIZ]; @@ -1294,8 +1283,9 @@ RB_HEAD(status_out_tree, status_out); /* Client connection. */ struct client { struct imsgbuf ibuf; + struct event event; - int retcode; + int retval; struct timeval creation_time; struct timeval activity_time; @@ -1326,7 +1316,7 @@ struct client { #define CLIENT_EXIT 0x4 #define CLIENT_REDRAW 0x8 #define CLIENT_STATUS 0x10 -#define CLIENT_REPEAT 0x20 /* allow command to repeat within repeat time */ +#define CLIENT_REPEAT 0x20 #define CLIENT_SUSPENDED 0x40 #define CLIENT_BAD 0x80 #define CLIENT_IDENTIFY 0x100 @@ -1335,7 +1325,11 @@ struct client { #define CLIENT_READONLY 0x800 #define CLIENT_REDRAWWINDOW 0x1000 #define CLIENT_CONTROL 0x2000 -#define CLIENT_FOCUSED 0x4000 +#define CLIENT_CONTROLCONTROL 0x4000 +#define CLIENT_FOCUSED 0x8000 +#define CLIENT_UTF8 0x10000 +#define CLIENT_256COLOURS 0x20000 +#define CLIENT_IDENTIFIED 0x40000 int flags; struct event identify_timer; @@ -1925,10 +1919,10 @@ void server_window_loop(void); /* server-fn.c */ void server_fill_environ(struct session *, struct environ *); void server_write_ready(struct client *); -int server_write_client( - struct client *, enum msgtype, const void *, size_t); -void server_write_session( - struct session *, enum msgtype, const void *, size_t); +int server_write_client(struct client *, enum msgtype, const void *, + size_t); +void server_write_session(struct session *, enum msgtype, const void *, + size_t); void server_redraw_client(struct client *); void server_status_client(struct client *); void server_redraw_session(struct session *);