Exemple #1
0
static void
parseCallXml(xmlrpc_env *   const envP,
             const char *   const xmlData,
             size_t         const xmlDataLen,
             xml_element ** const callElemPP) {
/*----------------------------------------------------------------------------
   Parse the XML of an XML-RPC call.
-----------------------------------------------------------------------------*/
    xml_element * callElemP;
    xmlrpc_env env;

    xmlrpc_env_init(&env);
    xml_parse(&env, xmlData, xmlDataLen, &callElemP);
    if (env.fault_occurred)
        xmlrpc_env_set_fault_formatted(
            envP, env.fault_code, "Call is not valid XML.  %s",
            env.fault_string);
    else {
        if (!xmlrpc_streq(xml_element_name(callElemP), "methodCall"))
            setParseFault(envP,
                          "XML-RPC call should be a <methodCall> element.  "
                          "Instead, we have a <%s> element.",
                          xml_element_name(callElemP));

        if (envP->fault_occurred)
            xml_element_free(callElemP);
    }
    *callElemPP = callElemP;

    xmlrpc_env_clean(&env);
}
Exemple #2
0
void
xml_element_free(xml_element * const elemP) {
/*----------------------------------------------------------------------------
  Blow away an existing element & all of its child elements.
-----------------------------------------------------------------------------*/
    xmlrpc_mem_block * children;
    unsigned int size;
    unsigned int i;
    xml_element ** contents;

    XMLRPC_ASSERT_ELEM_OK(elemP);

    xmlrpc_strfree(elemP->name);
    elemP->name = XMLRPC_BAD_POINTER;
    xmlrpc_mem_block_clean(&elemP->cdata);

    /* Deallocate all of our children recursively. */
    children = &elemP->children;
    contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(xml_element *, children);
    size = XMLRPC_TYPED_MEM_BLOCK_SIZE(xml_element *, children);
    for (i = 0; i < size; ++i)
        xml_element_free(contents[i]);

    xmlrpc_mem_block_clean(&elemP->children);

    free(elemP);
}
void
xmlrpc_parse_response2(xmlrpc_env *    const envP,
                       const char *    const xmlData,
                       size_t          const xmlDataLen,
                       xmlrpc_value ** const resultPP,
                       int *           const faultCodeP,
                       const char **   const faultStringP) {
/*----------------------------------------------------------------------------
  Given some XML text, attempt to parse it as an XML-RPC response.

  If the response is a regular, valid response, return a new reference
  to the appropriate value as *resultP and return NULL as
  *faultStringP and nothing as *faultCodeP.

  If the response is valid, but indicates a failure of the RPC, return the
  fault string in newly malloc'ed space as *faultStringP and the fault
  code as *faultCodeP and nothing as *resultP.

  If the XML text is not a valid response or something prevents us from
  parsing it, return a description of the error as *envP and nothing else.
-----------------------------------------------------------------------------*/
    xml_element * response;

    XMLRPC_ASSERT_ENV_OK(envP);
    XMLRPC_ASSERT(xmlData != NULL);

    /* SECURITY: Last-ditch attempt to make sure our content length is legal.
    ** XXX - This check occurs too late to prevent an attacker from creating
    ** an enormous memory block, so you should try to enforce it
    ** *before* reading any data off the network. */
    if (xmlDataLen > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID))
        xmlrpc_env_set_fault_formatted(
            envP, XMLRPC_LIMIT_EXCEEDED_ERROR,
            "XML-RPC response too large.  Our limit is %u characters.  "
            "We got %u characters",
            xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID), xmlDataLen);
    else {
        xmlrpc_env env;
        xmlrpc_env_init(&env);

        xml_parse(&env, xmlData, xmlDataLen, &response);

        if (env.fault_occurred)
            setParseFault(envP, "Not valid XML.  %s", env.fault_string);
        else {
            /* Pick apart and verify our structure. */
            if (xmlrpc_streq(xml_element_name(response), "methodResponse")) {
                parseMethodResponseElt(envP, response,
                                       resultPP, faultCodeP, faultStringP);
            } else
                setParseFault(envP, "XML-RPC response must consist of a "
                              "<methodResponse> element.  "
                              "This has a <%s> instead.",
                              xml_element_name(response));
            
            xml_element_free(response);
        }
        xmlrpc_env_clean(&env);
    }
}
static void
test_parse_xml_call(void) {

    xmlrpc_env env;
    const char *method_name;
    xmlrpc_value *params;
    int i1, i2;
    const char **bad_call;
    xml_element *elem;

    xmlrpc_env_init(&env);

    /* Parse a valid call. */
    xmlrpc_parse_call(&env, serialized_call, strlen(serialized_call),
                      &method_name, &params);
    TEST_NO_FAULT(&env);
    TEST(params != NULL);
    xmlrpc_decompose_value(&env, params, "(ii)", &i1, &i2);
    xmlrpc_DECREF(params);    
    TEST_NO_FAULT(&env);
    TEST(streq(method_name, "gloom&doom"));
    TEST(i1 == 10 && i2 == 20);
    strfree(method_name);

    /* Test some poorly-formed XML data. */
    xmlrpc_parse_call(&env, unparseable_value, strlen(unparseable_value),
                      &method_name, &params);
    TEST_FAULT(&env, XMLRPC_PARSE_ERROR);
    TEST(method_name == NULL && params == NULL);

    /* Next, check for bogus values. These are all well-formed XML, but
       they aren't legal XML-RPC.
    */
    for (bad_call = bad_calls; *bad_call != NULL; ++bad_call) {
    
        /* First, check to make sure that our test case is well-formed XML.
        ** (It's easy to make mistakes when writing the test cases!) */
        xml_parse(&env, *bad_call, strlen(*bad_call), &elem);
        TEST_NO_FAULT(&env);
        xml_element_free(elem);

        /* Now, make sure the higher-level routine barfs appropriately. */
        xmlrpc_parse_call(&env, *bad_call, strlen(*bad_call),
                          &method_name, &params);
        TEST_FAULT(&env, XMLRPC_PARSE_ERROR);
        TEST(method_name == NULL && params == NULL);
    }
    xmlrpc_env_clean(&env);    
}
Exemple #5
0
void
xmlrpc_parse_value_xml(xmlrpc_env *    const envP,
                       const char *    const xmlData,
                       size_t          const xmlDataLen,
                       xmlrpc_value ** const valuePP) {
/*----------------------------------------------------------------------------
   Compute the xmlrpc_value represented by the XML document 'xmlData' (of
   length 'xmlDataLen' characters), which must consist of a single <value>
   element.  Return that xmlrpc_value.

   We call convert_array() and convert_struct(), which may ultimately
   call us recursively.  Don't recurse any more than 'maxRecursion'
   times.

   This isn't generally useful in XML-RPC programs, because such programs
   parse a whole XML-RPC call or response document, and never see the XML text
   of just a <value> element.  But a program may do some weird form of XML-RPC
   processing or just borrow Xmlrpc-c's value serialization facilities for
   something unrelated to XML-RPC.  In any case, it makes sense to have an
   inverse of xmlrpc_serialize_value2(), which generates XML text from an
   xmlrpc_value.
-----------------------------------------------------------------------------*/
    xmlrpc_env env;

    xml_element * valueEltP;

    XMLRPC_ASSERT_ENV_OK(envP);
    XMLRPC_ASSERT(xmlData != NULL);

    xmlrpc_env_init(&env);

    xml_parse(&env, xmlData, xmlDataLen, &valueEltP);

    if (env.fault_occurred) {
        setParseFault(envP, "Not valid XML.  %s", env.fault_string);
    } else {
        if (xmlrpc_streq(xml_element_name(valueEltP), "value")) {
            unsigned int const maxRecursion = (unsigned int)
                xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID);
            xmlrpc_parseValue(envP, maxRecursion, valueEltP, valuePP);
        } else
            setParseFault(envP, "XML-RPC value XML document must consist of "
                          "a <value> element.  This has a <%s> instead.",
                          xml_element_name(valueEltP));
        xml_element_free(valueEltP);
    }
    xmlrpc_env_clean(&env);
}
static void
testParseBadResult(void) {
/*----------------------------------------------------------------------------
   Test parsing of data that is supposed to be a response, but is not
   valid.  It looks like a valid success response, but the result value
   is not valid XML-RPC.
-----------------------------------------------------------------------------*/
    unsigned int i;

    for (i = 0; bad_values[i] != NULL; ++i) {
        const char * const bad_resp = bad_values[i];
        xmlrpc_env env;
        xmlrpc_value * valueP;
        xml_element *elem;
        int faultCode;
        const char * faultString;
    
        xmlrpc_env_init(&env);

        /* First, check to make sure that our test case is well-formed XML.
        ** (It's easy to make mistakes when writing the test cases!) */
        xml_parse(&env, bad_resp, strlen(bad_resp), &elem);
        TEST_NO_FAULT(&env);
        xml_element_free(elem);
    
        /* Now, make sure the higher-level routine barfs appropriately. */
        
        xmlrpc_parse_response2(&env, bad_resp, strlen(bad_resp),
                               &valueP, &faultCode, &faultString);

        TEST_FAULT(&env, XMLRPC_PARSE_ERROR);
        xmlrpc_env_clean(&env);

        xmlrpc_env_init(&env);

        /* And again with the old interface */

        valueP = xmlrpc_parse_response(&env, bad_resp, strlen(bad_resp));
        TEST_FAULT(&env, XMLRPC_PARSE_ERROR);
        TEST(valueP == NULL);
        xmlrpc_env_clean(&env);
    }
}
static void test_expat (void)
{
    xmlrpc_env env;
    xml_element *elem, *array, *data, *value1, *i4;
    char *cdata;
    size_t size;

    xmlrpc_env_init(&env);

    /* Parse a moderately complex XML document. */
    xml_parse(&env, expat_data, strlen(expat_data), &elem);
    TEST_NO_FAULT(&env);
    TEST(elem != NULL);

    /* Verify our results. */
    TEST(streq(xml_element_name(elem), "value"));
    TEST(xml_element_children_size(elem) == 1);
    array = xml_element_children(elem)[0];
    TEST(streq(xml_element_name(array), "array"));
    TEST(xml_element_children_size(array) == 1);
    data = xml_element_children(array)[0];
    TEST(streq(xml_element_name(data), "data"));
    TEST(xml_element_children_size(data) > 1);
    value1 = xml_element_children(data)[0];
    TEST(streq(xml_element_name(value1), "value"));
    TEST(xml_element_children_size(value1) == 1);
    i4 = xml_element_children(value1)[0];
    TEST(streq(xml_element_name(i4), "i4"));
    TEST(xml_element_children_size(i4) == 0);
    cdata = xml_element_cdata(i4);
    size = xml_element_cdata_size(i4);
    TEST(size == strlen("2147483647"));
    TEST(memcmp(cdata, "2147483647", strlen("2147483647")) == 0);

    /* Test cleanup code (w/memprof). */
    xml_element_free(elem);

    /* Test broken XML */
    xml_parse(&env, expat_error_data, strlen(expat_error_data), &elem);
    TEST(env.fault_occurred);

    xmlrpc_env_clean(&env);
}
Exemple #8
0
void 
xmlrpc_parse_call(xmlrpc_env *    const envP,
                  const char *    const xmlData,
                  size_t          const xmlDataLen,
                  const char **   const methodNameP,
                  xmlrpc_value ** const paramArrayPP) {
/*----------------------------------------------------------------------------
  Given some XML text, attempt to parse it as an XML-RPC call.
  Return as *methodNameP the name of the method identified in the call
  and as *paramArrayPP the parameter list as an XML-RPC array.
  Caller must free() and xmlrpc_DECREF() these, respectively).
-----------------------------------------------------------------------------*/
    XMLRPC_ASSERT_ENV_OK(envP);
    XMLRPC_ASSERT(xmlData != NULL);
    XMLRPC_ASSERT(methodNameP != NULL && paramArrayPP != NULL);

    /* SECURITY: Last-ditch attempt to make sure our content length is
       legal.  XXX - This check occurs too late to prevent an attacker
       from creating an enormous memory block, so you should try to
       enforce it *before* reading any data off the network.
     */
    if (xmlDataLen > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID))
        xmlrpc_env_set_fault_formatted(
            envP, XMLRPC_LIMIT_EXCEEDED_ERROR,
            "XML-RPC request too large.  Max allowed is %u bytes",
            (unsigned)xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID));
    else {
        xml_element * callElemP;
        parseCallXml(envP, xmlData, xmlDataLen, &callElemP);
        if (!envP->fault_occurred) {
            parseCallChildren(envP, callElemP, methodNameP, paramArrayPP);

            xml_element_free(callElemP);
        }
    }
    if (envP->fault_occurred) {
        /* Should not be necessary, but for backward compatibility: */
        *methodNameP  = NULL;
        *paramArrayPP = NULL;
    }
}
Exemple #9
0
static void
xmlElementAppendChild(xmlrpc_env *  const envP,
				      xml_element * const elemP,
				      xml_element * const childP) {

    /* Whether or not this function succeeds, it takes ownership of the 'child'
       argument.
       WARNING - This is the exact opposite of the usual memory ownership
       rules for xmlrpc_value! So please pay attention.
    */
    XMLRPC_ASSERT_ENV_OK(envP);
    XMLRPC_ASSERT_ELEM_OK(elemP);
    XMLRPC_ASSERT_ELEM_OK(childP);
    assert(childP->parentP == NULL);

    XMLRPC_TYPED_MEM_BLOCK_APPEND(xml_element *, envP, &elemP->children,
                                  &childP, 1);
    if (!envP->fault_occurred)
        childP->parentP = elemP;
    else
        xml_element_free(childP);
}
static void
testParseBadResponseXmlRpc(void) {
/*----------------------------------------------------------------------------
   Test parsing of data that is supposed to be a response, and is valid
   XML, but is not valid XML-RPC.
-----------------------------------------------------------------------------*/
    unsigned int i;

    /* For this test, we test up to but not including the <value> in a
       successful RPC response. 
    */

    /* Next, check for bogus responses. These are all well-formed XML, but
    ** they aren't legal XML-RPC. */
    for (i = 15; bad_responses[i] != NULL; ++i) {
        const char * const bad_resp = bad_responses[i];
        xmlrpc_env env;
        xmlrpc_value * v;
        xml_element *elem;

        xmlrpc_env_init(&env);
    
        /* First, check to make sure that our test case is well-formed XML.
        ** (It's easy to make mistakes when writing the test cases!) */
        xml_parse(&env, bad_resp, strlen(bad_resp), &elem);
        TEST_NO_FAULT(&env);
        xml_element_free(elem);
    
        /* Now, make sure the higher-level routine barfs appropriately. */
        v = xmlrpc_parse_response(&env, bad_resp, strlen(bad_resp));
        TEST(env.fault_occurred);
        TEST(env.fault_code != 0); /* We use 0 as a code in our bad faults. */
        TEST(v == NULL);
        xmlrpc_env_clean(&env);
    }
}