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); } } }
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; } }
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"); } } }
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; } }
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)); }
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); }
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; }
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); }
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; } } } }
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); } }