File openssh-bsc1148566-scp-handle-quotes-while-checking-filenames-from-serv.patch of Package openssh.29884
@@ -, +, @@
---
scp.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 124 insertions(+), 19 deletions(-)
--- a/scp.c
+++ a/scp.c
@@ -645,33 +645,62 @@ append(char *cp, char ***ap, size_t *np)
}
/*
- * Finds the start and end of the first brace pair in the pattern.
+ * Finds the start and end of the first meta (braces or quotes) pair in the pattern.
* returns 0 on success or -1 for invalid patterns.
*/
static int
-find_brace(const char *pattern, int *startp, int *endp)
+find_meta_pair(const char *pattern, int *startp, int *endp)
{
int i;
int in_bracket, brace_level;
+ int in_single_qoutes, in_double_qoutes;
*startp = *endp = -1;
in_bracket = brace_level = 0;
+ in_single_qoutes = in_double_qoutes = 0;
+
for (i = 0; i < INT_MAX && *endp < 0 && pattern[i] != '\0'; i++) {
switch (pattern[i]) {
case '\\':
/* skip next character */
- if (pattern[i + 1] != '\0')
+ if (!in_single_qoutes && pattern[i + 1] != '\0')
i++;
break;
+ case '\'':
+ if (in_bracket || in_double_qoutes)
+ break;
+ if (in_single_qoutes) {
+ *endp = i;
+ } else {
+ *startp = i;
+ }
+ in_single_qoutes = !in_single_qoutes;
+ break;
+ case '"':
+ if (in_bracket || in_single_qoutes)
+ break;
+ if (in_double_qoutes) {
+ *endp = i;
+ } else {
+ *startp = i;
+ }
+ in_double_qoutes = !in_double_qoutes;
+ break;
case '[':
+ if (in_single_qoutes || in_double_qoutes)
+ break;
in_bracket = 1;
break;
case ']':
+ if (in_single_qoutes || in_double_qoutes)
+ break;
in_bracket = 0;
break;
case '{':
if (in_bracket)
break;
+ if (in_single_qoutes || in_double_qoutes)
+ break;
if (pattern[i + 1] == '}') {
/* Protect a single {}, for find(1), like csh */
i++; /* skip */
@@ -684,6 +713,8 @@ find_brace(const char *pattern, int *startp, int *endp)
case '}':
if (in_bracket)
break;
+ if (in_single_qoutes || in_double_qoutes)
+ break;
if (*startp < 0) {
/* Unbalanced brace */
return -1;
@@ -696,6 +727,9 @@ find_brace(const char *pattern, int *startp, int *endp)
/* unbalanced brackets/braces */
if (*endp < 0 && (*startp >= 0 || in_bracket))
return -1;
+ /* unbalanced qoutes */
+ if (in_single_qoutes || in_double_qoutes)
+ return -1;
return 0;
}
@@ -738,6 +772,56 @@ emit_expansion(const char *pattern, int brace_start, int brace_end,
return 0;
}
+
+/* Expand string with qoutes and put the result to *patternsp array.
+ */
+static int
+emit_quote_expansion(const char *pattern, int quote_start, int quote_end,
+ int single_quotes, char ***patternsp, size_t *npatternsp)
+{
+ char *cp;
+ int o = 0, tail_len = strlen(pattern + quote_end + 1);
+ int i;
+
+ if ((cp = malloc(strlen(pattern) + 1)) == NULL)
+ return -1;
+
+ /* Pattern before initial quote */
+ if (quote_start > 0) {
+ memcpy(cp, pattern, quote_start);
+ o = quote_start;
+ }
+
+ if (single_quotes) {
+ /* Single quoted selection */
+ if (quote_end - quote_start > 0) {
+ memcpy(cp + o, pattern + quote_start + 1,
+ quote_end - quote_start - 1);
+ o += quote_end - quote_start - 1;
+ }
+ } else {
+ /* Double quoted selection has to handle '\' */
+ for (i = quote_start + 1; i < quote_end; i++) {
+ if ((pattern[i] == '\\') && (i < quote_end - 1)) {
+ i++;
+ }
+ cp[o++] = pattern[i];
+ }
+ }
+
+ /* Remainder of pattern after closing brace */
+ if (tail_len > 0) {
+ memcpy(cp + o, pattern + quote_end + 1, tail_len);
+ o += tail_len;
+ }
+ cp[o] = '\0';
+ if (append(cp, patternsp, npatternsp) != 0) {
+ free(cp);
+ return -1;
+ }
+ return 0;
+}
+
/*
* Expand the first encountered brace in pattern, appending the expanded
* patterns it yielded to the *patternsp array.
@@ -748,21 +832,13 @@ emit_expansion(const char *pattern, int brace_start, int brace_end,
* pattern was invalid via *invalid.
*/
static int
-brace_expand_one(const char *pattern, char ***patternsp, size_t *npatternsp,
- int *expanded, int *invalid)
+brace_expand_one(const char *pattern, int brace_start, int brace_end,
+ char ***patternsp, size_t *npatternsp, int *expanded, int *invalid)
{
int i;
- int in_bracket, brace_start, brace_end, brace_level;
+ int in_bracket, brace_level;
int sel_start, sel_end;
- *invalid = *expanded = 0;
-
- if (find_brace(pattern, &brace_start, &brace_end) != 0) {
- *invalid = 1;
- return 0;
- } else if (brace_start == -1)
- return 0;
-
in_bracket = brace_level = 0;
for (i = sel_start = brace_start + 1; i < brace_end; i++) {
switch (pattern[i]) {
@@ -811,9 +887,38 @@ brace_expand_one(const char *pattern, char ***patternsp, size_t *npatternsp,
return 0;
}
-/* Expand braces from pattern. Returns 0 on success, -1 on failure */
+
+static int pattern_meta_expand_one(const char *pattern, char ***patternsp, size_t *npatternsp,
+ int *expanded, int *invalid)
+{
+ int meta_start, meta_end;
+
+ *invalid = *expanded = 0;
+
+ if (find_meta_pair(pattern, &meta_start, &meta_end) != 0) {
+ *invalid = 1;
+ return 0;
+ } else if (meta_start == -1)
+ return 0;
+
+ if (pattern[meta_start] == '\'' || pattern[meta_start] == '"')
+ {
+ if (emit_quote_expansion(pattern, meta_start, meta_end, pattern[meta_start] == '\'',
+ patternsp, npatternsp) != 0) {
+ return -1;
+ }
+ *invalid = 0;
+ *expanded = 1;
+ return 0;
+ }
+
+ return brace_expand_one(pattern, meta_start, meta_end, patternsp, npatternsp,
+ expanded, invalid);
+}
+
+/* Expand braces and quotes from pattern. Returns 0 on success, -1 on failure */
static int
-brace_expand(const char *pattern, char ***patternsp, size_t *npatternsp)
+pattern_meta_expand(const char *pattern, char ***patternsp, size_t *npatternsp)
{
char *cp, *cp2, **active = NULL, **done = NULL;
size_t i, nactive = 0, ndone = 0;
@@ -832,13 +937,13 @@ brace_expand(const char *pattern, char ***patternsp, size_t *npatternsp)
while (nactive > 0) {
cp = active[nactive - 1];
nactive--;
- if (brace_expand_one(cp, &active, &nactive,
+ if (pattern_meta_expand_one(cp, &active, &nactive,
&expanded, &invalid) == -1) {
free(cp);
goto fail;
}
if (invalid)
- fatal("%s: invalid brace pattern \"%s\"", __func__, cp);
+ fatal("%s: invalid filename pattern \"%s\"", __func__, cp);
if (expanded) {
/*
* Current entry expanded to new entries on the
@@ -1271,7 +1376,7 @@ sink(int argc, char **argv, const char *src)
* Prepare to try to restrict incoming filenames to match
* the requested destination file glob.
*/
- if (brace_expand(src, &patterns, &npatterns) != 0)
+ if (pattern_meta_expand(src, &patterns, &npatterns) != 0)
fatal("%s: could not expand pattern", __func__);
}
for (first = 1;; first = 0) {
--