Пример #1
0
static void
parseArrayDataChild(xmlrpc_env *   const envP,
                    xml_element *  const childP,
                    unsigned int   const maxRecursion,
                    xmlrpc_value * const arrayP) {

    const char * const elemName = xml_element_name(childP);

    if (!xmlrpc_streq(elemName, "value"))
        setParseFault(envP, "<data> element has <%s> child.  "
                      "Only <value> makes sense.", elemName);
    else {
        xmlrpc_value * itemP;

        xmlrpc_parseValue(envP, maxRecursion-1, childP, &itemP);

        if (!envP->fault_occurred) {
            xmlrpc_array_append_item(envP, arrayP, itemP);

            xmlrpc_DECREF(itemP);
        }
    }
}
Пример #2
0
static void
processHeader(const char * const fieldName,
              char *       const fieldValue,
              TSession *   const sessionP,
              uint16_t *   const httpErrorCodeP) {
/*----------------------------------------------------------------------------
   We may modify *fieldValue, and we put pointers to *fieldValue and
   *fieldName into *sessionP.

   We must fix this some day.  *sessionP should point to individual
   malloc'ed strings.
-----------------------------------------------------------------------------*/
    *httpErrorCodeP = 0;  /* initial assumption */

    if (xmlrpc_streq(fieldName, "connection")) {
        if (xmlrpc_strcaseeq(fieldValue, "keep-alive"))
            sessionP->request_info.keepalive = TRUE;
        else
            sessionP->request_info.keepalive = FALSE;
    } else if (xmlrpc_streq(fieldName, "host"))
        parseHostPort(fieldValue, &sessionP->request_info.host,
                      &sessionP->request_info.port, httpErrorCodeP);
    else if (xmlrpc_streq(fieldName, "from"))
        sessionP->request_info.from = fieldValue;
    else if (xmlrpc_streq(fieldName, "user-agent"))
        sessionP->request_info.useragent = fieldValue;
    else if (xmlrpc_streq(fieldName, "referer"))
        sessionP->request_info.referer = fieldValue;
    else if (xmlrpc_streq(fieldName, "range")) {
        if (xmlrpc_strneq(fieldValue, "bytes=", 6)) {
            abyss_bool succeeded;
            succeeded = ListAddFromString(&sessionP->ranges, &fieldValue[6]);
            *httpErrorCodeP = succeeded ? 0 : 400;
        }
    } else if (xmlrpc_streq(fieldName, "cookies")) {
        abyss_bool succeeded;
        succeeded = ListAddFromString(&sessionP->cookies, fieldValue);
        *httpErrorCodeP = succeeded ? 0 : 400;
    }
}
Пример #3
0
static void
parseMethodNameElement(xmlrpc_env *  const envP,
                       xml_element * const nameElemP,
                       const char ** const methodNameP) {
    
    XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(nameElemP), "methodName"));

    if (xml_element_children_size(nameElemP) > 0)
        setParseFault(envP, "A <methodName> element should not have "
                      "children.  This one has %u of them.",
                      xml_element_children_size(nameElemP));
    else {
        const char * const cdata = xml_element_cdata(nameElemP);

        xmlrpc_validate_utf8(envP, cdata, strlen(cdata));

        if (!envP->fault_occurred) {
            *methodNameP = strdup(cdata);
            if (*methodNameP == NULL)
                xmlrpc_faultf(envP,
                              "Could not allocate memory for method name");
        }
    }
}            
Пример #4
0
static void
signatureListCreate(xmlrpc_env *            const envP,
                    const char *            const sigListString,
                    xmlrpc_signatureList ** const signatureListPP) {

    xmlrpc_signatureList * signatureListP;

    XMLRPC_ASSERT_ENV_OK(envP);

    MALLOCVAR(signatureListP);

    if (signatureListP == NULL)
        xmlrpc_faultf(envP, "Could not allocate memory for signature list");
    else {
        signatureListP->firstSignatureP = NULL;

        if (sigListString == NULL || xmlrpc_streq(sigListString, "?")) {
            /* No signatures -- leave the list empty */
        } else {
            listSignatures(envP, sigListString,
                           &signatureListP->firstSignatureP);

            if (!envP->fault_occurred) {
                if (!signatureListP->firstSignatureP)
                    xmlrpc_faultf(envP, "Signature string is empty.");

                if (envP->fault_occurred)
                    destroySignatures(signatureListP->firstSignatureP);
            }
        }
        if (envP->fault_occurred)
            free(signatureListP);

        *signatureListPP = signatureListP;
    }
}
Пример #5
0
static void
sendDirectoryDocument(TList *      const listP,
                      abyss_bool   const ascending,
                      uint16_t     const sort,
                      abyss_bool   const text,
                      const char * const uri,
                      MIMEType *   const mimeTypeP,
                      TSession *   const sessionP,
                      char *       const z) {

    char *p,z1[26],z2[20],z3[9],u;
    const char * z4;
    int16_t i;
    uint32_t k;

    if (text) {
        sprintf(z, "Index of %s" CRLF, uri);
        i = strlen(z)-2;
        p = z + i + 2;

        while (i > 0) {
            *(p++) = '-';
            --i;
        }

        *p = '\0';
        strcat(z, CRLF CRLF
               "Name                      Size      "
               "Date-Time             Type" CRLF
               "------------------------------------"
               "--------------------------------------------"CRLF);
    } else {
        sprintf(z, "<HTML><HEAD><TITLE>Index of %s</TITLE></HEAD><BODY>"
                "<H1>Index of %s</H1><PRE>",
                uri, uri);
        strcat(z, "Name                      Size      "
               "Date-Time             Type<HR WIDTH=100%>"CRLF);
    }

    HTTPWriteBodyChunk(sessionP, z, strlen(z));

    /* Sort the files */
    qsort(listP->item, listP->size, sizeof(void *),
          (TQSortProc)(sort == 1 ? cmpfilenames : cmpfiledates));
    
    /* Write the listing */
    if (ascending)
        i = 0;
    else
        i = listP->size - 1;

    while ((i < listP->size) && (i >= 0)) {
        TFileInfo * fi;
        struct tm ftm;

        fi = listP->item[i];

        if (ascending)
            ++i;
        else
            --i;
            
        strcpy(z, fi->name);

        k = strlen(z);

        if (fi->attrib & A_SUBDIR) {
            z[k++] = '/';
            z[k] = '\0';
        }

        if (k > 24) {
            z[10] = '\0';
            strcpy(z1, z);
            strcat(z1, "...");
            strcat(z1, z + k - 11);
            k = 24;
            p = z1 + 24;
        } else {
            strcpy(z1, z);
            
            ++k;
            p = z1 + k;
            while (k < 25)
                z1[k++] = ' ';
            
            z1[25] = '\0';
        }

        ftm = *gmtime(&fi->time_write);
        sprintf(z2, "%02u/%02u/%04u %02u:%02u:%02u",ftm.tm_mday,ftm.tm_mon+1,
                ftm.tm_year+1900,ftm.tm_hour,ftm.tm_min,ftm.tm_sec);

        if (fi->attrib & A_SUBDIR) {
            strcpy(z3, "   --  ");
            z4 = "Directory";
        } else {
            if (fi->size < 9999)
                u = 'b';
            else {
                fi->size /= 1024;
                if (fi->size < 9999)
                    u = 'K';
                else {
                    fi->size /= 1024;
                    if (fi->size < 9999)
                        u = 'M';
                    else
                        u = 'G';
                }
            }
                
            sprintf(z3, "%5llu %c", fi->size, u);
            
            if (xmlrpc_streq(fi->name, ".."))
                z4 = "";
            else
                z4 = MIMETypeFromFileName2(mimeTypeP, fi->name);

            if (!z4)
                z4 = "Unknown";
        }

        if (text)
            sprintf(z, "%s%s %s    %s   %s"CRLF, z1, p, z3, z2, z4);
        else
            sprintf(z, "<A HREF=\"%s%s\">%s</A>%s %s    %s   %s"CRLF,
                    fi->name, fi->attrib & A_SUBDIR ? "/" : "",
                    z1, p, z3, z2, z4);

        HTTPWriteBodyChunk(sessionP, z, strlen(z));
    }
        
    /* Write the tail of the file */
    if (text)
        strcpy(z, SERVER_PLAIN_INFO);
    else
        strcpy(z, "</PRE>" SERVER_HTML_INFO "</BODY></HTML>" CRLF CRLF);
    
    HTTPWriteBodyChunk(sessionP, z, strlen(z));
}
Пример #6
0
static void
test_value_datetime_varytime(const char * const datestring,
                             time_t       const datetime,
                             unsigned int const usec) {

    xmlrpc_value * v;
    xmlrpc_env env;
    const char * readBackString;
    time_t readBackDt;
    unsigned int readBackUsec;
    const char * datestringSec;
#if XMLRPC_HAVE_TIMEVAL
    struct timeval const dtTimeval = makeTv(datetime, usec);
    struct timeval readBackTv;
#endif
#if XMLRPC_HAVE_TIMESPEC
    struct timespec const dtTimespec = makeTs(datetime, usec);
    struct timespec readBackTs;
#endif
    const char * const dt8601 = make8601(datetime, usec);
    const char * readBack8601;

    datestringSec = truncateFracSec(datestring);

    xmlrpc_env_init(&env);

    /* Test xmlrpc_datetime_new_str and time read functions*/
    v = xmlrpc_datetime_new_str(&env, datestring);
    TEST_NO_FAULT(&env);
    TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v));

    xmlrpc_read_datetime_sec(&env, v, &readBackDt);
    TEST_NO_FAULT(&env);
    TEST(readBackDt == datetime);

    xmlrpc_read_datetime_usec(&env, v, &readBackDt, &readBackUsec);
    TEST_NO_FAULT(&env);
    TEST(readBackDt == datetime);
    TEST(readBackUsec == usec);

