aboutsummaryrefslogtreecommitdiff
path: root/dev-libs/libstrophe/files/libstrophe-xml-escape.patch
blob: 4b97099021898eda395ae8a3253b8a3c59536946 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
commit c0b1e5b7fe51c6b7018116d96ea98b7912374385
Author: Alexandre Erwin Ittner <alexandre@ittner.com.br>
Date:   Sun Sep 23 17:18:53 2012 -0300

    Fix escaping of XML text and attributes
    
    There was a bug in xmpp_send which caused XML special characters to be
    sent to the server verbatim, implying in invalid stanzas and making the
    server drop the connection. This commit fixed the bug escaping such
    characters with the usual rules.
    
    Bugs: The code now do several (de)allocation operations in every send,
    this may have a negative effect on performance when used with slow
    memory managers.
    
    License: This code is distributed under the same license used by strophe
    (i.e., GPLv3 or MIT).

diff --git a/src/stanza.c b/src/stanza.c
index 6bf11b8..4ecc558 100644
--- a/src/stanza.c
+++ b/src/stanza.c
@@ -206,6 +206,64 @@ int xmpp_stanza_is_tag(xmpp_stanza_t * const stanza)
     return (stanza && stanza->type == XMPP_STANZA_TAG);
 }
 
+/* Escape a string with for use in a XML text node or attribute. Assumes that
+ * the input string is encoded in UTF-8. On sucess, returns a pointer to a
+ * buffer with the resulting data which must be xmpp_free()'d by the caller.
+ * On failure, returns NULL.
+ */
+
+static char *_escape_xml(xmpp_ctx_t * const ctx, char *text)
+{
+    size_t len = 0;
+    char *src;
+    char *dst;
+    char *buf;
+    for (src = text; *src != '\0'; src++) {
+        switch (*src) {
+            case '<':   /* "&lt;" */
+            case '>':   /* "&gt;" */
+                len += 4;
+                break;
+            case '&':   /* "&amp;" */
+                len += 5;
+                break;
+            case '"':
+                len += 6; /*"&quot;" */
+                break;
+            default:
+                len++;
+        }
+    }
+    if ((buf = xmpp_alloc(ctx, (len+1) * sizeof(char))) == NULL)
+        return NULL;    /* Error */
+    dst = buf;
+    for (src = text; *src != '\0'; src++) {
+        switch (*src) {
+            case '<':
+                strcpy(dst, "&lt;");
+                dst += 4;
+                break;
+            case '>':
+                strcpy(dst, "&gt;");
+                dst += 4;
+                break;
+            case '&':
+                strcpy(dst, "&amp;");
+                dst += 5;
+                break;
+            case '"':
+                strcpy(dst, "&quot;");
+                dst += 6;
+                break;
+            default:
+                *dst = *src;
+                dst++;
+        }
+    }
+    *dst = '\0';
+    return buf;
+}
+
 /* small helper function */
 static inline void _render_update(int *written, const int length,
 			   const int lastwrite,
@@ -236,6 +294,7 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
     xmpp_stanza_t *child;
     hash_iterator_t *iter;
     const char *key;
+    char *tmp;
 
     written = 0;
 
@@ -244,7 +303,10 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
     if (stanza->type == XMPP_STANZA_TEXT) {
 	if (!stanza->data) return XMPP_EINVOP;
 
-	ret = xmpp_snprintf(ptr, left, "%s", stanza->data);
+	tmp = _escape_xml(stanza->ctx, stanza->data);
+	if (tmp == NULL) return XMPP_EMEM;
+	ret = xmpp_snprintf(ptr, left, "%s", tmp);
+	xmpp_free(stanza->ctx, tmp);
 	if (ret < 0) return XMPP_EMEM;
 	_render_update(&written, buflen, ret, &left, &ptr);
     } else { /* stanza->type == XMPP_STANZA_TAG */
@@ -258,8 +320,11 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
 	if (stanza->attributes && hash_num_keys(stanza->attributes) > 0) {
 	    iter = hash_iter_new(stanza->attributes);
 	    while ((key = hash_iter_next(iter))) {
-		ret = xmpp_snprintf(ptr, left, " %s=\"%s\"", key,
-			       (char *)hash_get(stanza->attributes, key));
+		tmp = _escape_xml(stanza->ctx,
+		    (char *)hash_get(stanza->attributes, key));
+		if (tmp == NULL) return XMPP_EMEM;
+		ret = xmpp_snprintf(ptr, left, " %s=\"%s\"", key, tmp);
+		xmpp_free(stanza->ctx, tmp);
 		if (ret < 0) return XMPP_EMEM;
 		_render_update(&written, buflen, ret, &left, &ptr);
 	    }