diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 4e2d15da..32b1e0cb 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -61,6 +61,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag, struct window_pane *wp; char *cwd, *cause; enum msgtype msgtype; + uid_t uid; if (RB_EMPTY(&sessions)) { cmdq_error(item, "no sessions"); @@ -106,8 +107,16 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag, } if (fflag) server_client_set_flags(c, fflag); - if (rflag) + if (rflag) { + if (c->flags & CLIENT_READONLY) { + uid = proc_get_peer_uid(c->peer); + if (uid != getuid()) { + cmdq_error(item, "client is read-only"); + return (CMD_RETURN_ERROR); + } + } c->flags |= (CLIENT_READONLY|CLIENT_IGNORESIZE); + } c->last_session = c->session; if (c->session != NULL) { diff --git a/cmd-detach-client.c b/cmd-detach-client.c index 661293ae..b5a4cf1c 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -59,6 +59,7 @@ cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item) { struct args *args = cmd_get_args(self); struct cmd_find_state *source = cmdq_get_source(item); + struct client *c = cmdq_get_client(item); struct client *tc = cmdq_get_target_client(item), *loop; struct session *s; enum msgtype msgtype; @@ -69,6 +70,13 @@ cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_NORMAL); } + if (c->flags & CLIENT_READONLY) { + if (args_has(args, 's') || args_has(args, 'a') || c != tc) { + cmdq_error(item, "client is read-only"); + return (CMD_RETURN_ERROR); + } + } + if (args_has(args, 'P')) msgtype = MSG_DETACHKILL; else diff --git a/cmd-switch-client.c b/cmd-switch-client.c index b0a0d928..9865ac52 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -20,6 +20,7 @@ #include #include +#include #include "tmux.h" @@ -53,6 +54,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item) const char *tflag = args_get(args, 't'); enum cmd_find_type type; int flags; + struct client *c = cmdq_get_client(item); struct client *tc = cmdq_get_target_client(item); struct session *s; struct winlink *wl; @@ -61,6 +63,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item) const char *tablename; struct key_table *table; struct sort_criteria sort_crit; + uid_t uid; if (tflag != NULL && (tflag[strcspn(tflag, ":.%")] != '\0' || strcmp(tflag, "=") == 0)) { @@ -77,6 +80,13 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item) wp = target.wp; if (args_has(args, 'r')) { + if (tc->flags & CLIENT_READONLY) { + uid = proc_get_peer_uid(c->peer); + if (uid != getuid()) { + cmdq_error(item, "client is read-only"); + return (CMD_RETURN_ERROR); + } + } if (tc->flags & CLIENT_READONLY) tc->flags &= ~(CLIENT_READONLY|CLIENT_IGNORESIZE); else