aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--agent/command.c2
-rw-r--r--common/percent.c77
-rw-r--r--common/t-percent.c168
-rw-r--r--common/util.h3
4 files changed, 224 insertions, 26 deletions
diff --git a/agent/command.c b/agent/command.c
index 7fbf1de1c..c395b1e59 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -2751,7 +2751,7 @@ cmd_put_secret (assuan_context_t ctx, char *line)
* into a string. Instead of resorting to base64 encoding we use a
* special percent escaping which only quoted the Nul and the
* percent character. */
- string = percent_data_escape (value? value : valstr, valuelen);
+ string = percent_data_escape (0, NULL, value? value : valstr, valuelen);
if (!string)
{
err = gpg_error_from_syserror ();
diff --git a/common/percent.c b/common/percent.c
index 7b817684d..ecc6a1959 100644
--- a/common/percent.c
+++ b/common/percent.c
@@ -37,16 +37,16 @@
/* Create a newly alloced string from STRING with all spaces and
- control characters converted to plus signs or %xx sequences. The
- function returns the new string or NULL in case of a malloc
- failure.
-
- Note that we also escape the quote character to work around a bug
- in the mingw32 runtime which does not correctly handle command line
- quoting. We correctly double the quote mark when calling a program
- (i.e. gpg-protect-tool), but the pre-main code does not notice the
- double quote as an escaped quote. We do this also on POSIX systems
- for consistency. */
+ * control characters converted to plus signs or %xx sequences. The
+ * function returns the new string or NULL in case of a malloc
+ * failure.
+ *
+ * Note that this fucntion also escapes the quote character to work
+ * around a bug in the mingw32 runtime which does not correctly handle
+ * command line quoting. We correctly double the quote mark when
+ * calling a program (i.e. gpg-protect-tool), but the pre-main code
+ * does not notice the double quote as an escaped quote. We do this
+ * also on POSIX systems for consistency. */
char *
percent_plus_escape (const char *string)
{
@@ -87,19 +87,36 @@ percent_plus_escape (const char *string)
}
-/* Create a newly alloced string from (DATA,DATALEN) with embedded
- * Nuls quoted as %00. The standard percent unescaping can be
- * used to reverse this encoding. */
+/* Create a newly malloced string from (DATA,DATALEN) with embedded
+ * nuls quoted as %00. The standard percent unescaping can be used to
+ * reverse this encoding. With PLUS_ESCAPE set plus-escaping (spaces
+ * are replaced by a '+') and escaping of characters with values less
+ * than 0x20 is used. If PREFIX is not NULL it will be prepended to
+ * the output in standard escape format; that is PLUS_ESCAPING is
+ * ignored for PREFIX. */
char *
-percent_data_escape (const void *data, size_t datalen)
+percent_data_escape (int plus_escape, const char *prefix,
+ const void *data, size_t datalen)
{
char *buffer, *p;
- const char *s;
- size_t n, length;
+ const unsigned char *s;
+ size_t n;
+ size_t length = 1;
+
+ if (prefix)
+ {
+ for (s = prefix; *s; s++)
+ {
+ if (*s == '%' || *s < 0x20)
+ length += 3;
+ else
+ length++;
+ }
+ }
- for (length=1, s=data, n=datalen; n; s++, n--)
+ for (s=data, n=datalen; n; s++, n--)
{
- if (!*s || *s == '%')
+ if (!*s || *s == '%' || (plus_escape && (*s < ' ' || *s == '+')))
length += 3;
else
length++;
@@ -109,6 +126,20 @@ percent_data_escape (const void *data, size_t datalen)
if (!buffer)
return NULL;
+ if (prefix)
+ {
+ for (s = prefix; *s; s++)
+ {
+ if (*s == '%' || *s < 0x20)
+ {
+ snprintf (p, 4, "%%%02X", *s);
+ p += 3;
+ }
+ else
+ *p++ = *s;
+ }
+ }
+
for (s=data, n=datalen; n; s++, n--)
{
if (!*s)
@@ -121,13 +152,21 @@ percent_data_escape (const void *data, size_t datalen)
memcpy (p, "%25", 3);
p += 3;
}
+ else if (plus_escape && *s == ' ')
+ {
+ *p++ = '+';
+ }
+ else if (plus_escape && (*s < ' ' || *s == '+'))
+ {
+ snprintf (p, 4, "%%%02X", *s);
+ p += 3;
+ }
else
*p++ = *s;
}
*p = 0;
return buffer;
-
}
diff --git a/common/t-percent.c b/common/t-percent.c
index 94ece9249..774fa80ee 100644
--- a/common/t-percent.c
+++ b/common/t-percent.c
@@ -103,25 +103,182 @@ static void
test_percent_data_escape (void)
{
static struct {
+ const char *prefix;
const char *data;
size_t datalen;
const char *expect;
} tbl[] = {
{
+ NULL,
"", 0,
""
}, {
+ NULL,
"a", 1,
"a",
}, {
+ NULL,
"%22", 3,
"%2522"
}, {
+ NULL,
"%%", 3,
"%25%25%00"
}, {
+ NULL,
"\n \0BC\t", 6,
"\n %00BC\t"
+ }, {
+ "",
+ "", 0,
+ ""
+ }, {
+ "",
+ "a", 1,
+ "a",
+ }, {
+ "",
+ "%22", 3,
+ "%2522"
+ }, {
+ "",
+ "%%", 3,
+ "%25%25%00"
+ }, {
+ "",
+ "\n \0BC\t", 6,
+ "\n %00BC\t"
+ }, {
+ "a",
+ "", 0,
+ "a"
+ }, {
+ "a",
+ "a", 1,
+ "aa",
+ }, {
+ "a",
+ "%22", 3,
+ "a%2522"
+ }, {
+ "a",
+ "%%", 3,
+ "a%25%25%00"
+ }, {
+ "a",
+ "\n \0BC\t", 6,
+ "a\n %00BC\t"
+ }, {
+ " ",
+ "%%", 3,
+ " %25%25%00"
+ }, {
+ "+",
+ "%%", 3,
+ "+%25%25%00"
+ }, {
+ "%",
+ "%%", 3,
+ "%25%25%25%00"
+ }, {
+ "a b",
+ "%%", 3,
+ "a b%25%25%00"
+ }, {
+ "a%2Bb",
+ "%%", 3,
+ "a%252Bb%25%25%00"
+ }, {
+ "\n",
+ "%%", 3,
+ "%0A%25%25%00"
+ }, {
+ NULL,
+ NULL, 0,
+ NULL }
+ };
+ char *buf;
+ int i;
+ size_t len, prefixlen;
+
+ for (i=0; tbl[i].data; i++)
+ {
+ buf = percent_data_escape (0, tbl[i].prefix, tbl[i].data, tbl[i].datalen);
+ if (!buf)
+ {
+ fprintf (stderr, "out of core: %s\n", strerror (errno));
+ exit (2);
+ }
+ if (strcmp (buf, tbl[i].expect))
+ {
+ fail (i);
+ }
+ len = percent_plus_unescape_inplace (buf, 0);
+ prefixlen = tbl[i].prefix? strlen (tbl[i].prefix) : 0;
+ if (len != tbl[i].datalen + prefixlen)
+ fail (i);
+ else if (tbl[i].prefix && memcmp (buf, tbl[i].prefix, prefixlen)
+ && !(prefixlen == 1 && *tbl[i].prefix == '+' && *buf == ' '))
+ {
+ /* Note extra condition above handles the one test case
+ * which reverts a plus to a space due to the use of the
+ * plus-unescape fucntion also for the prefix part. */
+ fail (i);
+ }
+ else if (memcmp (buf+prefixlen, tbl[i].data, tbl[i].datalen))
+ {
+ fail (i);
+ }
+ xfree (buf);
+ }
+}
+
+
+
+static void
+test_percent_data_escape_plus (void)
+{
+ static struct {
+ const char *data;
+ size_t datalen;
+ const char *expect;
+ } tbl[] = {
+ {
+ "", 0,
+ ""
+ }, {
+ "a", 1,
+ "a",
+ }, {
+ "%22", 3,
+ "%2522"
+ }, {
+ "%%", 3,
+ "%25%25%00"
+ }, {
+ "\n \0BC\t", 6,
+ "%0A+%00BC%09"
+ }, {
+ " ", 1,
+ "+"
+ }, {
+ " ", 2,
+ "++"
+ }, {
+ "+ +", 3,
+ "%2B+%2B"
+ }, {
+ "\" \"", 3, /* Note: This function does not escape quotes. */
+ "\"+\""
+ }, {
+ "%22", 3,
+ "%2522"
+ }, {
+ "%% ", 3,
+ "%25%25+"
+ }, {
+ "\n ABC\t", 6,
+ "%0A+ABC%09"
}, { NULL, 0, NULL }
};
char *buf;
@@ -130,14 +287,16 @@ test_percent_data_escape (void)
for (i=0; tbl[i].data; i++)
{
- buf = percent_data_escape (tbl[i].data, tbl[i].datalen);
+ buf = percent_data_escape (1, NULL, tbl[i].data, tbl[i].datalen);
if (!buf)
{
fprintf (stderr, "out of core: %s\n", strerror (errno));
exit (2);
}
if (strcmp (buf, tbl[i].expect))
- fail (i);
+ {
+ fail (i);
+ }
len = percent_plus_unescape_inplace (buf, 0);
if (len != tbl[i].datalen)
fail (i);
@@ -148,16 +307,15 @@ test_percent_data_escape (void)
}
-
int
main (int argc, char **argv)
{
(void)argc;
(void)argv;
- /* FIXME: We escape_unescape is not tested - only
- percent_plus_unescape. */
+ /* FIXME: escape_unescape is not tested - only percent_plus_unescape. */
test_percent_plus_escape ();
test_percent_data_escape ();
+ test_percent_data_escape_plus ();
return 0;
}
diff --git a/common/util.h b/common/util.h
index 682415d92..d3a846f00 100644
--- a/common/util.h
+++ b/common/util.h
@@ -201,7 +201,8 @@ char *hex2str_alloc (const char *hexstring, size_t *r_count);
/*-- percent.c --*/
char *percent_plus_escape (const char *string);
-char *percent_data_escape (const void *data, size_t datalen);
+char *percent_data_escape (int plus, const char *prefix,
+ const void *data, size_t datalen);
char *percent_plus_unescape (const char *string, int nulrepl);
char *percent_unescape (const char *string, int nulrepl);