File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/xmlrpc_parse.c |
Location: | line 311, column 9 |
Description: | Access to field 'fault_occurred' results in a dereference of a null pointer (loaded from variable 'envP') |
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. */ |