#if XMLRPC_HAVE_TIMEVAL
    xmlrpc_read_datetime_timeval(&env, v, &readBackTv);
    TEST_NO_FAULT(&env);
    TEST(tvIsEqual(dtTimeval, readBackTv));
#endif

#if XMLRPC_HAVE_TIMESPEC
    xmlrpc_read_datetime_timespec(&env, v, &readBackTs);
    TEST_NO_FAULT(&env);
    TEST(tsIsEqual(dtTimespec, readBackTs));
#endif

    xmlrpc_read_datetime_8601(&env, v, &readBack8601);
    TEST_NO_FAULT(&env);
    TEST(xmlrpc_streq(dt8601, readBack8601));
    strfree(readBack8601);

    xmlrpc_DECREF(v);

    /* Test xmlrpc_datetime_new_sec */
    v = xmlrpc_datetime_new_sec(&env, datetime);
    TEST_NO_FAULT(&env);
    TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v));

    xmlrpc_read_datetime_str(&env, v, &readBackString);
    TEST_NO_FAULT(&env);
    TEST(streq(readBackString, datestringSec));
    strfree(readBackString);

    xmlrpc_DECREF(v);

    /* Test xmlrpc_datetime_new_usec */
    v = xmlrpc_datetime_new_usec(&env, datetime, usec);
    TEST_NO_FAULT(&env);
    TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v));

    xmlrpc_read_datetime_str(&env, v, &readBackString);
    TEST_NO_FAULT(&env);
    TEST(streq(readBackString, datestring));
    strfree(readBackString);

    xmlrpc_DECREF(v);

