|
|
|
@ -1017,82 +1017,9 @@ static void HtpRequestBodyReassemble(SCHtpTxUserData *htud,
|
|
|
|
|
*chunks_buffer_len = buf_len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Function callback to append chunks for Requests
|
|
|
|
|
* \param d pointer to the htp_tx_data_t structure (a chunk from htp lib)
|
|
|
|
|
* \retval int HOOK_OK if all goes well
|
|
|
|
|
*/
|
|
|
|
|
int HTPCallbackRequestBodyData(htp_tx_data_t *d)
|
|
|
|
|
int HtpRequestBodyHandleMultipart(HtpState *hstate, SCHtpTxUserData *htud,
|
|
|
|
|
uint8_t *chunks_buffer, uint32_t chunks_buffer_len)
|
|
|
|
|
{
|
|
|
|
|
SCEnter();
|
|
|
|
|
|
|
|
|
|
uint8_t *expected_boundary = NULL;
|
|
|
|
|
uint8_t *expected_boundary_end = NULL;
|
|
|
|
|
uint8_t *chunks_buffer = NULL;
|
|
|
|
|
uint32_t chunks_buffer_len = 0;
|
|
|
|
|
|
|
|
|
|
HtpState *hstate = (HtpState *)d->tx->connp->user_data;
|
|
|
|
|
if (hstate == NULL) {
|
|
|
|
|
SCReturnInt(HOOK_ERROR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCLogDebug("New response body data available at %p -> %p -> %p, bodylen "
|
|
|
|
|
"%"PRIu32"", hstate, d, d->data, (uint32_t)d->len);
|
|
|
|
|
|
|
|
|
|
SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(d->tx);
|
|
|
|
|
if (htud == NULL) {
|
|
|
|
|
htud = SCMalloc(sizeof(SCHtpTxUserData));
|
|
|
|
|
if (htud == NULL) {
|
|
|
|
|
SCReturnInt(HOOK_OK);
|
|
|
|
|
}
|
|
|
|
|
memset(htud, 0, sizeof(SCHtpTxUserData));
|
|
|
|
|
htud->body.operation = HTP_BODY_NONE;
|
|
|
|
|
|
|
|
|
|
HtpRequestBodySetupMultipart(d, htud);
|
|
|
|
|
|
|
|
|
|
/* Set the user data for handling body chunks on this transaction */
|
|
|
|
|
htp_tx_set_user_data(d->tx, htud);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
htud->body.operation = HTP_BODY_REQUEST;
|
|
|
|
|
|
|
|
|
|
SCLogDebug("htud->content_len_so_far %"PRIu64, htud->content_len_so_far);
|
|
|
|
|
SCLogDebug("hstate->request_body_limit %u", hstate->request_body_limit);
|
|
|
|
|
|
|
|
|
|
/* within limits, add the body chunk to the state. */
|
|
|
|
|
if (hstate->request_body_limit == 0 || htud->content_len_so_far < hstate->request_body_limit)
|
|
|
|
|
{
|
|
|
|
|
uint32_t len = (uint32_t)d->len;
|
|
|
|
|
|
|
|
|
|
if (hstate->request_body_limit > 0 &&
|
|
|
|
|
(htud->content_len_so_far + len) > hstate->request_body_limit)
|
|
|
|
|
{
|
|
|
|
|
len = hstate->request_body_limit - htud->content_len_so_far;
|
|
|
|
|
BUG_ON(len > (uint32_t)d->len);
|
|
|
|
|
}
|
|
|
|
|
SCLogDebug("len %u", len);
|
|
|
|
|
|
|
|
|
|
int r = HtpBodyAppendChunk(htud, &htud->body, (uint8_t *)d->data, len);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
htud->flags |= HTP_BODY_COMPLETE;
|
|
|
|
|
} else if (hstate->request_body_limit > 0 &&
|
|
|
|
|
htud->content_len_so_far >= hstate->request_body_limit)
|
|
|
|
|
{
|
|
|
|
|
htud->flags |= HTP_BODY_COMPLETE;
|
|
|
|
|
} else if (htud->content_len_so_far == htud->content_len) {
|
|
|
|
|
htud->flags |= HTP_BODY_COMPLETE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* multi-part body handling starts here */
|
|
|
|
|
if (!(htud->flags & HTP_BOUNDARY_SET)) {
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HtpRequestBodyReassemble(htud, &chunks_buffer, &chunks_buffer_len);
|
|
|
|
|
if (chunks_buffer == NULL) {
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef PRINT
|
|
|
|
|
printf("CHUNK START: \n");
|
|
|
|
|
PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
|
|
|
|
@ -1265,22 +1192,159 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d)
|
|
|
|
|
(uint8_t *) "\r\n\r\n", 4);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
/* see if we can get rid of htp body chunks */
|
|
|
|
|
HtpBodyPrune(htud);
|
|
|
|
|
|
|
|
|
|
if (expected_boundary != NULL) {
|
|
|
|
|
SCFree(expected_boundary);
|
|
|
|
|
}
|
|
|
|
|
if (expected_boundary_end != NULL) {
|
|
|
|
|
SCFree(expected_boundary_end);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \brief setup things for put request
|
|
|
|
|
* \todo really needed? */
|
|
|
|
|
int HtpRequestBodySetupPUT(htp_tx_data_t *d, SCHtpTxUserData *htud) {
|
|
|
|
|
// if (d->tx->parsed_uri == NULL || d->tx->parsed_uri->path == NULL) {
|
|
|
|
|
// return -1;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
/* filename is d->tx->parsed_uri->path */
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int HtpRequestBodyHandlePUT(HtpState *hstate, SCHtpTxUserData *htud,
|
|
|
|
|
htp_tx_t *tx, uint8_t *data, uint32_t data_len)
|
|
|
|
|
{
|
|
|
|
|
/* see if we need to open the file */
|
|
|
|
|
if (!(htud->flags & HTP_FILENAME_SET))
|
|
|
|
|
{
|
|
|
|
|
uint8_t *filename = NULL;
|
|
|
|
|
uint32_t filename_len = 0;
|
|
|
|
|
|
|
|
|
|
/* get the name */
|
|
|
|
|
if (tx->parsed_uri != NULL && tx->parsed_uri->path != NULL) {
|
|
|
|
|
filename = (uint8_t *)bstr_ptr(tx->parsed_uri->path);
|
|
|
|
|
filename_len = bstr_len(tx->parsed_uri->path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (HTPFileOpen(hstate->f, filename, filename_len,
|
|
|
|
|
data, data_len) == -1) {
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
htud->flags |= HTP_FILENAME_SET;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* otherwise, just store the data */
|
|
|
|
|
|
|
|
|
|
if (HTPFileStoreChunk(hstate->f, data, data_len) == -1) {
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
end:
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Function callback to append chunks for Requests
|
|
|
|
|
* \param d pointer to the htp_tx_data_t structure (a chunk from htp lib)
|
|
|
|
|
* \retval int HOOK_OK if all goes well
|
|
|
|
|
*/
|
|
|
|
|
int HTPCallbackRequestBodyData(htp_tx_data_t *d)
|
|
|
|
|
{
|
|
|
|
|
SCEnter();
|
|
|
|
|
|
|
|
|
|
HtpState *hstate = (HtpState *)d->tx->connp->user_data;
|
|
|
|
|
if (hstate == NULL) {
|
|
|
|
|
SCReturnInt(HOOK_ERROR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCLogDebug("New response body data available at %p -> %p -> %p, bodylen "
|
|
|
|
|
"%"PRIu32"", hstate, d, d->data, (uint32_t)d->len);
|
|
|
|
|
|
|
|
|
|
SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(d->tx);
|
|
|
|
|
if (htud == NULL) {
|
|
|
|
|
htud = SCMalloc(sizeof(SCHtpTxUserData));
|
|
|
|
|
if (htud == NULL) {
|
|
|
|
|
SCReturnInt(HOOK_OK);
|
|
|
|
|
}
|
|
|
|
|
memset(htud, 0, sizeof(SCHtpTxUserData));
|
|
|
|
|
htud->body.operation = HTP_BODY_NONE;
|
|
|
|
|
|
|
|
|
|
if (d->tx->request_method_number == M_POST) {
|
|
|
|
|
if (HtpRequestBodySetupMultipart(d, htud) == 0) {
|
|
|
|
|
htud->body.operation = HTP_BODY_REQUEST_MULTIPART;
|
|
|
|
|
}
|
|
|
|
|
} else if (d->tx->request_method_number == M_PUT) {
|
|
|
|
|
if (HtpRequestBodySetupPUT(d, htud) == 0) {
|
|
|
|
|
htud->body.operation = HTP_BODY_REQUEST_PUT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set the user data for handling body chunks on this transaction */
|
|
|
|
|
htp_tx_set_user_data(d->tx, htud);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCLogDebug("htud->content_len_so_far %"PRIu64, htud->content_len_so_far);
|
|
|
|
|
SCLogDebug("hstate->request_body_limit %u", hstate->request_body_limit);
|
|
|
|
|
|
|
|
|
|
/* within limits, add the body chunk to the state. */
|
|
|
|
|
if (hstate->request_body_limit == 0 || htud->content_len_so_far < hstate->request_body_limit)
|
|
|
|
|
{
|
|
|
|
|
uint32_t len = (uint32_t)d->len;
|
|
|
|
|
|
|
|
|
|
if (hstate->request_body_limit > 0 &&
|
|
|
|
|
(htud->content_len_so_far + len) > hstate->request_body_limit)
|
|
|
|
|
{
|
|
|
|
|
len = hstate->request_body_limit - htud->content_len_so_far;
|
|
|
|
|
BUG_ON(len > (uint32_t)d->len);
|
|
|
|
|
}
|
|
|
|
|
SCLogDebug("len %u", len);
|
|
|
|
|
|
|
|
|
|
int r = HtpBodyAppendChunk(htud, &htud->body, (uint8_t *)d->data, len);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
htud->flags |= HTP_BODY_COMPLETE;
|
|
|
|
|
} else if (hstate->request_body_limit > 0 &&
|
|
|
|
|
htud->content_len_so_far >= hstate->request_body_limit)
|
|
|
|
|
{
|
|
|
|
|
htud->flags |= HTP_BODY_COMPLETE;
|
|
|
|
|
} else if (htud->content_len_so_far == htud->content_len) {
|
|
|
|
|
htud->flags |= HTP_BODY_COMPLETE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t *chunks_buffer = NULL;
|
|
|
|
|
uint32_t chunks_buffer_len = 0;
|
|
|
|
|
|
|
|
|
|
if (htud->body.operation == HTP_BODY_REQUEST_MULTIPART) {
|
|
|
|
|
/* multi-part body handling starts here */
|
|
|
|
|
if (!(htud->flags & HTP_BOUNDARY_SET)) {
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HtpRequestBodyReassemble(htud, &chunks_buffer, &chunks_buffer_len);
|
|
|
|
|
if (chunks_buffer == NULL) {
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HtpRequestBodyHandleMultipart(hstate, htud, chunks_buffer, chunks_buffer_len);
|
|
|
|
|
|
|
|
|
|
if (chunks_buffer != NULL) {
|
|
|
|
|
SCFree(chunks_buffer);
|
|
|
|
|
}
|
|
|
|
|
} else if (htud->body.operation == HTP_BODY_REQUEST_PUT) {
|
|
|
|
|
HtpRequestBodyHandlePUT(hstate, htud, d->tx, (uint8_t *)d->data, (uint32_t)d->len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
/* see if we can get rid of htp body chunks */
|
|
|
|
|
HtpBodyPrune(htud);
|
|
|
|
|
|
|
|
|
|
/* set the new chunk flag */
|
|
|
|
|
hstate->flags |= HTP_FLAG_NEW_BODY_SET;
|
|
|
|
@ -1341,6 +1405,17 @@ static int HTPCallbackRequest(htp_connp_t *connp) {
|
|
|
|
|
|
|
|
|
|
SCLogDebug("HTTP request completed");
|
|
|
|
|
|
|
|
|
|
if (connp->in_tx != NULL) {
|
|
|
|
|
SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(connp->in_tx);
|
|
|
|
|
if (htud != NULL) {
|
|
|
|
|
if (htud->flags & HTP_FILENAME_SET) {
|
|
|
|
|
SCLogDebug("closing file that was being stored");
|
|
|
|
|
(void)HTPFileClose(hstate->f, NULL, 0, 0);
|
|
|
|
|
htud->flags &= ~HTP_FILENAME_SET;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCReturnInt(HOOK_OK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|