From da8468681b62b5723afaedc2afcd0918bdd50e41 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 15 Jun 2026 21:41:39 +0000 Subject: [PATCH] Be more strict about what names and titles we allow and reject them immediately when possible, but allow # again for those directly set by commands (but not escape sequences). From Barrett Ruth in GitHub issue 5175. --- usr.bin/tmux/cmd-break-pane.c | 25 +++++++------ usr.bin/tmux/cmd-new-session.c | 60 ++++++++++++++++++------------- usr.bin/tmux/cmd-new-window.c | 35 +++++++++++++----- usr.bin/tmux/cmd-rename-session.c | 8 ++--- usr.bin/tmux/cmd-rename-window.c | 16 ++++++--- usr.bin/tmux/cmd-select-pane.c | 4 +-- usr.bin/tmux/cmd-split-window.c | 4 +-- usr.bin/tmux/input.c | 12 +++---- usr.bin/tmux/names.c | 6 ++-- usr.bin/tmux/paste.c | 4 +-- usr.bin/tmux/popup.c | 4 +-- usr.bin/tmux/screen.c | 16 ++++++--- usr.bin/tmux/session.c | 3 +- usr.bin/tmux/spawn.c | 18 ++++------ usr.bin/tmux/tmux.c | 21 ++++++++++- usr.bin/tmux/tmux.h | 15 +++++--- usr.bin/tmux/window.c | 8 ++--- 17 files changed, 161 insertions(+), 98 deletions(-) diff --git a/usr.bin/tmux/cmd-break-pane.c b/usr.bin/tmux/cmd-break-pane.c index a82837259f4..167a369d274 100644 --- a/usr.bin/tmux/cmd-break-pane.c +++ b/usr.bin/tmux/cmd-break-pane.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-break-pane.c,v 1.66 2026/05/19 12:16:25 nicm Exp $ */ +/* $OpenBSD: cmd-break-pane.c,v 1.67 2026/06/15 21:41:39 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -58,9 +58,14 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item) struct session *dst_s = target->s; struct window_pane *wp = source->wp; struct window *w = wl->window; - char *name, *cause, *cp; + char *newname, *cause, *cp; int idx = target->idx, before; - const char *template; + const char *template, *name = args_get(args, 'n'); + + if (name != NULL && !check_name(name, WINDOW_NAME_FORBID)) { + cmdq_error(item, "invalid window name: %s", name); + return (CMD_RETURN_ERROR); + } before = args_has(args, 'b'); if (args_has(args, 'a') || before) { @@ -80,8 +85,8 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item) free(cause); return (CMD_RETURN_ERROR); } - if (args_has(args, 'n')) { - window_set_name(w, args_get(args, 'n')); + if (name != NULL) { + window_set_name(w, name, WINDOW_NAME_FORBID); options_set_number(w->options, "automatic-rename", 0); } server_unlink_window(src_s, wl); @@ -109,12 +114,12 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item) w->active = wp; w->latest = tc; - if (!args_has(args, 'n')) { - name = default_window_name(w); - window_set_name(w, name); - free(name); + if (name != NULL) { + newname = default_window_name(w); + window_set_name(w, newname, WINDOW_NAME_FORBID); + free(newname); } else { - window_set_name(w, args_get(args, 'n')); + window_set_name(w, name, 0); options_set_number(w->options, "automatic-rename", 0); } diff --git a/usr.bin/tmux/cmd-new-session.c b/usr.bin/tmux/cmd-new-session.c index d63f7674bbd..f195648f90e 100644 --- a/usr.bin/tmux/cmd-new-session.c +++ b/usr.bin/tmux/cmd-new-session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-new-session.c,v 1.149 2026/04/22 07:10:16 nicm Exp $ */ +/* $OpenBSD: cmd-new-session.c,v 1.150 2026/06/15 21:41:39 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -77,8 +77,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) struct termios tio, *tiop; struct session_group *sg = NULL; const char *errstr, *template, *group, *tmp; - char *cause, *cwd = NULL, *cp, *newname = NULL; - char *name, *prefix = NULL; + char *cause, *cwd = NULL, *cp, *ename; + char *wname = NULL, *sname = NULL, *prefix = NULL; int detached, already_attached, is_control = 0; u_int sx, sy, dsx, dsy, count = args_count(args); struct spawn_context sc = { 0 }; @@ -99,20 +99,29 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_ERROR); } - tmp = args_get(args, 's'); - if (tmp != NULL) { - name = format_single(item, tmp, c, NULL, NULL, NULL); - newname = clean_name(name, "#:."); - if (newname == NULL) { - cmdq_error(item, "invalid session: %s", name); - free(name); + if ((tmp = args_get(args, 'n')) != NULL) { + ename = format_single(item, tmp, c, NULL, NULL, NULL); + if (!check_name(ename, WINDOW_NAME_FORBID)) { + cmdq_error(item, "invalid window name: %s", ename); + free(ename); return (CMD_RETURN_ERROR); } - free(name); + wname = clean_name(ename, WINDOW_NAME_FORBID); + free(ename); + } + if ((tmp = args_get(args, 's')) != NULL) { + ename = format_single(item, tmp, c, NULL, NULL, NULL); + if (!check_name(ename, SESSION_NAME_FORBID)) { + cmdq_error(item, "invalid session name: %s", ename); + free(ename); + goto fail; + } + sname = clean_name(ename, SESSION_NAME_FORBID); + free(ename); } if (args_has(args, 'A')) { - if (newname != NULL) - as = session_find(newname); + if (sname != NULL) + as = session_find(sname); else as = target->s; if (as != NULL) { @@ -120,12 +129,13 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) args_has(args, 'D'), args_has(args, 'X'), 0, args_get(args, 'c'), args_has(args, 'E'), args_get(args, 'f')); - free(newname); + free(wname); + free(sname); return (retval); } } - if (newname != NULL && session_find(newname) != NULL) { - cmdq_error(item, "duplicate session: %s", newname); + if (sname != NULL && session_find(sname) != NULL) { + cmdq_error(item, "duplicate session: %s", sname); goto fail; } @@ -142,12 +152,12 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) else if (groupwith != NULL) prefix = xstrdup(groupwith->name); else { - prefix = clean_name(group, "#:."); - if (prefix == NULL) { - cmdq_error(item, "invalid session group: %s", - group); + if (!check_name(group, SESSION_NAME_FORBID)) { + cmdq_error(item, + "invalid session group name: %s", group); goto fail; } + prefix = clean_name(group, SESSION_NAME_FORBID); } } @@ -276,7 +286,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) environ_put(env, av->string, 0); av = args_next_value(av); } - s = session_create(prefix, newname, cwd, env, oo, tiop); + s = session_create(prefix, sname, cwd, env, oo, tiop); /* Spawn the initial window. */ sc.item = item; @@ -284,7 +294,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) if (!detached) sc.tc = c; - sc.name = args_get(args, 'n'); + sc.name = wname; args_to_vector(args, &sc.argc, &sc.argv); sc.idx = -1; @@ -357,7 +367,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) if (sc.argv != NULL) cmd_free_argv(sc.argc, sc.argv); free(cwd); - free(newname); + free(wname); + free(sname); free(prefix); return (CMD_RETURN_NORMAL); @@ -365,7 +376,8 @@ fail: if (sc.argv != NULL) cmd_free_argv(sc.argc, sc.argv); free(cwd); - free(newname); + free(wname); + free(sname); free(prefix); return (CMD_RETURN_ERROR); } diff --git a/usr.bin/tmux/cmd-new-window.c b/usr.bin/tmux/cmd-new-window.c index ece06e5106b..c1b4999012b 100644 --- a/usr.bin/tmux/cmd-new-window.c +++ b/usr.bin/tmux/cmd-new-window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-new-window.c,v 1.98 2025/04/09 07:03:04 nicm Exp $ */ +/* $OpenBSD: cmd-new-window.c,v 1.99 2026/06/15 21:41:39 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -61,7 +61,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) struct session *s = target->s; struct winlink *wl = target->wl, *new_wl = NULL; int idx = target->idx, before; - char *cause = NULL, *cp, *expanded; + char *cause = NULL, *cp, *expanded, *wname; const char *template, *name; struct cmd_find_state fs; struct args_value *av; @@ -71,8 +71,18 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) * name already exists, select it. */ name = args_get(args, 'n'); - if (args_has(args, 'S') && name != NULL && target->idx == -1) { + if (name != NULL) { expanded = format_single(item, name, c, s, NULL, NULL); + if (!check_name(expanded, WINDOW_NAME_FORBID)) { + cmdq_error(item, "invalid window name: %s", expanded); + free(expanded); + return (CMD_RETURN_ERROR); + } + wname = clean_name(expanded, WINDOW_NAME_FORBID); + free(expanded); + } + if (args_has(args, 'S') && wname != NULL && target->idx == -1) { + expanded = format_single(item, wname, c, s, NULL, NULL); RB_FOREACH(wl, winlinks, &s->windows) { if (strcmp(wl->window->name, expanded) != 0) continue; @@ -80,12 +90,14 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) new_wl = wl; continue; } - cmdq_error(item, "multiple windows named %s", name); + cmdq_error(item, "multiple windows named %s", wname); + free(wname); free(expanded); return (CMD_RETURN_ERROR); } free(expanded); if (new_wl != NULL) { + free(wname); if (args_has(args, 'd')) return (CMD_RETURN_NORMAL); if (session_set_current(s, new_wl) == 0) @@ -108,7 +120,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) sc.s = s; sc.tc = tc; - sc.name = args_get(args, 'n'); + sc.name = wname; args_to_vector(args, &sc.argc, &sc.argv); sc.environ = environ_create(); @@ -130,10 +142,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) if ((new_wl = spawn_window(&sc, &cause)) == NULL) { cmdq_error(item, "create window failed: %s", cause); free(cause); - if (sc.argv != NULL) - cmd_free_argv(sc.argc, sc.argv); - environ_free(sc.environ); - return (CMD_RETURN_ERROR); + goto fail; } if (!args_has(args, 'd') || new_wl == s->curw) { cmd_find_from_winlink(current, new_wl, 0); @@ -156,5 +165,13 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) if (sc.argv != NULL) cmd_free_argv(sc.argc, sc.argv); environ_free(sc.environ); + free(wname); return (CMD_RETURN_NORMAL); + +fail: + if (sc.argv != NULL) + cmd_free_argv(sc.argc, sc.argv); + environ_free(sc.environ); + free(wname); + return (CMD_RETURN_ERROR); } diff --git a/usr.bin/tmux/cmd-rename-session.c b/usr.bin/tmux/cmd-rename-session.c index d092342cfb7..b83f0a74665 100644 --- a/usr.bin/tmux/cmd-rename-session.c +++ b/usr.bin/tmux/cmd-rename-session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-rename-session.c,v 1.36 2026/04/22 07:10:16 nicm Exp $ */ +/* $OpenBSD: cmd-rename-session.c,v 1.37 2026/06/15 21:41:39 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -52,12 +52,12 @@ cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item) char *newname, *tmp; tmp = format_single_from_target(item, args_string(args, 0)); - newname = clean_name(tmp, "#:."); - if (newname == NULL) { - cmdq_error(item, "invalid session: %s", tmp); + if (!check_name(tmp, SESSION_NAME_FORBID)) { + cmdq_error(item, "invalid session name: %s", tmp); free(tmp); return (CMD_RETURN_ERROR); } + newname = clean_name(tmp, SESSION_NAME_FORBID); free(tmp); if (strcmp(newname, s->name) == 0) { free(newname); diff --git a/usr.bin/tmux/cmd-rename-window.c b/usr.bin/tmux/cmd-rename-window.c index 9805ca95371..61337348224 100644 --- a/usr.bin/tmux/cmd-rename-window.c +++ b/usr.bin/tmux/cmd-rename-window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-rename-window.c,v 1.28 2021/08/21 10:22:39 nicm Exp $ */ +/* $OpenBSD: cmd-rename-window.c,v 1.29 2026/06/15 21:41:39 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -48,15 +48,21 @@ cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item) struct args *args = cmd_get_args(self); struct cmd_find_state *target = cmdq_get_target(item); struct winlink *wl = target->wl; - char *newname; + char *name; - newname = format_single_from_target(item, args_string(args, 0)); - window_set_name(wl->window, newname); + name = format_single_from_target(item, args_string(args, 0)); + if (!check_name(name, WINDOW_NAME_FORBID)) { + cmdq_error(item, "invalid window name: %s", name); + free(name); + return (CMD_RETURN_ERROR); + } + + window_set_name(wl->window, name, WINDOW_NAME_FORBID); options_set_number(wl->window->options, "automatic-rename", 0); + free(name); server_redraw_window_borders(wl->window); server_status_window(wl->window); - free(newname); return (CMD_RETURN_NORMAL); } diff --git a/usr.bin/tmux/cmd-select-pane.c b/usr.bin/tmux/cmd-select-pane.c index 35fadda643c..baeb2dc0588 100644 --- a/usr.bin/tmux/cmd-select-pane.c +++ b/usr.bin/tmux/cmd-select-pane.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-select-pane.c,v 1.73 2026/06/02 08:13:50 nicm Exp $ */ +/* $OpenBSD: cmd-select-pane.c,v 1.74 2026/06/15 21:41:39 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -217,7 +217,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) if (args_has(args, 'T')) { title = format_single_from_target(item, args_get(args, 'T')); - if (screen_set_title(&wp->base, title)) { + if (screen_set_title(&wp->base, title, 0)) { notify_pane("pane-title-changed", wp); server_redraw_window_borders(wp->window); server_status_window(wp->window); diff --git a/usr.bin/tmux/cmd-split-window.c b/usr.bin/tmux/cmd-split-window.c index 06573d0233c..6c6aea2b154 100644 --- a/usr.bin/tmux/cmd-split-window.c +++ b/usr.bin/tmux/cmd-split-window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-split-window.c,v 1.134 2026/06/15 09:21:40 nicm Exp $ */ +/* $OpenBSD: cmd-split-window.c,v 1.135 2026/06/15 21:41:39 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -214,7 +214,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) } if (args_has(args, 'T')) { title = format_single_from_target(item, args_get(args, 'T')); - screen_set_title(&new_wp->base, title); + screen_set_title(&new_wp->base, title, 0); notify_pane("pane-title-changed", new_wp); free(title); } diff --git a/usr.bin/tmux/input.c b/usr.bin/tmux/input.c index f42578e2653..fe9f48a4c40 100644 --- a/usr.bin/tmux/input.c +++ b/usr.bin/tmux/input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: input.c,v 1.260 2026/06/13 20:07:30 nicm Exp $ */ +/* $OpenBSD: input.c,v 1.261 2026/06/15 21:41:39 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -2664,7 +2664,7 @@ input_exit_osc(struct input_ctx *ictx) case 2: if (wp != NULL && options_get_number(wp->options, "allow-set-title") && - screen_set_title(sctx->s, p)) { + screen_set_title(sctx->s, p, 1)) { notify_pane("pane-title-changed", wp); server_redraw_window_borders(wp->window); server_status_window(wp->window); @@ -2674,7 +2674,7 @@ input_exit_osc(struct input_ctx *ictx) input_osc_4(ictx, p); break; case 7: - if (screen_set_path(sctx->s, p) && wp != NULL) { + if (wp != NULL && screen_set_path(sctx->s, p, 1)) { server_redraw_window_borders(wp->window); server_status_window(wp->window); } @@ -2742,7 +2742,7 @@ input_exit_apc(struct input_ctx *ictx) if (wp != NULL && options_get_number(wp->options, "allow-set-title") && - screen_set_title(sctx->s, ictx->input_buf)) { + screen_set_title(sctx->s, ictx->input_buf, 1)) { notify_pane("pane-title-changed", wp); server_redraw_window_borders(wp->window); server_status_window(wp->window); @@ -2785,10 +2785,10 @@ input_exit_rename(struct input_ctx *ictx) if (o != NULL) options_remove_or_default(o, -1, NULL); if (!options_get_number(w->options, "automatic-rename")) - window_set_name(w, ""); + window_set_name(w, "", WINDOW_NAME_FORBID_EXT); } else { options_set_number(w->options, "automatic-rename", 0); - window_set_name(w, ictx->input_buf); + window_set_name(w, ictx->input_buf, WINDOW_NAME_FORBID_EXT); } server_redraw_window_borders(w); server_status_window(w); diff --git a/usr.bin/tmux/names.c b/usr.bin/tmux/names.c index 75f11785271..f61d80527b4 100644 --- a/usr.bin/tmux/names.c +++ b/usr.bin/tmux/names.c @@ -1,4 +1,4 @@ -/* $OpenBSD: names.c,v 1.46 2026/04/22 07:10:16 nicm Exp $ */ +/* $OpenBSD: names.c,v 1.47 2026/06/15 21:41:39 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -95,7 +95,7 @@ check_window_name(struct window *w) name = format_window_name(w); if (strcmp(name, w->name) != 0) { log_debug("@%u new name %s (was %s)", w->id, name, w->name); - window_set_name(w, name); + window_set_name(w, name, WINDOW_NAME_FORBID_EXT); server_redraw_window_borders(w); server_status_window(w); } else @@ -166,7 +166,7 @@ parse_window_name(const char *in) if (*name == '/') name = basename(name); - name = clean_name(name, "#"); + name = clean_name(name, WINDOW_NAME_FORBID); free(copy); if (name == NULL) return (xstrdup("")); diff --git a/usr.bin/tmux/paste.c b/usr.bin/tmux/paste.c index b25d0805c30..efaa3b3aaf6 100644 --- a/usr.bin/tmux/paste.c +++ b/usr.bin/tmux/paste.c @@ -1,4 +1,4 @@ -/* $OpenBSD: paste.c,v 1.50 2026/04/28 08:52:37 nicm Exp $ */ +/* $OpenBSD: paste.c,v 1.51 2026/06/15 21:41:39 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -177,7 +177,6 @@ paste_add(const char *prefix, char *data, size_t size) } pb = xmalloc(sizeof *pb); - pb->name = NULL; do { free(pb->name); @@ -297,7 +296,6 @@ paste_set(char *data, size_t size, const char *name, char **cause) } pb = xmalloc(sizeof *pb); - pb->name = newname; pb->data = data; diff --git a/usr.bin/tmux/popup.c b/usr.bin/tmux/popup.c index cb50e741940..9e1c7b964bb 100644 --- a/usr.bin/tmux/popup.c +++ b/usr.bin/tmux/popup.c @@ -1,4 +1,4 @@ -/* $OpenBSD: popup.c,v 1.69 2026/06/09 21:22:22 nicm Exp $ */ +/* $OpenBSD: popup.c,v 1.70 2026/06/15 21:41:39 nicm Exp $ */ /* * Copyright (c) 2020 Nicholas Marriott @@ -438,7 +438,7 @@ popup_make_pane(struct popup_data *pd, enum layout_type type) pd->job = NULL; } - screen_set_title(&pd->s, new_wp->base.title); + screen_set_title(&pd->s, new_wp->base.title, 0); screen_free(&new_wp->base); memcpy(&new_wp->base, &pd->s, sizeof wp->base); screen_resize(&new_wp->base, new_wp->sx, new_wp->sy, 1); diff --git a/usr.bin/tmux/screen.c b/usr.bin/tmux/screen.c index 9b5e8ce2247..27d3a571f91 100644 --- a/usr.bin/tmux/screen.c +++ b/usr.bin/tmux/screen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: screen.c,v 1.102 2026/06/08 20:41:21 nicm Exp $ */ +/* $OpenBSD: screen.c,v 1.103 2026/06/15 21:41:39 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -232,11 +232,14 @@ screen_set_cursor_colour(struct screen *s, int colour) /* Set screen title. */ int -screen_set_title(struct screen *s, const char *title) +screen_set_title(struct screen *s, const char *title, int untrusted) { char *new_title; - new_title = clean_name(title, "#"); + if (untrusted) + new_title = clean_name(title, "#"); + else + new_title = clean_name(title, ""); if (new_title == NULL) return (0); free(s->title); @@ -246,11 +249,14 @@ screen_set_title(struct screen *s, const char *title) /* Set screen path. */ int -screen_set_path(struct screen *s, const char *path) +screen_set_path(struct screen *s, const char *path, int untrusted) { char *new_path; - new_path = clean_name(path, "#"); + if (untrusted) + new_path = clean_name(path, "#"); + else + new_path = clean_name(path, ""); if (new_path == NULL) return (0); free(s->path); diff --git a/usr.bin/tmux/session.c b/usr.bin/tmux/session.c index 81aac38a5e6..160dcefbb3d 100644 --- a/usr.bin/tmux/session.c +++ b/usr.bin/tmux/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.103 2026/04/22 07:10:16 nicm Exp $ */ +/* $OpenBSD: session.c,v 1.104 2026/06/15 21:41:39 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -118,7 +118,6 @@ session_create(const char *prefix, const char *name, const char *cwd, s = xcalloc(1, sizeof *s); s->references = 1; s->flags = 0; - s->cwd = xstrdup(cwd); TAILQ_INIT(&s->lastw); diff --git a/usr.bin/tmux/spawn.c b/usr.bin/tmux/spawn.c index 0998ff9301d..f69d2a69984 100644 --- a/usr.bin/tmux/spawn.c +++ b/usr.bin/tmux/spawn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: spawn.c,v 1.39 2026/06/02 08:13:50 nicm Exp $ */ +/* $OpenBSD: spawn.c,v 1.40 2026/06/15 21:41:39 nicm Exp $ */ /* * Copyright (c) 2019 Nicholas Marriott @@ -76,15 +76,12 @@ spawn_log(const char *from, struct spawn_context *sc) struct winlink * spawn_window(struct spawn_context *sc, char **cause) { - struct cmdq_item *item = sc->item; - struct client *c = cmdq_get_client(item); struct session *s = sc->s; struct window *w; struct window_pane *wp; struct winlink *wl; int idx = sc->idx; u_int sx, sy, xpixel, ypixel; - char *name; spawn_log(__func__, sc); @@ -182,15 +179,12 @@ spawn_window(struct spawn_context *sc, char **cause) /* Set the name of the new window. */ if (~sc->flags & SPAWN_RESPAWN) { free(w->name); - if (sc->name != NULL) { - name = format_single(item, sc->name, c, s, NULL, NULL); - w->name = clean_name(name, "#"); - free(name); - if (w->name == NULL) - w->name = xstrdup(""); - options_set_number(w->options, "automatic-rename", 0); - } else + if (sc->name == NULL || *sc->name == '\0') w->name = default_window_name(w); + else { + w->name = xstrdup(sc->name); + options_set_number(w->options, "automatic-rename", 0); + } } /* Switch to the new window if required. */ diff --git a/usr.bin/tmux/tmux.c b/usr.bin/tmux/tmux.c index 9c28afc507f..7d9b2842157 100644 --- a/usr.bin/tmux/tmux.c +++ b/usr.bin/tmux/tmux.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.c,v 1.217 2026/04/22 07:10:16 nicm Exp $ */ +/* $OpenBSD: tmux.c,v 1.218 2026/06/15 21:41:39 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -303,6 +303,25 @@ clean_name(const char *name, const char* forbid) return (new_name); } +/* + * Check a name given by a command: reject it if it is empty, not valid UTF-8, + * or contains a forbidden character. Other characters that clean_name would + * change (for example with utf8_stravis) are allowed and fixed silently. + */ +int +check_name(const char *name, const char *forbid) +{ + const char *cp; + + if (*name == '\0' || !utf8_isvalid(name)) + return (0); + for (cp = name; *cp != '\0'; cp++) { + if (strchr(forbid, *cp) != NULL) + return (0); + } + return (1); +} + const char * sig2name(int signo) { diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h index 5d4236de107..7823b61d281 100644 --- a/usr.bin/tmux/tmux.h +++ b/usr.bin/tmux/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.1353 2026/06/15 17:34:25 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.1354 2026/06/15 21:41:39 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -87,6 +87,12 @@ struct winlink; #define TMUX_TERM "screen" #endif +/* Forbidden characters in names. */ +#define WINDOW_NAME_FORBID ":." +#define WINDOW_NAME_FORBID_EXT ":.#" +#define SESSION_NAME_FORBID ":." +#define SESSION_NAME_FORBID_EXT ":.#" + /* Minimum and maximum layout cell size, NOT including border lines. */ #define PANE_MINIMUM 1 #define PANE_MAXIMUM 10000 @@ -2382,6 +2388,7 @@ void setblocking(int, int); char *shell_argv0(const char *, int); uint64_t get_timer(void); char *clean_name(const char *, const char *); +int check_name(const char *, const char *); const char *sig2name(int); const char *find_cwd(void); const char *find_home(void); @@ -3345,8 +3352,8 @@ void screen_reset_hyperlinks(struct screen *); void screen_set_default_cursor(struct screen *, struct options *); void screen_set_cursor_style(u_int, enum screen_cursor_style *, int *); void screen_set_cursor_colour(struct screen *, int); -int screen_set_title(struct screen *, const char *); -int screen_set_path(struct screen *, const char *); +int screen_set_title(struct screen *, const char *, int); +int screen_set_path(struct screen *, const char *, int); void screen_push_title(struct screen *); void screen_pop_title(struct screen *); void screen_set_progress_bar(struct screen *, enum progress_bar_state, int); @@ -3453,7 +3460,7 @@ void window_pane_stack_push(struct window_panes *, struct window_pane *); void window_pane_stack_remove(struct window_panes *, struct window_pane *); -void window_set_name(struct window *, const char *); +void window_set_name(struct window *, const char *, const char *); void window_add_ref(struct window *, const char *); void window_remove_ref(struct window *, const char *); void winlink_clear_flags(struct winlink *); diff --git a/usr.bin/tmux/window.c b/usr.bin/tmux/window.c index bddcb7ab471..0759b95ffe7 100644 --- a/usr.bin/tmux/window.c +++ b/usr.bin/tmux/window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: window.c,v 1.339 2026/06/15 17:34:25 nicm Exp $ */ +/* $OpenBSD: window.c,v 1.340 2026/06/15 21:41:39 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -411,11 +411,11 @@ window_remove_ref(struct window *w, const char *from) } void -window_set_name(struct window *w, const char *new_name) +window_set_name(struct window *w, const char *new_name, const char *forbid) { char *name; - name = clean_name(new_name, "#"); + name = clean_name(new_name, forbid); if (name != NULL) { free(w->name); w->name = name; @@ -1089,7 +1089,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) style_ranges_init(&wp->border_status_line.ranges); if (gethostname(host, sizeof host) == 0) - screen_set_title(&wp->base, host); + screen_set_title(&wp->base, host, 0); return (wp); }