mirror of
https://github.com/tmux/tmux.git
synced 2026-10-06 17:49:52 +00:00
Change %% to escape single quotes (%1 remains with no quoting and %%
with double quotes) to avoid a single quote being able to terminate quoted sections of commands. Fixes unexpected behaviour with session names containing single quotes reported by Aliz Hammond.
This commit is contained in:
52
cmd.c
52
cmd.c
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: cmd.c,v 1.188 2026/07/15 13:02:33 nicm Exp $ */
|
/* $OpenBSD: cmd.c,v 1.189 2026/07/17 08:29:34 nicm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -841,14 +841,19 @@ cmd_mouse_pane(struct mouse_event *m, struct session **sp,
|
|||||||
return (wp);
|
return (wp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Replace the first %% or %idx in template by s. */
|
/*
|
||||||
|
* Replace the first %% or any %idx in template by s. %% is intended for use in
|
||||||
|
* single quotes, so ' is escaped. %%% and %idx% are for double quotes, so a
|
||||||
|
* list of special characters is escaped. %idx is left unescaped.
|
||||||
|
*/
|
||||||
char *
|
char *
|
||||||
cmd_template_replace(const char *template, const char *s, int idx)
|
cmd_template_replace(const char *template, const char *s, int idx)
|
||||||
{
|
{
|
||||||
char ch, *buf;
|
char ch, *buf;
|
||||||
const char *ptr, *cp, quote[] = "\"\\$;~";
|
const char *ptr, *cp, dquote[] = "\"\\$;~";
|
||||||
int replaced, quoted;
|
int replaced;
|
||||||
size_t len, slen;
|
size_t len, slen;
|
||||||
|
enum { NQ, SQ, DQ } quote;
|
||||||
|
|
||||||
if (strchr(template, '%') == NULL)
|
if (strchr(template, '%') == NULL)
|
||||||
return (xstrdup(template));
|
return (xstrdup(template));
|
||||||
@@ -862,23 +867,39 @@ cmd_template_replace(const char *template, const char *s, int idx)
|
|||||||
while (*ptr != '\0') {
|
while (*ptr != '\0') {
|
||||||
switch (ch = *ptr++) {
|
switch (ch = *ptr++) {
|
||||||
case '%':
|
case '%':
|
||||||
if (*ptr < '1' || *ptr > '9' || *ptr - '0' != idx) {
|
if (*ptr >= '1' && *ptr <= '9' && *ptr - '0' == idx) {
|
||||||
|
ptr++;
|
||||||
|
quote = NQ;
|
||||||
|
if (*ptr == '%') {
|
||||||
|
quote = DQ;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (*ptr != '%' || replaced)
|
if (*ptr != '%' || replaced)
|
||||||
break;
|
break;
|
||||||
replaced = 1;
|
replaced = 1;
|
||||||
}
|
|
||||||
ptr++;
|
|
||||||
|
|
||||||
quoted = (*ptr == '%');
|
|
||||||
if (quoted)
|
|
||||||
ptr++;
|
ptr++;
|
||||||
|
quote = SQ;
|
||||||
|
if (*ptr == '%') {
|
||||||
|
quote = DQ;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
slen = strlen(s);
|
slen = strlen(s);
|
||||||
if (slen >= SIZE_MAX / 3 || len > SIZE_MAX - (slen * 3) - 1)
|
if (slen >= SIZE_MAX / 4 ||
|
||||||
|
len > SIZE_MAX - (slen * 4) - 1)
|
||||||
fatalx("argument too long");
|
fatalx("argument too long");
|
||||||
buf = xrealloc(buf, len + (slen * 3) + 1);
|
buf = xrealloc(buf, len + (slen * 4) + 1);
|
||||||
for (cp = s; *cp != '\0'; cp++) {
|
for (cp = s; *cp != '\0'; cp++) {
|
||||||
if (quoted && strchr(quote, *cp) != NULL)
|
if (quote == SQ && *cp == '\'') {
|
||||||
|
buf[len++] = '\'';
|
||||||
|
buf[len++] = '\\';
|
||||||
|
buf[len++] = '\'';
|
||||||
|
buf[len++] = '\'';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (quote == DQ && strchr(dquote, *cp) != NULL)
|
||||||
buf[len++] = '\\';
|
buf[len++] = '\\';
|
||||||
buf[len++] = *cp;
|
buf[len++] = *cp;
|
||||||
}
|
}
|
||||||
@@ -892,5 +913,6 @@ cmd_template_replace(const char *template, const char *s, int idx)
|
|||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_debug("%s: %s -> %s", __func__, template, buf);
|
||||||
return (buf);
|
return (buf);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user