| 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. */ |