#if XMLRPC_HAVE_TIMEVAL
    /* Test xmlrpc_datetime_new_timeval */
    v = xmlrpc_datetime_new_timeval(&env, dtTimeval);
    TEST_NO_FAULT(&env);
    TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v));

    xmlrpc_read_datetime_str(&env, v, &readBackString);
    TEST_NO_FAULT(&env);
    TEST(streq(readBackString, datestring));
    strfree(readBackString);

    xmlrpc_DECREF(v);
#endif

#if XMLRPC_HAVE_TIMESPEC
    /* Test xmlrpc_datetime_new_timespec */
    v = xmlrpc_datetime_new_timespec(&env, dtTimespec);
    TEST_NO_FAULT(&env);
    TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v));

    xmlrpc_read_datetime_str(&env, v, &readBackString);
    TEST_NO_FAULT(&env);
    TEST(streq(readBackString, datestring));
    strfree(readBackString);

    xmlrpc_DECREF(v);
#endif

    xmlrpc_env_clean(&env);
    strfree(datestringSec);
}
Пример #7
0
abyss_bool
RequestAuth(TSession *   const sessionP,
            const char * const credential,
            const char * const user,
            const char * const pass) {
/*----------------------------------------------------------------------------
   Authenticate requester, in a very simplistic fashion.

   If the request executing on session *sessionP specifies basic
   authentication (via Authorization header) with username 'user', password
   'pass', then return true.  Else, return false and set up an authorization
   failure response (HTTP response status 401) that says user must supply an
   identity in the 'credential' domain.

   When we return true, we also set the username in the request info for the
   session to 'user' so that a future SessionGetRequestInfo can get it.
-----------------------------------------------------------------------------*/
    bool authorized;
    const char * authValue;

    authValue = RequestHeaderValue(sessionP, "authorization");
    if (authValue) {
        char * const valueBuffer = malloc(strlen(authValue));
            /* A buffer we can mangle as we parse the authorization: value */

        if (!authValue)
            /* Should return error, but we have no way to do that */
            authorized = false;
        else {
            const char * authType;
            char * authHdrPtr;

            strcpy(valueBuffer, authValue);
            authHdrPtr = &valueBuffer[0];

            NextToken((const char **)&authHdrPtr);
            GetTokenConst(&authHdrPtr, &authType);
            if (authType) {
                if (xmlrpc_strcaseeq(authType, "basic")) {
                    const char * userPass;
                    char userPassEncoded[80];

                    NextToken((const char **)&authHdrPtr);

                    xmlrpc_asprintf(&userPass, "%s:%s", user, pass);
                    xmlrpc_base64Encode(userPass, userPassEncoded);
                    xmlrpc_strfree(userPass);

                    if (xmlrpc_streq(authHdrPtr, userPassEncoded)) {
                        sessionP->requestInfo.user = xmlrpc_strdupsol(user);
                        authorized = true;
                    } else
                        authorized = false;
                } else
                    authorized = false;
            } else
                authorized = false;

            free(valueBuffer);
        }
    } else
        authorized = false;

    if (!authorized) {
        const char * hdrValue;
        xmlrpc_asprintf(&hdrValue, "Basic realm=\"%s\"", credential);
        ResponseAddField(sessionP, "WWW-Authenticate", hdrValue);

        xmlrpc_strfree(hdrValue);

        ResponseStatus(sessionP, 401);
    }
    return authorized;
}
Пример #8
0
static void
test_value_string_no_null(void) {

    /* Test strings (without '\0' bytes). */

    xmlrpc_value * v;
    xmlrpc_env env;
    const char * str;
    size_t len;

    xmlrpc_env_init(&env);

    TEST(streq(xmlrpc_type_name(XMLRPC_TYPE_STRING), "STRING"));

    {
        const char * const simpleAsciiString = "foo";
        v = xmlrpc_string_new(&env, simpleAsciiString);
        TEST_NO_FAULT(&env);
        TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_STRING);
        xmlrpc_read_string(&env, v, &str);
        TEST_NO_FAULT(&env);
        TEST(streq(str, simpleAsciiString));
        xmlrpc_DECREF(v);
        strfree(str);
    }        
    {
        const char * const utf8String = "KOŚĆ";
        v = xmlrpc_string_new(&env, utf8String);
        TEST_NO_FAULT(&env);
        TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_STRING);
        xmlrpc_read_string(&env, v, &str);
        TEST_NO_FAULT(&env);
        TEST(streq(str, utf8String));
        xmlrpc_DECREF(v);
        strfree(str);
    }
    v = xmlrpc_string_new_f(&env, "String %s, number %d", "xyz", 7);
    TEST_NO_FAULT(&env);
    TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_STRING);
    xmlrpc_read_string(&env, v, &str);
    TEST_NO_FAULT(&env);
    TEST(streq(str, "String xyz, number 7"));
    xmlrpc_DECREF(v);
    strfree(str);

    v = test_string_new_va(&env, "String %s, number %d", "xyz", 7);
    TEST_NO_FAULT(&env);
    TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_STRING);
    xmlrpc_read_string(&env, v, &str);
    TEST_NO_FAULT(&env);
    TEST(streq(str, "String xyz, number 7"));
    xmlrpc_DECREF(v);
    strfree(str);

    v = xmlrpc_build_value(&env, "s", "foo");

    TEST_NO_FAULT(&env);
    TEST(v != NULL);
    TEST(XMLRPC_TYPE_STRING == xmlrpc_value_type(v));

    xmlrpc_decompose_value(&env, v, "s", &str);
    TEST_NO_FAULT(&env);
    TEST(streq(str, "foo"));
    strfree(str);

    xmlrpc_decompose_value(&env, v, "s#", &str, &len);
    TEST_NO_FAULT(&env);
    TEST(len == strlen("foo"));
    TEST(xmlrpc_streq(str, "foo"));
    TEST(strlen(str) == strlen("foo"));
    strfree(str);

    xmlrpc_DECREF(v);

    xmlrpc_env_clean(&env);
}
Пример #9
0
static void
parseRequestLine(char *           const requestLine,
                 TMethod *        const httpMethodP,
                 httpVersion *    const httpVersionP,
                 const char **    const hostP,
                 unsigned short * const portP,
                 const char **    const pathP,
                 const char **    const queryP,
                 bool *           const moreLinesP,
                 uint16_t *       const httpErrorCodeP) {
/*----------------------------------------------------------------------------
   Modifies *requestLine!
-----------------------------------------------------------------------------*/
    const char * httpMethodName;
    char * p;

    p = requestLine;

    /* Jump over spaces */
    NextToken((const char **)&p);

    httpMethodName = GetToken(&p);
    if (!httpMethodName)
        *httpErrorCodeP = 400;  /* Bad Request */
    else {
        char * requestUri;

        if (xmlrpc_streq(httpMethodName, "GET"))
            *httpMethodP = m_get;
        else if (xmlrpc_streq(httpMethodName, "PUT"))
            *httpMethodP = m_put;
        else if (xmlrpc_streq(httpMethodName, "OPTIONS"))
            *httpMethodP = m_options;
        else if (xmlrpc_streq(httpMethodName, "DELETE"))
            *httpMethodP = m_delete;
        else if (xmlrpc_streq(httpMethodName, "POST"))
            *httpMethodP = m_post;
        else if (xmlrpc_streq(httpMethodName, "TRACE"))
            *httpMethodP = m_trace;
        else if (xmlrpc_streq(httpMethodName, "HEAD"))
            *httpMethodP = m_head;
        else
            *httpMethodP = m_unknown;
        
        /* URI and Query Decoding */
        NextToken((const char **)&p);

        requestUri = GetToken(&p);
        if (!requestUri)
            *httpErrorCodeP = 400;  /* Bad Request */
        else {
            const char * host;
            unsigned short port;
            const char * path;
            const char * query;

            parseRequestUri(requestUri, &host, &port, &path, &query,
                            httpErrorCodeP);

            if (!*httpErrorCodeP) {
                const char * httpVersion;

                NextToken((const char **)&p);
        
                /* HTTP Version Decoding */
                
                httpVersion = GetToken(&p);
                if (httpVersion) {
                    uint32_t vmin, vmaj;
                    if (sscanf(httpVersion, "HTTP/%d.%d", &vmaj, &vmin) != 2)
                        *httpErrorCodeP = 400;  /* Bad Request */
                    else {
                        httpVersionP->major = vmaj;
                        httpVersionP->minor = vmin;
                        *httpErrorCodeP = 0;  /* no error */
                    }
                    *moreLinesP = TRUE;
                } else {
                    /* There is no HTTP version, so this is a single
                       line request.
                    */
                    *httpErrorCodeP = 0;  /* no error */
                    *moreLinesP = FALSE;
                }
                if (*httpErrorCodeP) {
                    xmlrpc_strfree(host);
                    xmlrpc_strfree(path);
                    xmlrpc_strfree(query);
                }
                *hostP = host;
                *portP = port;
                *pathP = path;
                *queryP = query;
            }
        }
    }
}
Пример #10
0
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 * responseEltP;

    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",
            (unsigned)xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID),
            (unsigned)xmlDataLen);
    else {
        xmlrpc_env env;
        xmlrpc_env_init(&env);

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

        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(responseEltP),
                             "methodResponse")) {
                parseMethodResponseElt(envP, responseEltP,
                                       resultPP, faultCodeP, faultStringP);
            } else
                setParseFault(envP, "XML-RPC response must consist of a "
                              "<methodResponse> element.  "
                              "This has a <%s> instead.",
                              xml_element_name(responseEltP));
            
            xml_element_free(responseEltP);
        }
        xmlrpc_env_clean(&env);
    }
}