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 diff --git a/screen-write.c b/screen-write.c index 97714a5a..6c24c27b 100644 --- a/screen-write.c +++ b/screen-write.c @@ -172,10 +172,43 @@ screen_write_set_client_cb(struct tty_ctx *ttyctx, struct client *c) return (1); } +/* Return 1 if there is a floating window pane overlapping this pane. */ +static int +screen_write_pane_is_obscured(struct screen_write_ctx *ctx) +{ + struct window_pane *wp = ctx->wp; + + if (ctx->wp == NULL) + return (0); + + if (ctx->flags & SCREEN_WRITE_CHECKED_IF_OBSCURED) { + if (ctx->flags & SCREEN_WRITE_OBSCURED) + return (1); + return (0); + } + ctx->flags |= SCREEN_WRITE_CHECKED_IF_OBSCURED; + + while ((wp = TAILQ_PREV(wp, window_panes, zentry)) != NULL) { + if ((wp->flags & PANE_FLOATING) && + ((wp->yoff >= ctx->wp->yoff && + wp->yoff <= ctx->wp->yoff + (int)ctx->wp->sy) || + (wp->yoff + (int)wp->sy >= ctx->wp->yoff && + wp->yoff + wp->sy <= ctx->wp->yoff + ctx->wp->sy)) && + ((wp->xoff >= ctx->wp->xoff && + wp->xoff <= ctx->wp->xoff + (int)ctx->wp->sx) || + (wp->xoff + (int)wp->sx >= ctx->wp->xoff && + wp->xoff + wp->sx <= ctx->wp->xoff + ctx->wp->sx))) { + ctx->flags |= SCREEN_WRITE_OBSCURED; + return (1); + } + } + return (0); +} + /* Set up context for TTY command. */ static void screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, - int sync) + int is_sync, int check_obscured) { struct screen *s = ctx->s; @@ -190,6 +223,9 @@ screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, ttyctx->orlower = s->rlower; ttyctx->orupper = s->rupper; + if (check_obscured && screen_write_pane_is_obscured(ctx)) + ttyctx->flags |= TTY_CTX_PANE_OBSCURED; + memcpy(&ttyctx->defaults, &grid_default_cell, sizeof ttyctx->defaults); if (ctx->init_ctx_cb != NULL) { ctx->init_ctx_cb(ctx, ttyctx); @@ -221,7 +257,7 @@ screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, else { if (ctx->wp == NULL) ttyctx->flags |= TTY_CTX_OVERLAY_SYNC; - if (sync) + if (is_sync) ttyctx->flags |= TTY_CTX_SYNC; } tty_write(tty_cmd_syncstart, ttyctx); @@ -588,7 +624,7 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src, break; s->cx = cx; if (wp != NULL) - screen_write_initctx(ctx, &ttyctx, 0); + screen_write_initctx(ctx, &ttyctx, 0, 0); for (xx = px; xx < px + nx; xx++) { gl = grid_get_line(gd, yy); sgl = grid_get_line(ctx->s->grid, s->cy); @@ -1096,7 +1132,7 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx) s->rupper = 0; s->rlower = screen_size_y(s) - 1; - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1, 1); screen_write_collect_clear(ctx, 0, screen_size_y(s) - 1); tty_write(tty_cmd_alignmenttest, &ttyctx); @@ -1125,7 +1161,7 @@ screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg) ctx->wp->flags |= PANE_REDRAW; #endif - screen_write_initctx(ctx, &ttyctx, 0); + screen_write_initctx(ctx, &ttyctx, 0, 1); ttyctx.bg = bg; grid_view_insert_cells(s->grid, s->cx, s->cy, nx, bg); @@ -1158,7 +1194,7 @@ screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg) ctx->wp->flags |= PANE_REDRAW; #endif - screen_write_initctx(ctx, &ttyctx, 0); + screen_write_initctx(ctx, &ttyctx, 0, 1); ttyctx.bg = bg; grid_view_delete_cells(s->grid, s->cx, s->cy, nx, bg); @@ -1191,7 +1227,7 @@ screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg) ctx->wp->flags |= PANE_REDRAW; #endif - screen_write_initctx(ctx, &ttyctx, 0); + screen_write_initctx(ctx, &ttyctx, 0, 0); ttyctx.bg = bg; grid_view_clear(s->grid, s->cx, s->cy, nx, 1, bg); @@ -1227,7 +1263,7 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg) if (ny == 0) return; - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1, 1); ttyctx.bg = bg; grid_view_insert_lines(gd, s->cy, ny, bg); @@ -1243,7 +1279,7 @@ screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg) if (ny == 0) return; - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1, 1); ttyctx.bg = bg; if (s->cy < s->rupper || s->cy > s->rlower) @@ -1280,7 +1316,7 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg) if (ny == 0) return; - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1, 1); ttyctx.bg = bg; grid_view_delete_lines(gd, s->cy, ny, bg); @@ -1296,7 +1332,7 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg) if (ny == 0) return; - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1, 1); ttyctx.bg = bg; if (s->cy < s->rupper || s->cy > s->rlower) @@ -1439,7 +1475,7 @@ screen_write_reverseindex(struct screen_write_ctx *ctx, u_int bg) grid_view_scroll_region_down(s->grid, s->rupper, s->rlower, bg); screen_write_collect_flush(ctx, 0, __func__); - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1, 0); ttyctx.bg = bg; tty_write(tty_cmd_reverseindex, &ttyctx); @@ -1550,7 +1586,7 @@ screen_write_scrolldown(struct screen_write_ctx *ctx, u_int lines, u_int bg) struct tty_ctx ttyctx; u_int i; - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1, 1); ttyctx.bg = bg; if (lines == 0) @@ -1592,7 +1628,7 @@ screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg) ctx->wp->flags |= PANE_REDRAW; #endif - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1, 1); ttyctx.bg = bg; /* Scroll into history if it is enabled and clearing entire screen. */ @@ -1626,7 +1662,7 @@ screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg) ctx->wp->flags |= PANE_REDRAW; #endif - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1, 1); ttyctx.bg = bg; if (s->cy > 0) @@ -1654,7 +1690,7 @@ screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg) ctx->wp->flags |= PANE_REDRAW; #endif - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1, 1); ttyctx.bg = bg; /* Scroll into history if it is enabled. */ @@ -1684,7 +1720,7 @@ screen_write_fullredraw(struct screen_write_ctx *ctx) screen_write_collect_flush(ctx, 0, __func__); - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1, 0); if (ttyctx.redraw_cb != NULL) ttyctx.redraw_cb(&ttyctx); } @@ -1846,7 +1882,7 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, if (ctx->scrolled > s->rlower - s->rupper + 1) ctx->scrolled = s->rlower - s->rupper + 1; - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1, 1); ttyctx.n = ctx->scrolled; ttyctx.bg = ctx->bg; tty_write(tty_cmd_scrollup, &ttyctx); @@ -1873,12 +1909,12 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, } screen_write_set_cursor(ctx, ci->x, y); if (ci->type == CLEAR) { - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1, 0); ttyctx.bg = ci->bg; ttyctx.n = ci->used; tty_write(tty_cmd_clearcharacter, &ttyctx); } else { - screen_write_initctx(ctx, &ttyctx, 0); + screen_write_initctx(ctx, &ttyctx, 0, 0); ttyctx.cell = &ci->gc; if (ci->wrapped) ttyctx.flags |= TTY_CTX_WRAPPED; @@ -2101,7 +2137,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) /* Sanity check cursor position. */ if (s->cx > sx - width || s->cy > sy - 1) return; - screen_write_initctx(ctx, &ttyctx, 0); + screen_write_initctx(ctx, &ttyctx, 0, 0); /* Handle overwriting of UTF-8 characters. */ gl = grid_get_line(s->grid, s->grid->hsize + s->cy); @@ -2298,7 +2334,7 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc) * and what it is going to do now. */ screen_write_set_cursor(ctx, cx - n, cy); - screen_write_initctx(ctx, &ttyctx, 0); + screen_write_initctx(ctx, &ttyctx, 0, 0); ttyctx.cell = &last; if (force_wide) ttyctx.flags |= TTY_CTX_CELL_INVALIDATE; @@ -2387,7 +2423,7 @@ screen_write_setselection(struct screen_write_ctx *ctx, const char *clip, { struct tty_ctx ttyctx; - screen_write_initctx(ctx, &ttyctx, 0); + screen_write_initctx(ctx, &ttyctx, 0, 0); ttyctx.sel.clip = clip; ttyctx.sel.data = str; ttyctx.sel.size = len; @@ -2402,7 +2438,7 @@ screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len, { struct tty_ctx ttyctx; - screen_write_initctx(ctx, &ttyctx, 0); + screen_write_initctx(ctx, &ttyctx, 0, 0); if (allow_invisible_panes) ttyctx.flags |= TTY_CTX_INVISIBLE_PANES; ttyctx.data.data = str; @@ -2490,7 +2526,7 @@ screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc, server_redraw_window_borders(wp->window); } - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1, 0); if (ttyctx.redraw_cb != NULL) ttyctx.redraw_cb(&ttyctx); } @@ -2514,7 +2550,7 @@ screen_write_alternateoff(struct screen_write_ctx *ctx, struct grid_cell *gc, server_redraw_window_borders(wp->window); } - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1, 0); if (ttyctx.redraw_cb != NULL) ttyctx.redraw_cb(&ttyctx); } diff --git a/tmux.h b/tmux.h index 869f84eb..8e999942 100644 --- a/tmux.h +++ b/tmux.h @@ -1055,6 +1055,8 @@ struct screen_write_ctx { int flags; #define SCREEN_WRITE_SYNC 0x1 +#define SCREEN_WRITE_OBSCURED 0x2 +#define SCREEN_WRITE_CHECKED_IF_OBSCURED 0x4 screen_write_init_ctx_cb init_ctx_cb; void *arg; @@ -1740,6 +1742,7 @@ struct tty_ctx { #define TTY_CTX_OVERLAY_SYNC 0x10 #define TTY_CTX_CELL_DRAW_LINE 0x20 #define TTY_CTX_CELL_INVALIDATE 0x40 +#define TTY_CTX_PANE_OBSCURED 0x80 union { u_int n;