File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/xmlrpc_parse.c |
Location: | line 604, column 13 |
Description: | Branch condition evaluates to a garbage value |
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. */ |