File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/xmlrpc_parse.c |
Location: | line 256, column 31 |
Description: | Dereference of null pointer (loaded from variable 'paramArrayPP') |
1 | /* Copyright information is at end of file. */ | |||||||
2 | ||||||||
3 | #define _XOPEN_SOURCE700 600 /* Make sure strdup() is in <string.h> */ | |||||||
4 | ||||||||
5 | #include "xmlrpc_config.h" | |||||||
6 | ||||||||
7 | #include <stddef.h> | |||||||
8 | #include <stdlib.h> | |||||||
9 | #include <string.h> | |||||||
10 | #include <errno(*__errno_location ()).h> | |||||||
11 | #include <ctype.h> | |||||||
12 | #include <limits.h> | |||||||
13 | ||||||||
14 | #include "bool.h" | |||||||
15 | ||||||||
16 | #include "xmlrpc-c/base.h" | |||||||
17 | #include "xmlrpc-c/base_int.h" | |||||||
18 | #include "xmlrpc-c/string_int.h" | |||||||
19 | #include "xmlrpc-c/util.h" | |||||||
20 | #include "xmlrpc-c/xmlparser.h" | |||||||
21 | #include "parse_value.h" | |||||||
22 | ||||||||
23 | ||||||||
24 | /* Notes about XML-RPC XML documents: | |||||||
25 | ||||||||
26 | Contain CDATA: methodName, i4, int, boolean, string, double, | |||||||
27 | dateTime.iso8601, base64, name | |||||||
28 | ||||||||
29 | We attempt to validate the structure of the XML document carefully. | |||||||
30 | We also try *very* hard to handle malicious data gracefully, and without | |||||||
31 | leaking memory. | |||||||
32 | ||||||||
33 | The CHECK_NAME and CHECK_CHILD_COUNT macros examine an XML element, and | |||||||
34 | invoke XMLRPC_FAIL if something looks wrong. | |||||||
35 | */ | |||||||
36 | ||||||||
37 | static void | |||||||
38 | setParseFault(xmlrpc_env * const envP, | |||||||
39 | const char * const format, | |||||||
40 | ...) { | |||||||
41 | ||||||||
42 | va_list args; | |||||||
43 | va_start(args, format)__builtin_va_start(args, format); | |||||||
44 | xmlrpc_set_fault_formatted_v(envP, XMLRPC_PARSE_ERROR(-503), format, args); | |||||||
45 | va_end(args)__builtin_va_end(args); | |||||||
46 | } | |||||||
47 | ||||||||
48 | ||||||||
49 | ||||||||
50 | #define CHECK_NAME(env,elem,name)do if (!xmlrpc_streq((name), xml_element_name(elem))) do { xmlrpc_env_set_fault_formatted ((env),((-503)),("Expected element of type <%s>, found <%s>" ),((name)),(xml_element_name(elem))); goto cleanup; } while ( 0); while (0) \ | |||||||
51 | do \ | |||||||
52 | if (!xmlrpc_streq((name), xml_element_name(elem))) \ | |||||||
53 | XMLRPC_FAIL2(env, XMLRPC_PARSE_ERROR, \do { xmlrpc_env_set_fault_formatted((env),((-503)),("Expected element of type <%s>, found <%s>" ),((name)),(xml_element_name(elem))); goto cleanup; } while ( 0) | |||||||
54 | "Expected element of type <%s>, found <%s>", \do { xmlrpc_env_set_fault_formatted((env),((-503)),("Expected element of type <%s>, found <%s>" ),((name)),(xml_element_name(elem))); goto cleanup; } while ( 0) | |||||||
55 | (name), xml_element_name(elem))do { xmlrpc_env_set_fault_formatted((env),((-503)),("Expected element of type <%s>, found <%s>" ),((name)),(xml_element_name(elem))); goto cleanup; } while ( 0); \ | |||||||
56 | while (0) | |||||||
57 | ||||||||
58 | #define CHECK_CHILD_COUNT(env,elem,count)do if (xml_element_children_size(elem) != (count)) do { xmlrpc_env_set_fault_formatted ((env),((-503)), ("Expected <%s> to have %u children, found %u" ),(xml_element_name(elem)),((count)),((unsigned)xml_element_children_size (elem))); goto cleanup; } while (0); while (0) \ | |||||||
59 | do \ | |||||||
60 | if (xml_element_children_size(elem) != (count)) \ | |||||||
61 | XMLRPC_FAIL3(env, XMLRPC_PARSE_ERROR, \do { xmlrpc_env_set_fault_formatted((env),((-503)), ("Expected <%s> to have %u children, found %u" ),(xml_element_name(elem)),((count)),((unsigned)xml_element_children_size (elem))); goto cleanup; } while (0) | |||||||
62 | "Expected <%s> to have %u children, found %u", \do { xmlrpc_env_set_fault_formatted((env),((-503)), ("Expected <%s> to have %u children, found %u" ),(xml_element_name(elem)),((count)),((unsigned)xml_element_children_size (elem))); goto cleanup; } while (0) | |||||||
63 | xml_element_name(elem), (count), \do { xmlrpc_env_set_fault_formatted((env),((-503)), ("Expected <%s> to have %u children, found %u" ),(xml_element_name(elem)),((count)),((unsigned)xml_element_children_size (elem))); goto cleanup; } while (0) | |||||||
64 | (unsigned)xml_element_children_size(elem))do { xmlrpc_env_set_fault_formatted((env),((-503)), ("Expected <%s> to have %u children, found %u" ),(xml_element_name(elem)),((count)),((unsigned)xml_element_children_size (elem))); goto cleanup; } while (0); \ | |||||||
65 | while (0) | |||||||
66 | ||||||||
67 | static xml_element * | |||||||
68 | getChildByName (xmlrpc_env * const envP, | |||||||
69 | xml_element * const parentP, | |||||||
70 | const char * const name) { | |||||||
71 | ||||||||
72 | size_t const childCount = xml_element_children_size(parentP); | |||||||
73 | xml_element ** const childrenP = xml_element_children(parentP); | |||||||
74 | ||||||||
75 | unsigned int i; | |||||||
76 | ||||||||
77 | for (i = 0; i < childCount; ++i) { | |||||||
78 | if (xmlrpc_streq(xml_element_name(childrenP[i]), name)) | |||||||
79 | return childrenP[i]; | |||||||
80 | } | |||||||
81 | ||||||||
82 | setParseFault(envP, "Expected <%s> to have child <%s>", | |||||||
83 | xml_element_name(parentP), name); | |||||||
84 | return NULL((void*)0); | |||||||
85 | } | |||||||
86 | ||||||||
87 | ||||||||
88 | ||||||||
89 | /*========================================================================= | |||||||
90 | ** convert_params | |||||||
91 | **========================================================================= | |||||||
92 | ** Convert an XML element representing a list of params into an | |||||||
93 | ** xmlrpc_value (of type array). | |||||||
94 | */ | |||||||
95 | ||||||||
96 | static xmlrpc_value * | |||||||
97 | convert_params(xmlrpc_env * const envP, | |||||||
98 | const xml_element * const elemP) { | |||||||
99 | /*---------------------------------------------------------------------------- | |||||||
100 | Convert an XML element representing a list of parameters (i.e. a <params> | |||||||
101 | element) to an xmlrpc_value of type array. Note that an xmlrpc_value is | |||||||
102 | normally represented in XML by a <value> element, not a <params> element. | |||||||
103 | We use type xmlrpc_value to represent the parameter list just for | |||||||
104 | convenience. | |||||||
105 | -----------------------------------------------------------------------------*/ | |||||||
106 | xmlrpc_value *array, *item; | |||||||
107 | int size, i; | |||||||
108 | xml_element **params, *param, *value; | |||||||
109 | ||||||||
110 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/xmlrpc_parse.c", 110); while ( 0); | |||||||
111 | XMLRPC_ASSERT(elemP != NULL)do if (!(elemP != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_parse.c" , 111); while (0); | |||||||
112 | ||||||||
113 | /* Set up our error-handling preconditions. */ | |||||||
114 | array = item = NULL((void*)0); | |||||||
115 | ||||||||
116 | /* Allocate an array to hold our parameters. */ | |||||||
117 | array = xmlrpc_build_value(envP, "()"); | |||||||
118 | XMLRPC_FAIL_IF_FAULT(envP)do { if ((envP)->fault_occurred) goto cleanup; } while (0); | |||||||
119 | ||||||||
120 | /* We're responsible for checking our own element name. */ | |||||||
121 | CHECK_NAME(envP, elemP, "params")do if (!xmlrpc_streq(("params"), xml_element_name(elemP))) do { xmlrpc_env_set_fault_formatted((envP),((-503)),("Expected element of type <%s>, found <%s>" ),(("params")),(xml_element_name(elemP))); goto cleanup; } while (0); while (0); | |||||||
122 | ||||||||
123 | /* Iterate over our children. */ | |||||||
124 | size = xml_element_children_size(elemP); | |||||||
125 | params = xml_element_children(elemP); | |||||||
126 | for (i = 0; i < size; ++i) { | |||||||
127 | unsigned int const maxNest = (unsigned int) | |||||||
128 | xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID(0)); | |||||||
129 | ||||||||
130 | param = params[i]; | |||||||
131 | CHECK_NAME(envP, param, "param")do if (!xmlrpc_streq(("param"), xml_element_name(param))) do { xmlrpc_env_set_fault_formatted((envP),((-503)),("Expected element of type <%s>, found <%s>" ),(("param")),(xml_element_name(param))); goto cleanup; } while (0); while (0); | |||||||
132 | CHECK_CHILD_COUNT(envP, param, 1)do if (xml_element_children_size(param) != (1)) do { xmlrpc_env_set_fault_formatted ((envP),((-503)), ("Expected <%s> to have %u children, found %u" ),(xml_element_name(param)),((1)),((unsigned)xml_element_children_size (param))); goto cleanup; } while (0); while (0); | |||||||
133 | ||||||||
134 | value = xml_element_children(param)[0]; | |||||||
135 | ||||||||
136 | CHECK_NAME(envP, value, "value")do if (!xmlrpc_streq(("value"), xml_element_name(value))) do { xmlrpc_env_set_fault_formatted((envP),((-503)),("Expected element of type <%s>, found <%s>" ),(("value")),(xml_element_name(value))); goto cleanup; } while (0); while (0); | |||||||
137 | ||||||||
138 | xmlrpc_parseValue(envP, maxNest, value, &item); | |||||||
139 | XMLRPC_FAIL_IF_FAULT(envP)do { if ((envP)->fault_occurred) goto cleanup; } while (0); | |||||||
140 | ||||||||
141 | xmlrpc_array_append_item(envP, array, item); | |||||||
142 | xmlrpc_DECREF(item); | |||||||
143 | item = NULL((void*)0); | |||||||
144 | XMLRPC_FAIL_IF_FAULT(envP)do { if ((envP)->fault_occurred) goto cleanup; } while (0); | |||||||
145 | } | |||||||
146 | ||||||||
147 | cleanup: | |||||||
148 | if (envP->fault_occurred) { | |||||||
149 | if (array) | |||||||
150 | xmlrpc_DECREF(array); | |||||||
151 | if (item) | |||||||
152 | xmlrpc_DECREF(item); | |||||||
153 | return NULL((void*)0); | |||||||
154 | } | |||||||
155 | return array; | |||||||
156 | } | |||||||
157 | ||||||||
158 | ||||||||
159 | ||||||||
160 | static void | |||||||
161 | parseCallXml(xmlrpc_env * const envP, | |||||||
162 | const char * const xmlData, | |||||||
163 | size_t const xmlDataLen, | |||||||
164 | xml_element ** const callElemPP) { | |||||||
165 | /*---------------------------------------------------------------------------- | |||||||
166 | Parse the XML of an XML-RPC call. | |||||||
167 | -----------------------------------------------------------------------------*/ | |||||||
168 | xml_element * callElemP; | |||||||
169 | xmlrpc_env env; | |||||||
170 | ||||||||
171 | xmlrpc_env_init(&env); | |||||||
172 | xml_parse(&env, xmlData, xmlDataLen, &callElemP); | |||||||
173 | if (env.fault_occurred) | |||||||
174 | xmlrpc_env_set_fault_formatted( | |||||||
175 | envP, env.fault_code, "Call is not valid XML. %s", | |||||||
176 | env.fault_string); | |||||||
177 | else { | |||||||
178 | if (!xmlrpc_streq(xml_element_name(callElemP), "methodCall")) | |||||||
179 | setParseFault(envP, | |||||||
180 | "XML-RPC call should be a <methodCall> element. " | |||||||
181 | "Instead, we have a <%s> element.", | |||||||
182 | xml_element_name(callElemP)); | |||||||
183 | ||||||||
184 | if (envP->fault_occurred) | |||||||
185 | xml_element_free(callElemP); | |||||||
186 | } | |||||||
187 | *callElemPP = callElemP; | |||||||
188 | ||||||||
189 | xmlrpc_env_clean(&env); | |||||||
190 | } | |||||||
191 | ||||||||
192 | ||||||||
193 | ||||||||
194 | static void | |||||||
195 | parseMethodNameElement(xmlrpc_env * const envP, | |||||||
196 | xml_element * const nameElemP, | |||||||
197 | const char ** const methodNameP) { | |||||||
198 | ||||||||
199 | XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(nameElemP), "methodName"))do if (!(xmlrpc_streq(xml_element_name(nameElemP), "methodName" ))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_parse.c" , 199); while (0); | |||||||
200 | ||||||||
201 | if (xml_element_children_size(nameElemP) > 0) | |||||||
202 | setParseFault(envP, "A <methodName> element should not have " | |||||||
203 | "children. This one has %u of them.", | |||||||
204 | xml_element_children_size(nameElemP)); | |||||||
205 | else { | |||||||
206 | const char * const cdata = xml_element_cdata(nameElemP); | |||||||
207 | ||||||||
208 | xmlrpc_validate_utf8(envP, cdata, strlen(cdata)); | |||||||
209 | ||||||||
210 | if (!envP->fault_occurred) { | |||||||
211 | *methodNameP = strdup(cdata)(__extension__ (__builtin_constant_p (cdata) && ((size_t )(const void *)((cdata) + 1) - (size_t)(const void *)(cdata) == 1) ? (((const char *) (cdata))[0] == '\0' ? (char *) calloc ( (size_t) 1, (size_t) 1) : ({ size_t __len = strlen (cdata) + 1 ; char *__retval = (char *) malloc (__len); if (__retval != ( (void*)0)) __retval = (char *) memcpy (__retval, cdata, __len ); __retval; })) : __strdup (cdata))); | |||||||
212 | if (*methodNameP == NULL((void*)0)) | |||||||
213 | xmlrpc_faultf(envP, | |||||||
214 | "Could not allocate memory for method name"); | |||||||
215 | } | |||||||
216 | } | |||||||
217 | } | |||||||
218 | ||||||||
219 | ||||||||
220 | ||||||||
221 | static void | |||||||
222 | parseCallChildren(xmlrpc_env * const envP, | |||||||
223 | xml_element * const callElemP, | |||||||
224 | const char ** const methodNameP, | |||||||
225 | xmlrpc_value ** const paramArrayPP ) { | |||||||
226 | /*---------------------------------------------------------------------------- | |||||||
227 | Parse the children of a <methodCall> XML element *callElemP. They should | |||||||
228 | be <methodName> and <params>. | |||||||
229 | -----------------------------------------------------------------------------*/ | |||||||
230 | size_t const callChildCount = xml_element_children_size(callElemP); | |||||||
231 | ||||||||
232 | xml_element * nameElemP; | |||||||
233 | ||||||||
234 | XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(callElemP), "methodCall"))do if (!(xmlrpc_streq(xml_element_name(callElemP), "methodCall" ))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_parse.c" , 234); while (0); | |||||||
235 | ||||||||
236 | nameElemP = getChildByName(envP, callElemP, "methodName"); | |||||||
237 | ||||||||
238 | if (!envP->fault_occurred) { | |||||||
239 | parseMethodNameElement(envP, nameElemP, methodNameP); | |||||||
240 | ||||||||
241 | if (!envP->fault_occurred) { | |||||||
242 | /* Convert our parameters. */ | |||||||
243 | if (callChildCount > 1) { | |||||||
244 | xml_element * paramsElemP; | |||||||
245 | ||||||||
246 | paramsElemP = getChildByName(envP, callElemP, "params"); | |||||||
247 | ||||||||
248 | if (!envP->fault_occurred) | |||||||
249 | *paramArrayPP = convert_params(envP, paramsElemP); | |||||||
250 | } else { | |||||||
251 | /* Workaround for Ruby XML-RPC and old versions of | |||||||
252 | xmlrpc-epi. Future improvement: Instead of looking | |||||||
253 | at child count, we should just check for existence | |||||||
254 | of <params>. | |||||||
255 | */ | |||||||
256 | *paramArrayPP = xmlrpc_array_new(envP); | |||||||
| ||||||||
257 | } | |||||||
258 | if (!envP->fault_occurred) { | |||||||
259 | if (callChildCount > 2) | |||||||
260 | setParseFault(envP, "<methodCall> has extraneous " | |||||||
261 | "children, other than <methodName> and " | |||||||
262 | "<params>. Total child count = %u", | |||||||
263 | callChildCount); | |||||||
264 | ||||||||
265 | if (envP->fault_occurred) | |||||||
266 | xmlrpc_DECREF(*paramArrayPP); | |||||||
267 | } | |||||||
268 | if (envP->fault_occurred) | |||||||
269 | xmlrpc_strfree(*methodNameP); | |||||||
270 | } | |||||||
271 | } | |||||||
272 | } | |||||||
273 | ||||||||
274 | ||||||||
275 | ||||||||
276 | void | |||||||
277 | xmlrpc_parse_call(xmlrpc_env * const envP, | |||||||
278 | const char * const xmlData, | |||||||
279 | size_t const xmlDataLen, | |||||||
280 | const char ** const methodNameP, | |||||||
281 | xmlrpc_value ** const paramArrayPP) { | |||||||
282 | /*---------------------------------------------------------------------------- | |||||||
283 | Given some XML text, attempt to parse it as an XML-RPC call. | |||||||
284 | Return as *methodNameP the name of the method identified in the call | |||||||
285 | and as *paramArrayPP the parameter list as an XML-RPC array. | |||||||
286 | Caller must free() and xmlrpc_DECREF() these, respectively). | |||||||
287 | -----------------------------------------------------------------------------*/ | |||||||
288 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/xmlrpc_parse.c", 288); while ( 0); | |||||||
289 | XMLRPC_ASSERT(xmlData != NULL)do if (!(xmlData != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_parse.c" , 289); while (0); | |||||||
290 | XMLRPC_ASSERT(methodNameP != NULL && paramArrayPP != NULL)do if (!(methodNameP != ((void*)0) && paramArrayPP != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_parse.c" , 290); while (0); | |||||||
| ||||||||
291 | ||||||||
292 | /* SECURITY: Last-ditch attempt to make sure our content length is | |||||||
293 | legal. XXX - This check occurs too late to prevent an attacker | |||||||
294 | from creating an enormous memory block, so you should try to | |||||||
295 | enforce it *before* reading any data off the network. | |||||||
296 | */ | |||||||
297 | if (xmlDataLen > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID(1))) | |||||||
298 | xmlrpc_env_set_fault_formatted( | |||||||
299 | envP, XMLRPC_LIMIT_EXCEEDED_ERROR(-509), | |||||||
300 | "XML-RPC request too large. Max allowed is %u bytes", | |||||||
301 | (unsigned)xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID(1))); | |||||||
302 | else { | |||||||
303 | xml_element * callElemP; | |||||||
304 | parseCallXml(envP, xmlData, xmlDataLen, &callElemP); | |||||||
305 | if (!envP->fault_occurred) { | |||||||
306 | parseCallChildren(envP, callElemP, methodNameP, paramArrayPP); | |||||||
307 | ||||||||
308 | xml_element_free(callElemP); | |||||||
309 | } | |||||||
310 | } | |||||||
311 | if (envP->fault_occurred) { | |||||||
312 | /* Should not be necessary, but for backward compatibility: */ | |||||||
313 | *methodNameP = NULL((void*)0); | |||||||
314 | *paramArrayPP = NULL((void*)0); | |||||||
315 | } | |||||||
316 | } | |||||||
317 | ||||||||
318 | ||||||||
319 | ||||||||
320 | static void | |||||||
321 | interpretFaultCode(xmlrpc_env * const envP, | |||||||
322 | xmlrpc_value * const faultCodeVP, | |||||||
323 | int * const faultCodeP) { | |||||||
324 | ||||||||
325 | xmlrpc_env fcEnv; | |||||||
326 | xmlrpc_env_init(&fcEnv); | |||||||
327 | ||||||||
328 | xmlrpc_read_int(&fcEnv, faultCodeVP, faultCodeP); | |||||||
329 | if (fcEnv.fault_occurred) | |||||||
330 | xmlrpc_faultf(envP, "Invalid value for 'faultCode' member. %s", | |||||||
331 | fcEnv.fault_string); | |||||||
332 | ||||||||
333 | xmlrpc_env_clean(&fcEnv); | |||||||
334 | } | |||||||
335 | ||||||||
336 | ||||||||
337 | ||||||||
338 | static void | |||||||
339 | interpretFaultString(xmlrpc_env * const envP, | |||||||
340 | xmlrpc_value * const faultStringVP, | |||||||
341 | const char ** const faultStringP) { | |||||||
342 | ||||||||
343 | xmlrpc_env fsEnv; | |||||||
344 | xmlrpc_env_init(&fsEnv); | |||||||
345 | ||||||||
346 | xmlrpc_read_string(&fsEnv, faultStringVP, faultStringP); | |||||||
347 | ||||||||
348 | if (fsEnv.fault_occurred) | |||||||
349 | xmlrpc_faultf(envP, "Invalid value for 'faultString' member. %s", | |||||||
350 | fsEnv.fault_string); | |||||||
351 | ||||||||
352 | xmlrpc_env_clean(&fsEnv); | |||||||
353 | } | |||||||
354 | ||||||||
355 | ||||||||
356 | ||||||||
357 | static void | |||||||
358 | interpretFaultValue(xmlrpc_env * const envP, | |||||||
359 | xmlrpc_value * const faultVP, | |||||||
360 | int * const faultCodeP, | |||||||
361 | const char ** const faultStringP) { | |||||||
362 | ||||||||
363 | if (faultVP->_type != XMLRPC_TYPE_STRUCT) | |||||||
364 | setParseFault(envP, | |||||||
365 | "<value> element of <fault> response is not " | |||||||
366 | "of structure type"); | |||||||
367 | else { | |||||||
368 | xmlrpc_value * faultCodeVP; | |||||||
369 | xmlrpc_env fvEnv; | |||||||
370 | ||||||||
371 | xmlrpc_env_init(&fvEnv); | |||||||
372 | ||||||||
373 | xmlrpc_struct_read_value(&fvEnv, faultVP, "faultCode", &faultCodeVP); | |||||||
374 | if (!fvEnv.fault_occurred) { | |||||||
375 | interpretFaultCode(&fvEnv, faultCodeVP, faultCodeP); | |||||||
376 | ||||||||
377 | if (!fvEnv.fault_occurred) { | |||||||
378 | xmlrpc_value * faultStringVP; | |||||||
379 | ||||||||
380 | xmlrpc_struct_read_value(&fvEnv, faultVP, "faultString", | |||||||
381 | &faultStringVP); | |||||||
382 | if (!fvEnv.fault_occurred) { | |||||||
383 | interpretFaultString(&fvEnv, faultStringVP, faultStringP); | |||||||
384 | ||||||||
385 | xmlrpc_DECREF(faultStringVP); | |||||||
386 | } | |||||||
387 | } | |||||||
388 | xmlrpc_DECREF(faultCodeVP); | |||||||
389 | } | |||||||
390 | if (fvEnv.fault_occurred) | |||||||
391 | setParseFault(envP, "Invalid struct for <fault> value. %s", | |||||||
392 | fvEnv.fault_string); | |||||||
393 | ||||||||
394 | xmlrpc_env_clean(&fvEnv); | |||||||
395 | } | |||||||
396 | } | |||||||
397 | ||||||||
398 | ||||||||
399 | ||||||||
400 | static void | |||||||
401 | parseFaultElement(xmlrpc_env * const envP, | |||||||
402 | const xml_element * const faultElement, | |||||||
403 | int * const faultCodeP, | |||||||
404 | const char ** const faultStringP) { | |||||||
405 | ||||||||
406 | unsigned int const maxRecursion = (unsigned int) | |||||||
407 | xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID(0)); | |||||||
408 | ||||||||
409 | XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(faultElement), "fault"))do if (!(xmlrpc_streq(xml_element_name(faultElement), "fault" ))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_parse.c" , 409); while (0); | |||||||
410 | ||||||||
411 | if (xml_element_children_size(faultElement) != 1) | |||||||
412 | setParseFault(envP, "<fault> element should have 1 child, " | |||||||
413 | "but it has %u.", | |||||||
414 | xml_element_children_size(faultElement)); | |||||||
415 | else { | |||||||
416 | xml_element * const faultValueP = | |||||||
417 | xml_element_children(faultElement)[0]; | |||||||
418 | const char * const elemName = xml_element_name(faultValueP); | |||||||
419 | ||||||||
420 | if (!xmlrpc_streq(elemName, "value")) | |||||||
421 | setParseFault(envP, | |||||||
422 | "<fault> contains a <%s> element. " | |||||||
423 | "Only <value> makes sense.", | |||||||
424 | elemName); | |||||||
425 | else { | |||||||
426 | xmlrpc_value * faultVP; | |||||||
427 | ||||||||
428 | xmlrpc_parseValue(envP, maxRecursion, faultValueP, &faultVP); | |||||||
429 | ||||||||
430 | if (!envP->fault_occurred) { | |||||||
431 | interpretFaultValue(envP, faultVP, faultCodeP, faultStringP); | |||||||
432 | ||||||||
433 | xmlrpc_DECREF(faultVP); | |||||||
434 | } | |||||||
435 | } | |||||||
436 | } | |||||||
437 | } | |||||||
438 | ||||||||
439 | ||||||||
440 | ||||||||
441 | static void | |||||||
442 | parseParamsElement(xmlrpc_env * const envP, | |||||||
443 | const xml_element * const paramsElementP, | |||||||
444 | xmlrpc_value ** const resultPP) { | |||||||
445 | ||||||||
446 | xmlrpc_value * paramsVP; | |||||||
447 | xmlrpc_env env; | |||||||
448 | ||||||||
449 | xmlrpc_env_init(&env); | |||||||
450 | ||||||||
451 | XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(paramsElementP), "params"))do if (!(xmlrpc_streq(xml_element_name(paramsElementP), "params" ))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_parse.c" , 451); while (0); | |||||||
452 | ||||||||
453 | paramsVP = convert_params(envP, paramsElementP); | |||||||
454 | ||||||||
455 | if (!envP->fault_occurred) { | |||||||
456 | int arraySize; | |||||||
457 | xmlrpc_env sizeEnv; | |||||||
458 | ||||||||
459 | XMLRPC_ASSERT_ARRAY_OK(paramsVP)xmlrpc_abort_if_array_bad(paramsVP); | |||||||
460 | ||||||||
461 | xmlrpc_env_init(&sizeEnv); | |||||||
462 | ||||||||
463 | arraySize = xmlrpc_array_size(&sizeEnv, paramsVP); | |||||||
464 | /* Since it's a valid array, as asserted above, can't fail */ | |||||||
465 | XMLRPC_ASSERT(!sizeEnv.fault_occurred)do if (!(!sizeEnv.fault_occurred)) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_parse.c" , 465); while (0); | |||||||
466 | ||||||||
467 | if (arraySize != 1) | |||||||
468 | setParseFault(envP, "Contains %d items. It should have 1.", | |||||||
469 | arraySize); | |||||||
470 | else { | |||||||
471 | xmlrpc_array_read_item(envP, paramsVP, 0, resultPP); | |||||||
472 | } | |||||||
473 | xmlrpc_DECREF(paramsVP); | |||||||
474 | xmlrpc_env_clean(&sizeEnv); | |||||||
475 | } | |||||||
476 | if (env.fault_occurred) | |||||||
477 | xmlrpc_env_set_fault_formatted( | |||||||
478 | envP, env.fault_code, | |||||||
479 | "Invalid <params> element. %s", env.fault_string); | |||||||
480 | ||||||||
481 | xmlrpc_env_clean(&env); | |||||||
482 | } | |||||||
483 | ||||||||
484 | ||||||||
485 | ||||||||
486 | static void | |||||||
487 | parseMethodResponseElt(xmlrpc_env * const envP, | |||||||
488 | const xml_element * const methodResponseEltP, | |||||||
489 | xmlrpc_value ** const resultPP, | |||||||
490 | int * const faultCodeP, | |||||||
491 | const char ** const faultStringP) { | |||||||
492 | ||||||||
493 | XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(methodResponseEltP),do if (!(xmlrpc_streq(xml_element_name(methodResponseEltP), "methodResponse" ))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_parse.c" , 494); while (0) | |||||||
494 | "methodResponse"))do if (!(xmlrpc_streq(xml_element_name(methodResponseEltP), "methodResponse" ))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_parse.c" , 494); while (0); | |||||||
495 | ||||||||
496 | if (xml_element_children_size(methodResponseEltP) == 1) { | |||||||
497 | xml_element * const child = | |||||||
498 | xml_element_children(methodResponseEltP)[0]; | |||||||
499 | ||||||||
500 | if (xmlrpc_streq(xml_element_name(child), "params")) { | |||||||
501 | /* It's a successful response */ | |||||||
502 | parseParamsElement(envP, child, resultPP); | |||||||
503 | *faultStringP = NULL((void*)0); | |||||||
504 | } else if (xmlrpc_streq(xml_element_name(child), "fault")) { | |||||||
505 | /* It's a failure response */ | |||||||
506 | parseFaultElement(envP, child, faultCodeP, faultStringP); | |||||||
507 | } else | |||||||
508 | setParseFault(envP, | |||||||
509 | "<methodResponse> must contain <params> or <fault>, " | |||||||
510 | "but contains <%s>.", xml_element_name(child)); | |||||||
511 | } else | |||||||
512 | setParseFault(envP, | |||||||
513 | "<methodResponse> has %u children, should have 1.", | |||||||
514 | xml_element_children_size(methodResponseEltP)); | |||||||
515 | } | |||||||
516 | ||||||||
517 | ||||||||
518 | ||||||||
519 | void | |||||||
520 | xmlrpc_parse_response2(xmlrpc_env * const envP, | |||||||
521 | const char * const xmlData, | |||||||
522 | size_t const xmlDataLen, | |||||||
523 | xmlrpc_value ** const resultPP, | |||||||
524 | int * const faultCodeP, | |||||||
525 | const char ** const faultStringP) { | |||||||
526 | /*---------------------------------------------------------------------------- | |||||||
527 | Given some XML text, attempt to parse it as an XML-RPC response. | |||||||
528 | ||||||||
529 | If the response is a regular, valid response, return a new reference | |||||||
530 | to the appropriate value as *resultP and return NULL as | |||||||
531 | *faultStringP and nothing as *faultCodeP. | |||||||
532 | ||||||||
533 | If the response is valid, but indicates a failure of the RPC, return the | |||||||
534 | fault string in newly malloc'ed space as *faultStringP and the fault | |||||||
535 | code as *faultCodeP and nothing as *resultP. | |||||||
536 | ||||||||
537 | If the XML text is not a valid response or something prevents us from | |||||||
538 | parsing it, return a description of the error as *envP and nothing else. | |||||||
539 | -----------------------------------------------------------------------------*/ | |||||||
540 | xml_element * responseEltP; | |||||||
541 | ||||||||
542 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/xmlrpc_parse.c", 542); while ( 0); | |||||||
543 | XMLRPC_ASSERT(xmlData != NULL)do if (!(xmlData != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_parse.c" , 543); while (0); | |||||||
544 | ||||||||
545 | /* SECURITY: Last-ditch attempt to make sure our content length is legal. | |||||||
546 | ** XXX - This check occurs too late to prevent an attacker from creating | |||||||
547 | ** an enormous memory block, so you should try to enforce it | |||||||
548 | ** *before* reading any data off the network. */ | |||||||
549 | if (xmlDataLen > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID(1))) | |||||||
550 | xmlrpc_env_set_fault_formatted( | |||||||
551 | envP, XMLRPC_LIMIT_EXCEEDED_ERROR(-509), | |||||||
552 | "XML-RPC response too large. Our limit is %u characters. " | |||||||
553 | "We got %u characters", | |||||||
554 | (unsigned)xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID(1)), | |||||||
555 | (unsigned)xmlDataLen); | |||||||
556 | else { | |||||||
557 | xmlrpc_env env; | |||||||
558 | xmlrpc_env_init(&env); | |||||||
559 | ||||||||
560 | xml_parse(&env, xmlData, xmlDataLen, &responseEltP); | |||||||
561 | ||||||||
562 | if (env.fault_occurred) | |||||||
563 | setParseFault(envP, "Not valid XML. %s", env.fault_string); | |||||||
564 | else { | |||||||
565 | /* Pick apart and verify our structure. */ | |||||||
566 | if (xmlrpc_streq(xml_element_name(responseEltP), | |||||||
567 | "methodResponse")) { | |||||||
568 | parseMethodResponseElt(envP, responseEltP, | |||||||
569 | resultPP, faultCodeP, faultStringP); | |||||||
570 | } else | |||||||
571 | setParseFault(envP, "XML-RPC response must consist of a " | |||||||
572 | "<methodResponse> element. " | |||||||
573 | "This has a <%s> instead.", | |||||||
574 | xml_element_name(responseEltP)); | |||||||
575 | ||||||||
576 | xml_element_free(responseEltP); | |||||||
577 | } | |||||||
578 | xmlrpc_env_clean(&env); | |||||||
579 | } | |||||||
580 | } | |||||||
581 | ||||||||
582 | ||||||||
583 | ||||||||
584 | xmlrpc_value * | |||||||
585 | xmlrpc_parse_response(xmlrpc_env * const envP, | |||||||
586 | const char * const xmlData, | |||||||
587 | size_t const xmlDataLen) { | |||||||
588 | /*---------------------------------------------------------------------------- | |||||||
589 | This exists for backward compatibility. It is like | |||||||
590 | xmlrpc_parse_response2(), except that it merges the concepts of a | |||||||
591 | failed RPC and an error in executing the RPC. | |||||||
592 | -----------------------------------------------------------------------------*/ | |||||||
593 | xmlrpc_value * retval; | |||||||
594 | xmlrpc_value * result; | |||||||
595 | const char * faultString; | |||||||
596 | int faultCode; | |||||||
597 | ||||||||
598 | xmlrpc_parse_response2(envP, xmlData, xmlDataLen, | |||||||
599 | &result, &faultCode, &faultString); | |||||||
600 | ||||||||
601 | if (envP->fault_occurred) | |||||||
602 | retval = NULL((void*)0); | |||||||
603 | else { | |||||||
604 | if (faultString) { | |||||||
605 | xmlrpc_env_set_fault(envP, faultCode, faultString); | |||||||
606 | xmlrpc_strfree(faultString); | |||||||
607 | retval = NULL((void*)0); | |||||||
608 | } else | |||||||
609 | retval = result; /* transfer reference */ | |||||||
610 | } | |||||||
611 | return retval; | |||||||
612 | } | |||||||
613 | ||||||||
614 | ||||||||
615 | ||||||||
616 | void | |||||||
617 | xmlrpc_parse_value_xml(xmlrpc_env * const envP, | |||||||
618 | const char * const xmlData, | |||||||
619 | size_t const xmlDataLen, | |||||||
620 | xmlrpc_value ** const valuePP) { | |||||||
621 | /*---------------------------------------------------------------------------- | |||||||
622 | Compute the xmlrpc_value represented by the XML document 'xmlData' (of | |||||||
623 | length 'xmlDataLen' characters), which must consist of a single <value> | |||||||
624 | element. Return that xmlrpc_value. | |||||||
625 | ||||||||
626 | We call convert_array() and convert_struct(), which may ultimately | |||||||
627 | call us recursively. Don't recurse any more than 'maxRecursion' | |||||||
628 | times. | |||||||
629 | ||||||||
630 | This isn't generally useful in XML-RPC programs, because such programs | |||||||
631 | parse a whole XML-RPC call or response document, and never see the XML text | |||||||
632 | of just a <value> element. But a program may do some weird form of XML-RPC | |||||||
633 | processing or just borrow Xmlrpc-c's value serialization facilities for | |||||||
634 | something unrelated to XML-RPC. In any case, it makes sense to have an | |||||||
635 | inverse of xmlrpc_serialize_value2(), which generates XML text from an | |||||||
636 | xmlrpc_value. | |||||||
637 | -----------------------------------------------------------------------------*/ | |||||||
638 | xmlrpc_env env; | |||||||
639 | ||||||||
640 | xml_element * valueEltP; | |||||||
641 | ||||||||
642 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/xmlrpc_parse.c", 642); while ( 0); | |||||||
643 | XMLRPC_ASSERT(xmlData != NULL)do if (!(xmlData != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_parse.c" , 643); while (0); | |||||||
644 | ||||||||
645 | xmlrpc_env_init(&env); | |||||||
646 | ||||||||
647 | xml_parse(&env, xmlData, xmlDataLen, &valueEltP); | |||||||
648 | ||||||||
649 | if (env.fault_occurred) { | |||||||
650 | setParseFault(envP, "Not valid XML. %s", env.fault_string); | |||||||
651 | } else { | |||||||
652 | if (xmlrpc_streq(xml_element_name(valueEltP), "value")) { | |||||||
653 | unsigned int const maxRecursion = (unsigned int) | |||||||
654 | xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID(0)); | |||||||
655 | xmlrpc_parseValue(envP, maxRecursion, valueEltP, valuePP); | |||||||
656 | } else | |||||||
657 | setParseFault(envP, "XML-RPC value XML document must consist of " | |||||||
658 | "a <value> element. This has a <%s> instead.", | |||||||
659 | xml_element_name(valueEltP)); | |||||||
660 | xml_element_free(valueEltP); | |||||||
661 | } | |||||||
662 | xmlrpc_env_clean(&env); | |||||||
663 | } | |||||||
664 | ||||||||
665 | ||||||||
666 | ||||||||
667 | /* Copyright (C) 2001 by First Peer, Inc. All rights reserved. | |||||||
668 | ** | |||||||
669 | ** Redistribution and use in source and binary forms, with or without | |||||||
670 | ** modification, are permitted provided that the following conditions | |||||||
671 | ** are met: | |||||||
672 | ** 1. Redistributions of source code must retain the above copyright | |||||||
673 | ** notice, this list of conditions and the following disclaimer. | |||||||
674 | ** 2. Redistributions in binary form must reproduce the above copyright | |||||||
675 | ** notice, this list of conditions and the following disclaimer in the | |||||||
676 | ** documentation and/or other materials provided with the distribution. | |||||||
677 | ** 3. The name of the author may not be used to endorse or promote products | |||||||
678 | ** derived from this software without specific prior written permission. | |||||||
679 | ** | |||||||
680 | ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |||||||
681 | ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||||
682 | ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||||
683 | ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |||||||
684 | ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||||||
685 | ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||||||
686 | ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||||||
687 | ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||||||
688 | ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||||||
689 | ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||||
690 | ** SUCH DAMAGE. */ |