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