[libvirt] [PATCH] xml: shell-escape domain name in comment

Add virBufferEscapeShellXMLComment function that both quotes a string so shell deosn't interpert any special characters in it and makes sure that there's no "--" in it, to avoid clashes with XML comments. virXMLEmitWarning is changed to use virBuffer and use the above function on the domain name. --- src/libvirt_private.syms | 1 + src/util/buf.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/buf.h | 1 + src/util/xml.c | 52 +++++++++++++++--------------------- 4 files changed, 90 insertions(+), 30 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 699c9a3..a49d5dc 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -37,6 +37,7 @@ virBufferError; virBufferEscape; virBufferEscapeSexpr; virBufferEscapeShell; +virBufferEscapeShellXML; virBufferEscapeString; virBufferFreeAndReset; virBufferGetIndent; diff --git a/src/util/buf.c b/src/util/buf.c index 030dc97..839b663 100644 --- a/src/util/buf.c +++ b/src/util/buf.c @@ -623,6 +623,72 @@ virBufferEscapeShell(virBufferPtr buf, const char *str) } /** + * virBufferEscapeShellXMLComment: + * @buf: the buffer to append to + * @str: an unquoted string + * + * Quotes a string so that the shell (/bin/sh) will interpret the + * quoted string to mean str. Auto indentation may be applied. + * It also escapes any "--" so that the string can be used in XML comments. + */ +void virBufferEscapeShellXMLComment(virBufferPtr buf, const char *str) +{ + int len; + char *escaped, *out; + const char *cur; + char prev = '\0'; + + if ((buf == NULL) || (str == NULL)) + return; + + if (buf->error) + return; + + /* Only quote if str includes shell metacharacters. */ + if (*str && !strpbrk(str, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~") && + !strstr(str,"--")) { + virBufferAdd(buf, str, -1); + return; + } + + if (*str) { + len = strlen(str); + if (xalloc_oversized(4, len) || + VIR_ALLOC_N(escaped, 4 * len + 3) < 0) { + virBufferSetError(buf, errno); + return; + } + } else { + virBufferAddLit(buf, "''"); + return; + } + + cur = str; + out = escaped; + + *out++ = '\''; + while (*cur != 0) { + if (*cur == '\'') { + *out++ = '\''; + /* Replace literal ' with a close ', a \', and a open ' */ + *out++ = '\\'; + *out++ = '\''; + } else if (*cur == '-' && prev == '-') { + /* Replace -- with -''- */ + *out++ = '\''; + *out++ = '\''; + } + prev = *cur; + *out++ = *cur++; + } + *out++ = '\''; + *out = 0; + + virBufferAdd(buf, escaped, -1); + VIR_FREE(escaped); +} + +/** * virBufferStrcat: * @buf: the buffer to append to * @...: the variable list of strings, the last argument must be NULL diff --git a/src/util/buf.h b/src/util/buf.h index c3a498d..25e31fd 100644 --- a/src/util/buf.h +++ b/src/util/buf.h @@ -69,6 +69,7 @@ void virBufferEscapeString(virBufferPtr buf, const char *format, void virBufferEscapeSexpr(virBufferPtr buf, const char *format, const char *str); void virBufferEscapeShell(virBufferPtr buf, const char *str); +void virBufferEscapeShellXMLComment(virBufferPtr buf, const char *str); void virBufferURIEncodeString(virBufferPtr buf, const char *str); # define virBufferAddLit(buf_, literal_string_) \ diff --git a/src/util/xml.c b/src/util/xml.c index f3dc256..685f903 100644 --- a/src/util/xml.c +++ b/src/util/xml.c @@ -780,49 +780,41 @@ error: goto cleanup; } - static int virXMLEmitWarning(int fd, const char *name, const char *cmd) { + virBuffer buf = VIR_BUFFER_INITIALIZER; + char *str = NULL; size_t len; - const char *prologue = "<!--\n\ -WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE \n\ -OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:\n\ - virsh "; - const char *epilogue = "\n\ -or other application using the libvirt API.\n\ --->\n\n"; if (fd < 0 || !name || !cmd) { errno = EINVAL; return -1; } - len = strlen(prologue); - if (safewrite(fd, prologue, len) != len) - return -1; - - len = strlen(cmd); - if (safewrite(fd, cmd, len) != len) - return -1; - - /* Omit the domain name if it contains a double hyphen - * because they aren't allowed in XML comments */ - if (!strstr(name, "--")) { - if (safewrite(fd, " ", 1) != 1) - return -1; - - len = strlen(name); - if (safewrite(fd, name, len) != len) - return -1; + virBufferAddLit(&buf, "<!--\n" +"WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE\n" +"OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:\n" +" virsh "); + virBufferAdd(&buf, cmd, -1); + virBufferAddLit(&buf," "); + virBufferEscapeShellXMLComment(&buf, name); + virBufferAddLit(&buf, "\n" +"or other application using the libvirt API.\n" +"-->\n\n"); + + str = virBufferContentAndReset(&buf); + if (str) { + len = strlen(str); + if (safewrite(fd, str, len) == len) { + VIR_FREE(str); + return 0; + } } - len = strlen(epilogue); - if (safewrite(fd, epilogue, len) != len) - return -1; - - return 0; + VIR_FREE(str); + return -1; } -- 1.7.8.6

On Wed, Oct 24, 2012 at 14:03:12 +0200, Ján Tomko wrote:
Add virBufferEscapeShellXMLComment function that both quotes a string so shell deosn't interpert any special characters in it and makes sure that there's no "--" in it, to avoid clashes with XML comments.
virXMLEmitWarning is changed to use virBuffer and use the above function on the domain name.
I should have spoken earlier but why don't we just emit UUID there? It's guaranteed that it is safe for both XML and shell and thus can be just copy&pasted even into interactive virsh. Jirka

On 10/24/12 14:59, Jiri Denemark wrote:
On Wed, Oct 24, 2012 at 14:03:12 +0200, Ján Tomko wrote: I should have spoken earlier but why don't we just emit UUID there? It's guaranteed that it is safe for both XML and shell and thus can be just copy&pasted even into interactive virsh.
UUIDs are uglier than plain domain names, but they might be prettier than some escaped ones, and would work even with tcsh (which doesn't seem to understand single quotes). How about emiting UUID for domains containing special shell characters or "]]>" and domain names for the rest (including "--")?

On 10/24/2012 06:03 AM, Ján Tomko wrote:
Add virBufferEscapeShellXMLComment function that both quotes a string so shell deosn't interpert any special characters in it and makes sure that there's no "--" in it, to avoid clashes with XML comments.
virXMLEmitWarning is changed to use virBuffer and use the above function on the domain name. --- src/libvirt_private.syms | 1 + src/util/buf.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/buf.h | 1 + src/util/xml.c | 52 +++++++++++++++--------------------- 4 files changed, 90 insertions(+), 30 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 699c9a3..a49d5dc 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -37,6 +37,7 @@ virBufferError; virBufferEscape; virBufferEscapeSexpr; virBufferEscapeShell; +virBufferEscapeShellXML;
This name doesn't match.
+ *out++ = '\''; + while (*cur != 0) { + if (*cur == '\'') { + *out++ = '\''; + /* Replace literal ' with a close ', a \', and a open ' */ + *out++ = '\\'; + *out++ = '\''; + } else if (*cur == '-' && prev == '-') {
Is two spaces after && intentional?
+ virBufferAddLit(&buf, "<!--\n" +"WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE\n" +"OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:\n" +" virsh "); + virBufferAdd(&buf, cmd, -1); + virBufferAddLit(&buf," ");
virBufferAddChar() is more efficient for a single byte. The idea of using UUID instead of name for problematic names sounds appealing to me. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (3)
-
Eric Blake
-
Jiri Denemark
-
Ján Tomko