Rolled back to 0.2.x branch renamed htp to libhtp

remotes/origin/master-1.0.x
William Metcalf 16 years ago committed by Victor Julien
parent dc11247511
commit 0fe4373b67

@ -6,7 +6,7 @@ EXTRA_DIST = ChangeLog COPYING LICENSE suricata.yaml \
doc/AUTHORS doc/GITGUIDE doc/INSTALL doc/NEWS \
doc/README doc/TODO
if BUILD_LIBHTP
HTP_DIR = htp
HTP_DIR = libhtp
endif
SUBDIRS = $(HTP_DIR) src

@ -5,6 +5,6 @@ libtoolize --force --automake --copy
autoheader
automake --add-missing --copy
autoconf
cd htp/
cd libhtp/
autoreconf -i --force
cd ..

@ -589,18 +589,18 @@ AC_CHECK_HEADER(pcap.h,,[AC_ERROR(pcap.h not found ...)])
#we did not specify non-bundled-htp so use the built-in.
else
if test -d "htp"; then
if test -d "libhtp"; then
echo "Going to try and build the bundled htp in htp/"
else
echo
echo " ERROR! htp/ dir not found in source"
echo " ERROR! libhtp/ dir not found in source"
echo
exit 1
fi
fi
#even if we are using an installed htp lib we still need to gen Makefiles inside of htp
AC_CONFIG_SUBDIRS([htp])
AC_CONFIG_SUBDIRS([libhtp])
AM_CONDITIONAL([BUILD_LIBHTP], [test "$enable_non_bundled_htp" = "no"])
# enable CUDA output
@ -645,5 +645,5 @@ AC_SUBST(CFLAGS)
AC_SUBST(LDFLAGS)
AC_SUBST(CPPFLAGS)
AC_CONFIG_FILES([htp/Makefile htp/htp/Makefile Makefile src/Makefile])
AC_CONFIG_FILES([libhtp/Makefile libhtp/htp/Makefile Makefile src/Makefile])
AC_OUTPUT

@ -1,14 +0,0 @@
h_sources = bstr.h bstr_builder.h dslib.h hooks.h htp.h utf8_decoder.h htp_decompressors.h htp_urlencoded.h htp_multipart.h
c_sources = bstr.c bstr_builder.c hooks.c htp_config.c htp_connection_parser.c htp_request_apache_2_2.c htp_request_generic.c htp_request_parsers.c htp_response_generic.c htp_util.c dslib.c htp.c htp_connection.c htp_parsers.c htp_request.c htp_response.c htp_transaction.c utf8_decoder.c htp_decompressors.c htp_urlencoded.c htp_multipart.c
library_includedir = $(includedir)/$(GENERIC_LIBRARY_NAME)
library_include_HEADERS = $(h_sources)
INCLUDES = -I$(top_srcdir)
AM_CFLAGS = -D_GNU_SOURCE -g -O2 -Wall -Wextra -std=gnu99 -pedantic
lib_LTLIBRARIES= libhtp.la
libhtp_la_SOURCES= $(h_sources) $(c_sources)
libhtp_la_LDFLAGS= -version-info $(GENERIC_LIBRARY_VERSION) -release $(GENERIC_RELEASE)

@ -1,161 +0,0 @@
/*
* LibHTP (http://www.libhtp.org)
* Copyright 2009,2010 Ivan Ristic <ivanr@webkreator.com>
*
* LibHTP is an open source product, released under terms of the General Public Licence
* version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text
* of the license.
*
* In addition, there is a special exception that allows LibHTP to be freely
* used with any OSI-approved open source licence. Please refer to the file
* LIBHTP_LICENSING_EXCEPTION for the full text of the exception.
*
*/
#include "bstr.h"
#include "bstr_builder.h"
#include "dslib.h"
/**
* Returns the size (the number of pieces) currently in a string builder.
*
* @param bb
* @return size
*/
size_t bstr_builder_size(bstr_builder_t *bb) {
return list_size(bb->pieces);
}
/**
* Clears this string builder, destroying all existing pieces. You may
* want to clear a builder once you've either read all the pieces and
* done something with them, or after you've converted the builder into
* a single string.
*
* @param bb
*/
void bstr_builder_clear(bstr_builder_t *bb) {
// Do nothing if the list is empty
if (list_size(bb->pieces) == 0) return;
// Destroy any pieces we might have
bstr *b = NULL;
list_iterator_reset(bb->pieces);
while ((b = list_iterator_next(bb->pieces)) != NULL) {
bstr_free(b);
}
list_destroy(bb->pieces);
bb->pieces = list_array_create(BSTR_BUILDER_DEFAULT_SIZE);
// TODO What should we do on allocation failure?
}
/**
* Creates a new string builder.
*
* @return New string builder
*/
bstr_builder_t * bstr_builder_create() {
bstr_builder_t *bb = calloc(1, sizeof(bstr_builder_t));
if (bb == NULL) return NULL;
bb->pieces = list_array_create(BSTR_BUILDER_DEFAULT_SIZE);
if (bb->pieces == NULL) {
free(bb);
return NULL;
}
return bb;
}
/**
* Destroys an existing string builder, also destroying all
* the pieces stored within.
*
* @param bb
*/
void bstr_builder_destroy(bstr_builder_t *bb) {
if (bb == NULL) return;
// Destroy any pieces we might have
bstr *b = NULL;
list_iterator_reset(bb->pieces);
while ((b = list_iterator_next(bb->pieces)) != NULL) {
bstr_free(b);
}
list_destroy(bb->pieces);
free(bb);
}
/**
* Adds one new string to the builder.
*
* @param bb
* @param b
* @return Success indication
*/
int bstr_builder_append(bstr_builder_t *bb, bstr *b) {
return list_push(bb->pieces, b);
}
/**
* Adds one new piece, defined with the supplied pointer and
* length, to the builder.
*
* @param bb
* @param data
* @param len
* @return Success indication
*/
int bstr_builder_append_mem(bstr_builder_t *bb, char *data, size_t len) {
bstr *b = bstr_memdup(data, len);
if (b == NULL) return -1; // TODO Is the return code correct?
return list_push(bb->pieces, b);
}
/**
* Adds one new piece, in the form of a NUL-terminated string, to
* the builder.
*
* @param bb
* @param cstr
* @return Success indication
*/
int bstr_builder_append_cstr(bstr_builder_t *bb, char *cstr) {
bstr *b = bstr_cstrdup(cstr);
if (b == NULL) return -1; // TODO Is the return code correct?
return list_push(bb->pieces, b);
}
/**
* Creates a single string out of all the pieces held in a
* string builder. This method will not destroy any of the pieces.
*
* @param bb
* @return New string
*/
bstr * bstr_builder_to_str(bstr_builder_t *bb) {
bstr *b = NULL;
size_t len = 0;
// Determine the size of the string
list_iterator_reset(bb->pieces);
while ((b = list_iterator_next(bb->pieces)) != NULL) {
len += bstr_len(b);
}
// Allocate string
bstr *bnew = bstr_alloc(len);
if (bnew == NULL) return NULL;
// Determine the size of the string
list_iterator_reset(bb->pieces);
while ((b = list_iterator_next(bb->pieces)) != NULL) {
bstr_add_str_noex(bnew, b);
}
return bnew;
}

@ -1,40 +0,0 @@
/*
* LibHTP (http://www.libhtp.org)
* Copyright 2009,2010 Ivan Ristic <ivanr@webkreator.com>
*
* LibHTP is an open source product, released under terms of the General Public Licence
* version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text
* of the license.
*
* In addition, there is a special exception that allows LibHTP to be freely
* used with any OSI-approved open source licence. Please refer to the file
* LIBHTP_LICENSING_EXCEPTION for the full text of the exception.
*
*/
#ifndef _BSTR_BUILDER_H
#define _BSTR_BUILDER_H
typedef struct bstr_builder_t bstr_builder_t;
#include "dslib.h"
struct bstr_builder_t {
list_t *pieces;
};
#define BSTR_BUILDER_DEFAULT_SIZE 16
bstr_builder_t * bstr_builder_create();
void bstr_builder_destroy(bstr_builder_t *bb);
size_t bstr_builder_size(bstr_builder_t *bb);
void bstr_builder_clear(bstr_builder_t *bb);
int bstr_builder_append(bstr_builder_t *bb, bstr *b);
int bstr_builder_append_mem(bstr_builder_t *bb, char *data, size_t len);
int bstr_builder_append_cstr(bstr_builder_t *bb, char *str);
bstr * bstr_builder_to_str(bstr_builder_t *bb);
#endif /* _BSTR_BUILDER_H */

@ -1,894 +0,0 @@
/*
* LibHTP (http://www.libhtp.org)
* Copyright 2009,2010 Ivan Ristic <ivanr@webkreator.com>
*
* LibHTP is an open source product, released under terms of the General Public Licence
* version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text
* of the license.
*
* In addition, there is a special exception that allows LibHTP to be freely
* used with any OSI-approved open source licence. Please refer to the file
* LIBHTP_LICENSING_EXCEPTION for the full text of the exception.
*
*/
#include "htp.h"
#include "htp_multipart.h"
#define PARAM_OTHER 0
#define PARAM_NAME 1
#define PARAM_FILENAME 2
/**
* Determines the type of a Content-Disposition parameter.
*
* @param data
* @param startpos
* @param pos
* @return PARAM_OTHER, PARAM_NAME or PARAM_FILENAME
*/
static int htp_mpartp_cd_param_type(unsigned char *data, size_t startpos, size_t pos) {
if ((pos - startpos) == 4) {
if (memcmp(data + startpos, "name", 4) == 0) return PARAM_NAME;
} else if ((pos - startpos) == 8) {
if (memcmp(data + startpos, "filename", 8) == 0) return PARAM_FILENAME;
}
return PARAM_OTHER;
}
/**
* Process part headers. In the current implementation, we only parse the
* Content-Disposition header if it is present.
*
* @param part
* @return Success indication
*/
int htp_mpart_part_process_headers(htp_mpart_part_t *part) {
// Find C-D header
htp_header_t *h = (htp_header_t *) table_getc(part->headers, "content-disposition");
if (h == NULL) {
// TODO Error message
return 0;
}
// fprint_raw_data(stderr, "C-D", (unsigned char *) bstr_ptr(h->value), bstr_len(h->value));
if (bstr_indexofc(h->value, "form-data") != 0) {
return -1;
}
// The parsing starts here
unsigned char *data = (unsigned char *) bstr_ptr(h->value);
size_t len = bstr_len(h->value);
size_t pos = 9; // Start after "form-data"
// Main parameter parsing loop (once per parameter)
while (pos < len) {
// Find semicolon and go over it
while ((pos < len) && ((data[pos] == '\t') || (data[pos] == ' '))) pos++;
if (pos == len) return -2;
// Semicolon
if (data[pos] != ';') return -3;
pos++;
// Go over the whitespace before parameter name
while ((pos < len) && ((data[pos] == '\t') || (data[pos] == ' '))) pos++;
if (pos == len) return -4;
// Found starting position (name)
size_t start = pos;
// Look for ending position
while ((pos < len) && (data[pos] != '\t') && (data[pos] != ' ') && (data[pos] != '=')) pos++;
if (pos == len) return -5;
// Ending position is in "pos" now
// Is it a parameter we are interested in?
int param_type = htp_mpartp_cd_param_type(data, start, pos);
// Ignore whitespace
while ((pos < len) && ((data[pos] == '\t') || (data[pos] == ' '))) pos++;
if (pos == len) return -6;
// Equals
if (data[pos] != '=') return -7;
pos++;
// Go over the whitespace before value
while ((pos < len) && ((data[pos] == '\t') || (data[pos] == ' '))) pos++;
if (pos == len) return -8;
// Found starting point (value)
start = pos;
// Quoting char indicator
int qchar = -1;
// Different handling for quoted and bare strings
if (data[start] == '"') {
// Quoted string
qchar = data[start];
start = ++pos;
// Find the end of the value
while ((pos < len) && (data[pos] != qchar)) {
if (data[pos] == '\\') {
// Ignore invalid quoting pairs
if (pos + 1 < len) return -9;
// Go over the quoted character
pos++;
}
pos++;
}
} else {
// Bare string
while ((pos < len) && (!htp_is_token(data[pos]))) pos++;
}
switch (param_type) {
case PARAM_NAME:
// TODO Unquote
part->name = bstr_memdup((char *)data + start, pos - start);
// fprint_raw_data(stderr, "NAME", (unsigned char *) bstr_ptr(part->name), bstr_len(part->name));
break;
case PARAM_FILENAME:
// TODO Unquote
part->filename = bstr_memdup((char *)data + start, pos - start);
// fprint_raw_data(stderr, "FILENAME", (unsigned char *) bstr_ptr(part->filename), bstr_len(part->filename));
break;
default:
// Ignore unknown parameter
// TODO Warn/log?
break;
}
// Skip over the quoting character
if (qchar != -1) {
pos++;
}
// Continue to parse the next parameter, if any
}
return 1;
}
/**
* Parses one part header.
*
* @param data
* @param len
* @param Success indication
*/
int htp_mpartp_parse_header(htp_mpart_part_t *part, unsigned char *data, size_t len) {
size_t name_start, name_end;
size_t value_start, value_end;
name_start = 0;
// Look for the colon
size_t colon_pos = 0;
while ((colon_pos < len) && (data[colon_pos] != ':')) colon_pos++;
if (colon_pos == len) {
// Missing colon
// TODO Error message
return -1;
}
if (colon_pos == 0) {
// Empty header name
// TODO Error message
}
name_end = colon_pos;
// Ignore LWS after field-name
size_t prev = name_end - 1;
while ((prev > name_start) && (htp_is_lws(data[prev]))) {
prev--;
name_end--;
// LWS after field name
// TODO Error message
}
// Value
value_start = colon_pos;
// Go over the colon
if (value_start < len) {
value_start++;
}
// Ignore LWS before field-content
while ((value_start < len) && (htp_is_lws(data[value_start]))) {
value_start++;
}
// Look for the end of field-content
value_end = value_start;
while (value_end < len) value_end++;
// Ignore LWS after field-content
prev = value_end - 1;
while ((prev > value_start) && (htp_is_lws(data[prev]))) {
prev--;
value_end--;
}
// Check that the header name is a token
size_t i = name_start;
while (i < name_end) {
if (!htp_is_token(data[i])) {
// Request field is not a token
// TODO Error message
break;
}
i++;
}
// Now extract the name and the value
htp_header_t *h = calloc(1, sizeof (htp_header_t));
if (h == NULL) return -1;
h->name = bstr_memdup((char *) data + name_start, name_end - name_start);
h->value = bstr_memdup((char *) data + value_start, value_end - value_start);
// Check if the header already exists
htp_header_t * h_existing = table_get(part->headers, h->name);
if (h_existing != NULL) {
// Add to existing header
h_existing->value = bstr_expand(h_existing->value, bstr_len(h_existing->value)
+ 2 + bstr_len(h->value));
bstr_add_mem_noex(h_existing->value, ", ", 2);
bstr_add_str_noex(h_existing->value, h->value);
// The header is no longer needed
bstr_free(h->name);
bstr_free(h->value);
free(h);
// Keep track of same-name headers
h_existing->flags |= HTP_FIELD_REPEATED;
} else {
// Add as a new header
table_add(part->headers, h->name, h);
}
return 1;
}
/**
* Creates new multipart part.
*
* @param mpartp
*/
htp_mpart_part_t *htp_mpart_part_create(htp_mpartp_t *mpartp) {
htp_mpart_part_t * part = calloc(1, sizeof (htp_mpart_part_t));
if (part == NULL) return NULL;
part->headers = table_create(32);
if (part->headers == NULL) {
free(part);
return NULL;
}
part->mpartp = mpartp;
part->mpartp->pieces_form_line = 0;
bstr_builder_clear(mpartp->part_pieces);
return part;
}
/**
* Destroys multipart part.
*
* @param part
*/
void htp_mpart_part_destroy(htp_mpart_part_t *part) {
if (part == NULL) return;
bstr_free(part->name);
bstr_free(part->filename);
bstr_free(part->value);
if (part->headers != NULL) {
// Destroy request_headers
htp_header_t *h = NULL;
table_iterator_reset(part->headers);
while (table_iterator_next(part->headers, (void **) & h) != NULL) {
bstr_free(h->name);
bstr_free(h->value);
free(h);
}
table_destroy(part->headers);
}
free(part);
}
/**
* Finalizes part processing.
*
* @param part
*/
int htp_mpart_part_finalize_data(htp_mpart_part_t *part) {
// We currently do not process the preamble and epilogue parts
if ((part->type == MULTIPART_PART_PREAMBLE) || (part->type == MULTIPART_PART_EPILOGUE)) return 1;
if (bstr_builder_size(part->mpartp->part_pieces) > 0) {
part->value = bstr_builder_to_str(part->mpartp->part_pieces);
bstr_builder_clear(part->mpartp->part_pieces);
// fprint_raw_data(stderr, "PART DATA", (unsigned char *) bstr_ptr(part->value), bstr_len(part->value));
}
return 1;
}
/**
* Handles part data.
*
* @param part
* @param data
* @param len
* @param is_line
*/
int htp_mpart_part_handle_data(htp_mpart_part_t *part, unsigned char *data, size_t len, int is_line) {
// fprint_raw_data_ex(stderr, "PART DATA", data, 0, len);
// printf("PART DATA is_line %d mode %d\n", is_line, part->mpartp->current_mode);
// TODO We don't actually need the is_line parameter, because we can
// discover that ourselves by looking at the last byte in the buffer.
// Keep track of part length
part->len += len;
// We currently do not process the preamble and epilogue parts
if ((part->type == MULTIPART_PART_PREAMBLE) || (part->type == MULTIPART_PART_EPILOGUE)) return 1;
if (part->mpartp->current_mode == MULTIPART_MODE_LINE) {
// Line mode
// TODO Remove the extra characters from folded lines
if (is_line) {
// End of line
// Ignore the line ending
if (len > 1) {
if (data[len - 1] == LF) len--;
if (data[len - 1] == CR) len--;
} else if (len > 0) {
if (data[len - 1] == LF) len--;
}
// Is it an empty line?
if ((len == 0) && ((bstr_builder_size(part->mpartp->part_pieces) == 0))) {
// Empty line; switch to data mode
part->mpartp->current_mode = MULTIPART_MODE_DATA;
htp_mpart_part_process_headers(part); // TODO RC
} else {
// Not an empty line
// Is there a folded line coming after this one?
if ((part->mpartp->first_boundary_byte != ' ') && (part->mpartp->first_boundary_byte != '\t')) {
// No folded lines after this one, so process header
// Do we have more than once piece?
if (bstr_builder_size(part->mpartp->part_pieces) > 0) {
// Line in pieces
bstr_builder_append_mem(part->mpartp->part_pieces, (char *) data, len);
bstr *line = bstr_builder_to_str(part->mpartp->part_pieces); // TODO RC
// fprint_raw_data(stderr, "LINE(1)", (unsigned char *) bstr_ptr(line), bstr_len(line));
htp_mpartp_parse_header(part, (unsigned char *) bstr_ptr(line), bstr_len(line)); // TODO RC
bstr_free(line);
bstr_builder_clear(part->mpartp->part_pieces);
} else {
// Just this line
htp_mpartp_parse_header(part, data, len); // TODO RC
}
part->mpartp->pieces_form_line = 0;
} else {
// Folded line, just store this piece for later
bstr_builder_append_mem(part->mpartp->part_pieces, (char *) data, len);
part->mpartp->pieces_form_line = 1;
}
}
} else {
// Not end of line; keep the data chunk for later
bstr_builder_append_mem(part->mpartp->part_pieces, (char *) data, len);
part->mpartp->pieces_form_line = 0;
}
} else {
// Data mode; keep the data chunk for later (but not if it is a file)
if (part->type != MULTIPART_PART_FILE) {
bstr_builder_append_mem(part->mpartp->part_pieces, (char *) data, len);
}
}
return 1;
}
/**
* Handles data, creating new parts as necessary.
*
* @param mpartp
* @param data
* @param len
* @param is_line
*/
static int htp_mpartp_handle_data(htp_mpartp_t *mpartp, unsigned char *data, size_t len, int is_line) {
if (len == 0) return 1;
// Do we have a part already?
if (mpartp->current_part == NULL) {
// Create new part
mpartp->current_part = htp_mpart_part_create(mpartp);
if (mpartp->current_part == NULL) return -1; // TODO RC
if (mpartp->boundary_count == 0) {
mpartp->current_part->type = MULTIPART_PART_PREAMBLE;
mpartp->current_mode = MULTIPART_MODE_DATA;
} else {
if (mpartp->seen_last_boundary) {
mpartp->current_part->type = MULTIPART_PART_EPILOGUE;
mpartp->current_mode = MULTIPART_MODE_DATA;
}
}
// Add part to the list.
// TODO Perhaps we need a flag to know if a part has been finalized.
list_push(mpartp->parts, mpartp->current_part);
}
// Send data to part
htp_mpart_part_handle_data(mpartp->current_part, data, len, is_line); // TODO RC
return 1;
}
/**
* Handles a boundary event, which means that it will finalize a part
* if one exists.
*
* @param mpartp
*/
static int htp_mpartp_handle_boundary(htp_mpartp_t * mpartp) {
// TODO Having mpartp->seen_last_boundary set here means that there's
// a boundary after the "last boundary".
if (mpartp->current_part != NULL) {
if (htp_mpart_part_finalize_data(mpartp->current_part) < 0) return -1; // TODO RC
// We're done with this part
mpartp->current_part = NULL;
// Revert to line mode
mpartp->current_mode = MULTIPART_MODE_LINE;
}
return 1;
}
/**
* Creates a new multipart/form-data parser.
*
* @param boundary
* @return New parser, or NULL on memory allocation failure.
*/
htp_mpartp_t * htp_mpartp_create(char *boundary) {
htp_mpartp_t *mpartp = calloc(1, sizeof (htp_mpartp_t));
if (mpartp == NULL) return NULL;
mpartp->boundary_pieces = bstr_builder_create();
if (mpartp->boundary_pieces == NULL) {
free(mpartp);
return NULL;
}
mpartp->part_pieces = bstr_builder_create();
if (mpartp->part_pieces == NULL) {
bstr_builder_destroy(mpartp->boundary_pieces);
free(mpartp);
return NULL;
}
mpartp->parts = list_array_create(64);
if (mpartp->parts == NULL) {
bstr_builder_destroy(mpartp->part_pieces);
bstr_builder_destroy(mpartp->boundary_pieces);
free(mpartp);
return NULL;
}
// Copy the boundary and convert it to lowercase
mpartp->boundary_len = strlen(boundary) + 4;
mpartp->boundary = malloc(mpartp->boundary_len + 1);
if (mpartp->boundary == NULL) {
bstr_builder_destroy(mpartp->boundary_pieces);
free(mpartp);
return NULL;
}
// TODO Not using the CR and LF any more
mpartp->boundary[0] = CR;
mpartp->boundary[1] = LF;
mpartp->boundary[2] = '-';
mpartp->boundary[3] = '-';
size_t i = 4;
while (i < mpartp->boundary_len) {
mpartp->boundary[i] = tolower((int) ((unsigned char) boundary[i - 4]));
i++;
}
mpartp->state = MULTIPART_STATE_BOUNDARY;
mpartp->bpos = 2;
mpartp->handle_data = htp_mpartp_handle_data;
mpartp->handle_boundary = htp_mpartp_handle_boundary;
return mpartp;
}
/**
* Destroys a multipart/form-data parser.
*
* @param mpartp
*/
void htp_mpartp_destroy(htp_mpartp_t * mpartp) {
if (mpartp == NULL) return;
free(mpartp->boundary);
bstr_builder_destroy(mpartp->part_pieces);
bstr_builder_destroy(mpartp->boundary_pieces);
// Free parts
htp_mpart_part_t * part = NULL;
list_iterator_reset(mpartp->parts);
while ((part = list_iterator_next(mpartp->parts)) != NULL) {
htp_mpart_part_destroy(part);
}
list_destroy(mpartp->parts);
free(mpartp);
}
/**
* Processes set-aside data.
*
* @param mpartp
* @param data
* @param pos
* @param startpos
* @param return_pos
* @param matched
*/
static int htp_martp_process_aside(htp_mpartp_t *mpartp, int matched) {
// The store data pieces can contain up to one line. If we're in data mode and there
// was no boundary match, things are straightforward -- we process everything as data.
// If there was a match, we need to take care to not send the line ending as data, nor
// anything that follows (because it's going to be a part of the boundary). Similary,
// when we are in line mode, we need to split the first data chunk, processing the first
// part as line and the second part as data.
// Do we need to do any chunk splitting?
if (matched || (mpartp->current_mode == MULTIPART_MODE_LINE)) {
// Line mode or boundary match
// In line mode, we ignore lone CR bytes
mpartp->cr_aside = 0;
// We know that we went to match a boundary because
// we saw a new line. Now we have to find that line and
// process it. It's either going to be in the current chunk,
// or in the first stored chunk.
if (bstr_builder_size(mpartp->boundary_pieces) > 0) {
// We have stored chunks
bstr *b = NULL;
int first = 1;
list_iterator_reset(mpartp->boundary_pieces->pieces);
while ((b = list_iterator_next(mpartp->boundary_pieces->pieces)) != NULL) {
if (first) {
// Split the first chunk
if (!matched) {
// In line mode, we are OK with line endings
mpartp->handle_data(mpartp, (unsigned char *) bstr_ptr(b), mpartp->boundarypos, 1);
} else {
// But if there was a match, the line ending belongs to the boundary
unsigned char *dx = (unsigned char *) bstr_ptr(b);
size_t lx = mpartp->boundarypos;
// Remove LF or CRLF
if ((lx > 0) && (dx[lx - 1] == LF)) {
lx--;
// Remove CR
if ((lx > 0) && (dx[lx - 1] == CR)) {
lx--;
}
}
mpartp->handle_data(mpartp, dx, lx, 0);
}
// The second part of the split chunks belongs to the boundary
// when matched, data otherwise.
if (!matched) {
mpartp->handle_data(mpartp, (unsigned char *) bstr_ptr(b) + mpartp->boundarypos,
bstr_len(b) - mpartp->boundarypos, 0);
}
first = 0;
} else {
// Do not send data if there was a boundary match. The stored
// data belongs to the boundary.
if (!matched) {
mpartp->handle_data(mpartp, (unsigned char *) bstr_ptr(b), bstr_len(b), 0);
}
}
}
bstr_builder_clear(mpartp->boundary_pieces);
}
} else {
// Data mode and no match
// In data mode, we process the lone CR byte as data
if (mpartp->cr_aside) {
mpartp->handle_data(mpartp, (unsigned char *) &"\r", 1, 0 /* Not end of line */);
mpartp->cr_aside = 0;
}
// We then process any pieces that we might have stored, also as data
if (bstr_builder_size(mpartp->boundary_pieces) > 0) {
bstr *b = NULL;
list_iterator_reset(mpartp->boundary_pieces->pieces);
while ((b = list_iterator_next(mpartp->boundary_pieces->pieces)) != NULL) {
mpartp->handle_data(mpartp, (unsigned char *) bstr_ptr(b), bstr_len(b), 0);
}
bstr_builder_clear(mpartp->boundary_pieces);
}
}
return 1;
}
/**
* Finalize parsing.
*
* @param mpartp
*/
int htp_mpartp_finalize(htp_mpartp_t * mpartp) {
if (mpartp->current_part != NULL) {
htp_martp_process_aside(mpartp, 0);
if (htp_mpart_part_finalize_data(mpartp->current_part) < 0) return -1; // TODO RC
}
bstr_builder_clear(mpartp->boundary_pieces);
return 1;
}
/**
* Parses a chunk of multipart/form-data data. This function should be called
* as many times as necessary until all data has been consumed.
*
* @param mpartp
* @parma data
* @param len
* @return Status indicator
*/
int htp_mpartp_parse(htp_mpartp_t *mpartp, unsigned char *data, size_t len) {
// fprint_raw_data_ex(stderr, "INPUT", data, 0, len);
size_t pos = 0; // Current position in the input chunk.
size_t startpos = 0; // The starting position of data.
size_t data_return_pos = 0; // The position of the (possible) boundary.
//size_t local_aside_len = 0; // How many bytes have we put side from this chunk only?
// Loop while there's data in the buffer
while (pos < len) {
STATE_SWITCH:
// fprintf(stderr, "STATE %d pos %d\n", mpartp->state, pos);
switch (mpartp->state) {
case MULTIPART_STATE_DATA:
// We don't need a local aside any more since we're back
// local_aside_len = 0;
if ((pos == 0) && (mpartp->cr_aside) && (pos < len)) {
mpartp->handle_data(mpartp, (unsigned char *) &"\r", 1, 0);
mpartp->cr_aside = 0;
}
// Loop through available data
while (pos < len) {
if (data[pos] == CR) {
// We have a CR byte
// Is this CR the last byte?
if (pos + 1 == len) {
// We have CR as the last byte in input. We are going to process
// what we have in the buffer as data, except for the CR byte,
// which we're going to leave for later. If it happens that a
// CR is followed by a LF and then a boundary, the CR is going
// to be discarded.
pos++; // Take CR from input
mpartp->cr_aside = 1;
// local_aside_len = 1;
} else {
// We have CR and at least one more byte in the buffer, so we
// are able to test for the LF byte too.
if (data[pos + 1] == LF) {
pos += 2; // Take CR and LF from input
// Prepare to switch to boundary testing
data_return_pos = pos;
mpartp->boundarypos = pos - startpos;
mpartp->bpos = 2; // After LF/first dash
mpartp->state = MULTIPART_STATE_BOUNDARY;
goto STATE_SWITCH;
}
}
} else if (data[pos] == LF) {
// Possible boundary start position (LF line)
pos++; // Take LF from input
// Prepare to switch to boundary testing
data_return_pos = pos;
mpartp->boundarypos = pos - startpos;
mpartp->bpos = 2; // After LF/first dash
mpartp->state = MULTIPART_STATE_BOUNDARY;
goto STATE_SWITCH;
} else {
// Take one byte from input
pos++;
mpartp->cr_aside = 0;
}
} // while
// End of data; process data chunk
mpartp->handle_data(mpartp, data + startpos, pos - startpos - mpartp->cr_aside, 0);
break;
case MULTIPART_STATE_BOUNDARY:
// Possible boundary
while (pos < len) {
// fprintf(stderr, "B byte %d desired %d\n", data[pos], mpartp->boundary[mpartp->bpos]);
// Remember the first byte in the new line; we'll need to
// determine if the line is a part of a folder header.
if (mpartp->bpos == 2) {
mpartp->first_boundary_byte = data[pos];
}
// Check if the bytes match
if (!(data[pos] == mpartp->boundary[mpartp->bpos])) {
// Boundary mismatch
// Process stored data
htp_martp_process_aside(mpartp, 0);
// Return back where DATA parsing left off
if (mpartp->current_mode == MULTIPART_MODE_LINE) {
// In line mode, we process the line
mpartp->handle_data(mpartp, data + startpos, data_return_pos - startpos, 1);
startpos = data_return_pos;
} else {
// In data mode, we go back where we left off
pos = data_return_pos;
}
mpartp->state = MULTIPART_STATE_DATA;
goto STATE_SWITCH;
}
// Consume one matched boundary byte
pos++;
// Have we seen all boundary bytes?
if (++mpartp->bpos == mpartp->boundary_len) {
// Boundary match!
// Process stored data
htp_martp_process_aside(mpartp, 1);
// Process data prior to the boundary in the local chunk
mpartp->handle_data(mpartp, data + startpos, data_return_pos - startpos, 0);
// Keep track of how many boundaries we've seen.
mpartp->boundary_count++;
// Run boundary match.
mpartp->handle_boundary(mpartp);
// We now need to check if this is the last boundary in the payload
mpartp->state = MULTIPART_STATE_BOUNDARY_IS_LAST2;
goto STATE_SWITCH;
}
} // while
// No more data in the local chunk; store the unprocessed part for later
bstr_builder_append_mem(mpartp->boundary_pieces, (char *) data + startpos, len - startpos);
break;
case MULTIPART_STATE_BOUNDARY_IS_LAST2:
// We're expecting two dashes
if (data[pos] == '-') {
// Still hoping!
pos++;
mpartp->state = MULTIPART_STATE_BOUNDARY_IS_LAST1;
} else {
// Hmpf, it's not the last boundary.
mpartp->state = MULTIPART_STATE_BOUNDARY_EAT_LF;
}
break;
case MULTIPART_STATE_BOUNDARY_IS_LAST1:
// One more dash left to go
if (data[pos] == '-') {
// This is indeed the last boundary in the payload
pos++;
mpartp->seen_last_boundary = 1;
mpartp->state = MULTIPART_STATE_BOUNDARY_EAT_LF;
} else {
// The second character is not a dash. This means that we have
// an error in the payload. We should report the error and
// continue to eat the rest of the line.
// TODO Error
mpartp->state = MULTIPART_STATE_BOUNDARY_EAT_LF;
}
break;
case MULTIPART_STATE_BOUNDARY_EAT_LF:
if (data[pos] == LF) {
pos++;
startpos = pos;
mpartp->state = MULTIPART_STATE_DATA;
} else {
// Error!
// Unexpected byte; remain in the same state
pos++;
}
break;
} // switch
}
return 1;
}

@ -1,120 +0,0 @@
/*
* LibHTP (http://www.libhtp.org)
* Copyright 2009,2010 Ivan Ristic <ivanr@webkreator.com>
*
* LibHTP is an open source product, released under terms of the General Public Licence
* version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text
* of the license.
*
* In addition, there is a special exception that allows LibHTP to be freely
* used with any OSI-approved open source licence. Please refer to the file
* LIBHTP_LICENSING_EXCEPTION for the full text of the exception.
*
*/
#ifndef _HTP_MULTIPART_H
#define _HTP_MULTIPART_H
typedef struct htp_mpartp_t htp_mpartp_t;
typedef struct htp_mpart_part_t htp_mpart_part_t;
#include "bstr.h"
#include "dslib.h"
#define MULTIPART_PART_UNKNOWN 0
#define MULTIPART_PART_TEXT 1
#define MULTIPART_PART_FILE 2
#define MULTIPART_PART_PREAMBLE 3
#define MULTIPART_PART_EPILOGUE 4
#define MULTIPART_MODE_LINE 0
#define MULTIPART_MODE_DATA 1
#define MULTIPART_STATE_DATA 1
#define MULTIPART_STATE_BOUNDARY 2
#define MULTIPART_STATE_BOUNDARY_IS_LAST1 3
#define MULTIPART_STATE_BOUNDARY_IS_LAST2 4
//#define MULTIPART_STATE_BOUNDARY_EAT_CRLF 5
#define MULTIPART_STATE_BOUNDARY_EAT_LF 6
#ifndef CR
#define CR '\r'
#endif
#ifndef LF
#define LF '\n'
#endif
struct htp_mpart_part_t {
/** Pointer to the parser. */
htp_mpartp_t *mpartp;
/** Part type; see the MULTIPART_PART_* constants. */
int type;
/** Raw part length. */
size_t len;
/** Part name, from the Content-Disposition header. */
bstr *name;
/** Part filename, from the Content-Disposition header. */
bstr *filename;
/** Part value; currently only available for MULTIPART_PART_TEXT parts. */
bstr *value;
/** Part headers (htp_header_t instances), indexed by name. */
table_t *headers;
};
struct htp_mpartp_t {
/** Boundary to be used to extract parts. */
char *boundary;
/** Boundary length. */
size_t boundary_len;
/** How many boundaries were seen? */
int boundary_count;
/** Did we see the last boundary? */
int seen_last_boundary;
/** List of parts. */
list_t *parts;
// Parsing callbacks
int (*handle_data)(htp_mpartp_t *mpartp, unsigned char *data, size_t len, int line_end);
int (*handle_boundary)(htp_mpartp_t *mpartp);
// Internal parsing fields
// TODO Consider prefixing them with an underscore.
int state;
size_t bpos;
unsigned char *current_data;
htp_mpart_part_t *current_part;
int current_mode;
size_t current_len;
bstr_builder_t *boundary_pieces;
bstr_builder_t *part_pieces;
int pieces_form_line;
unsigned char first_boundary_byte;
size_t boundarypos;
int cr_aside;
};
htp_mpartp_t *htp_mpartp_create(char *boundary);
void htp_mpartp_destroy(htp_mpartp_t *mpartp);
int htp_mpartp_parse(htp_mpartp_t *mpartp, unsigned char *data, size_t len);
int htp_mpartp_finalize(htp_mpartp_t *mpartp);
htp_mpart_part_t *htp_mpart_part_create(htp_mpartp_t *mpartp);
int htp_mpart_part_receive_data(htp_mpart_part_t *part, unsigned char *data, size_t len, int line);
int htp_mpart_part_finalize_data(htp_mpart_part_t *part);
void htp_mpart_part_destroy(htp_mpart_part_t *part);
#endif /* _HTP_MULTIPART_H */

@ -1,256 +0,0 @@
/*
* LibHTP (http://www.libhtp.org)
* Copyright 2009,2010 Ivan Ristic <ivanr@webkreator.com>
*
* LibHTP is an open source product, released under terms of the General Public Licence
* version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text
* of the license.
*
* In addition, there is a special exception that allows LibHTP to be freely
* used with any OSI-approved open source licence. Please refer to the file
* LIBHTP_LICENSING_EXCEPTION for the full text of the exception.
*
*/
#include "stdlib.h"
#include "htp_urlencoded.h"
/**
* This method is invoked whenever a piece of data, belonging to a single field (name or value)
* becomes available. It will either create a new parameter or store the transient information
* until a parameter can be created.
*
* @param urlenp
* @param data
* @param startpos
* @param endpos
* @param c Should contain -1 if the reason this function is called is because the end of
* the current data chunk is reached.
*/
static void htp_urlenp_add_field_piece(htp_urlenp_t *urlenp, unsigned char *data, size_t startpos, size_t endpos, int c) {
// Add field if we know it ended or if we know that
// we've used all of the input data
if ((c != -1) || (urlenp->_complete)) {
// Add field
bstr *field = NULL;
// Did we use the string builder for this field?
if (bstr_builder_size(urlenp->_bb) > 0) {
// The current field consists of more than once piece,
// we have to use the string builder
// Add current piece to string builder
if (endpos - startpos > 0) {
bstr_builder_append_mem(urlenp->_bb, (char *) data + startpos, endpos - startpos);
}
// Generate the field and clear the string builder
field = bstr_builder_to_str(urlenp->_bb);
bstr_builder_clear(urlenp->_bb);
} else {
// We only have the current piece to work with, so
// no need to involve the string builder
field = bstr_memdup((char *) data + startpos, endpos - startpos);
}
// Process the field differently, depending on the current state
if (urlenp->_state == HTP_URLENP_STATE_KEY) {
// Store the name for later
urlenp->_name = field;
if (urlenp->_complete) {
// Param with key but no value
htp_urlen_param_t *param = calloc(1, sizeof (htp_urlen_param_t));
param->name = urlenp->_name;
urlenp->_name = NULL;
param->value = bstr_cstrdup("");
if (urlenp->decode_url_encoding) {
htp_uriencoding_normalize_inplace(param->name);
}
table_add(urlenp->params, param->name, param);
#ifdef HTP_DEBUG
fprint_raw_data(stderr, "NAME", (unsigned char *) bstr_ptr(param->name), bstr_len(param->name));
fprint_raw_data(stderr, "VALUE", (unsigned char *) bstr_ptr(param->value), bstr_len(param->value));
#endif
}
} else {
// Param with key and value
htp_urlen_param_t *param = calloc(1, sizeof (htp_urlen_param_t));
param->name = urlenp->_name;
urlenp->_name = NULL;
param->value = field;
if (urlenp->decode_url_encoding) {
htp_uriencoding_normalize_inplace(param->name);
htp_uriencoding_normalize_inplace(param->value);
}
table_add(urlenp->params, param->name, param);
#ifdef HTP_DEBUG
fprint_raw_data(stderr, "NAME", (unsigned char *) bstr_ptr(param->name), bstr_len(param->name));
fprint_raw_data(stderr, "VALUE", (unsigned char *) bstr_ptr(param->value), bstr_len(param->value));
#endif
}
} else {
// Make a copy of the data and store it in an array for later
if (endpos - startpos > 0) {
bstr_builder_append_mem(urlenp->_bb, (char *) data + startpos, endpos - startpos);
}
}
}
/**
* Creates a new URLENCODED parser.
*
* @return New parser, or NULL on memory allocation failure.
*/
htp_urlenp_t *htp_urlenp_create() {
htp_urlenp_t *urlenp = calloc(1, sizeof (htp_urlenp_t));
if (urlenp == NULL) return NULL;
urlenp->params = table_create(HTP_URLENP_DEFAULT_PARAMS_SIZE);
if (urlenp->params == NULL) {
free(urlenp);
return NULL;
}
urlenp->_bb = bstr_builder_create();
if (urlenp->_bb == NULL) {
table_destroy(urlenp->params);
free(urlenp);
return NULL;
}
urlenp->argument_separator = '&';
urlenp->decode_url_encoding = 1;
urlenp->_state = HTP_URLENP_STATE_KEY;
return urlenp;
}
/**
* Destroys an existing URLENCODED parser.
*
* @param urlenp
*/
void htp_urlenp_destroy(htp_urlenp_t *urlenp) {
if (urlenp == NULL) return;
if (urlenp->_name != NULL) {
bstr_free(urlenp->_name);
}
bstr_builder_destroy(urlenp->_bb);
// Destroy individual parameters
htp_urlen_param_t *param = NULL;
table_iterator_reset(urlenp->params);
while (table_iterator_next(urlenp->params, (void **) & param) != NULL) {
bstr_free(param->name);
bstr_free(param->value);
free(param);
}
table_destroy(urlenp->params);
free(urlenp);
}
/**
* Finalizes parsing, forcing the parser to convert any outstanding
* data into parameters. This method should be invoked at the end
* of a parsing operation that used htp_urlenp_parse_partial().
*
* @param urlenp
* @return Success indication
*/
int htp_urlenp_finalize(htp_urlenp_t *urlenp) {
return htp_urlenp_parse_complete(urlenp, NULL, 0);
}
/**
* Parses the provided data chunk under the assumption
* that it contains all the data that will be parsed. When this
* method is used for parsing the finalization method should not
* be invoked.
*
* @param urlenp
* @param data
* @param len
* @return
*/
int htp_urlenp_parse_complete(htp_urlenp_t *urlenp, unsigned char *data, size_t len) {
// TODO urlenp->complete must not already be 1
urlenp->_complete = 1;
return htp_urlenp_parse_partial(urlenp, data, len);
}
/**
* Parses the provided data chunk, keeping state to allow streaming parsing, i.e., the
* parsing where only partial information is available at any one time. The method
* htp_urlenp_finalize() must be invoked at the end to finalize parsing.
*
* @param urlenp
* @param data
* @param len
* @return
*/
int htp_urlenp_parse_partial(htp_urlenp_t *urlenp, unsigned char *data, size_t len) {
size_t startpos = 0;
size_t pos = 0;
int c;
if (data == NULL) len = 0;
for (;;) {
// Get the next character, or -1
if (pos < len) c = data[pos];
else c = -1;
// printf("Pos %d C %c state %d\n", pos, c, urlenp->state);
switch (urlenp->_state) {
// Process key
case HTP_URLENP_STATE_KEY:
// Look for =, argument separator, or end of input
if ((c == '=') || (c == urlenp->argument_separator) || (c == -1)) {
// Data from startpos to pos
htp_urlenp_add_field_piece(urlenp, data, startpos, pos, c);
if (c != -1) {
// Next state
startpos = pos + 1;
urlenp->_state = HTP_URLENP_STATE_VALUE;
}
}
break;
// Process value
case HTP_URLENP_STATE_VALUE:
// Look for argument separator or end of input
if ((c == urlenp->argument_separator) || (c == -1)) {
// Data from startpos to pos
htp_urlenp_add_field_piece(urlenp, data, startpos, pos, c);
if (c != -1) {
// Next state
startpos = pos + 1;
urlenp->_state = HTP_URLENP_STATE_KEY;
}
}
break;
}
// Have we reached the end of input?
if (c == -1) break;
pos++;
}
return HTP_OK;
}

@ -1,73 +0,0 @@
/*
* LibHTP (http://www.libhtp.org)
* Copyright 2009,2010 Ivan Ristic <ivanr@webkreator.com>
*
* LibHTP is an open source product, released under terms of the General Public Licence
* version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text
* of the license.
*
* In addition, there is a special exception that allows LibHTP to be freely
* used with any OSI-approved open source licence. Please refer to the file
* LIBHTP_LICENSING_EXCEPTION for the full text of the exception.
*
*/
#ifndef _HTP_URLENCODED_H
#define _HTP_URLENCODED_H
typedef struct htp_urlenp_t htp_urlenp_t;
typedef struct htp_urlen_param_t htp_urlen_param_t;
#include "htp.h"
#define HTP_URLENP_DEFAULT_PARAMS_SIZE 32
#define HTP_URLENP_STATE_KEY 1
#define HTP_URLENP_STATE_VALUE 2
/**
* This is the main URLENCODED parser structure. It is used to store
* parser configuration, temporary parsing data, as well as the parameters.
*/
struct htp_urlenp_t {
/** The character used to separate parameters. Defaults to & and should
* not be changed without good reason.
*/
unsigned char argument_separator;
/** Whether to perform URL-decoding on parameters. */
int decode_url_encoding;
/** This table contains the list of parameters, indexed by name. */
table_t *params;
// Private fields; they are used during the parsing process
int _state;
int _complete;
bstr *_name;
bstr_builder_t *_bb;
};
/**
* Holds one application/x-www-form-urlencoded parameter.
*/
struct htp_urlen_param_t {
/** Parameter name. */
bstr *name;
/** Parameter value. */
bstr *value;
};
htp_urlenp_t *htp_urlenp_create();
void htp_urlenp_destroy(htp_urlenp_t *urlenp);
void htp_urlenp_set_argument_separator(htp_urlenp_t *urlenp, unsigned char argument_separator);
void htp_urlenp_set_decode_url_encoding(htp_urlenp_t *urlenp, int decode_url_encoding);
int htp_urlenp_parse_partial(htp_urlenp_t *urlenp, unsigned char *data, size_t len);
int htp_urlenp_parse_complete(htp_urlenp_t *urlenp, unsigned char *data, size_t len);
int htp_urlenp_finalize(htp_urlenp_t *urlenp);
#endif /* _HTP_URLENCODED_H */

@ -1,41 +0,0 @@
>>>
POST /upload.php HTTP/1.1
Host: 192.168.3.100:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Content-Type: multipart/form-data; boundary=---------------------------41184676334
Content-Length: 610
-----------------------------41184676334
Content-Disposition: form-data; name="field1"
0123456789
-----------------------------41184676334
Content-Disposition: form-data; name="field2"
9876543210
-----------------------------41184676334
Content-Disposition: form-data; name="file1"; filename="New Text Document.txt"
Content-Type: text/plain
FFFFFFFFFFFFFFFFFFFFFFFFFFFF
-----------------------------41184676334
Content-Disposition: form-data; name="file2"; filename="New Text Document.txt"
Content-Type: text/plain
FFFFFFFFFFFFFFFFFFFFFFFFFFFF
-----------------------------41184676334--
<<<
HTTP/1.0 200 OK
Date: Mon, 31 Aug 2009 20:25:50 GMT
Server: Apache
Connection: close
Content-Type: text/html
Hello World!

@ -1,11 +0,0 @@
>>>
GET /../../images.gif HTTP/1.1
Host: www.ExAmPlE.cOM
<<<
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 12
Hello World!

@ -2,7 +2,7 @@ Installation Instructions
*************************
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
2006, 2007, 2008, 2009 Free Software Foundation, Inc.
2006, 2007, 2008 Free Software Foundation, Inc.
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
@ -159,7 +159,7 @@ Particular systems
CC is not installed, it is recommended to use the following options in
order to use an ANSI C compiler:
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
./configure CC="cc -Ae"
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
@ -174,16 +174,6 @@ and if that doesn't work, try
./configure CC="cc -nodtk"
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
directory contains several dysfunctional programs; working variants of
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
in your `PATH', put it _after_ `/usr/bin'.
On Haiku, software installed for all users goes in `/boot/common',
not `/usr/local'. It is recommended to use the following options:
./configure --prefix=/boot/common
Specifying the System Type
==========================
@ -199,8 +189,7 @@ type, such as `sun4', or a canonical name which has the form:
where SYSTEM can have one of these forms:
OS
KERNEL-OS
OS KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't

@ -1,4 +1,4 @@
ACLOCAL_AMFLAGS = -I m4
SUBDIRS= $(GENERIC_LIBRARY_NAME) test
DIST_SUBDIRS = $(GENERIC_LIBRARY_NAME)

@ -48,7 +48,7 @@ The installation process should be as simple as:
$ ./configure
$ make
$ sudo make install
# make install
| NOTE If you already have an early 0.2.x version installed, you must
| uninstall it before proceeding. Initially /usr was used for the

@ -14,7 +14,7 @@ dnl -----------------------------------------------
GENERIC_LIBRARY_NAME=htp
GENERIC_MAJOR_VERSION=0
GENERIC_MINOR_VERSION=3
GENERIC_MINOR_VERSION=2
GENERIC_MICRO_VERSION=X
# API version (often = GENERIC_MAJOR_VERSION.GENERIC_MINOR_VERSION)
@ -56,8 +56,8 @@ AM_INIT_AUTOMAKE($PACKAGE, $VERSION, no-define)
AC_CONFIG_MACRO_DIR([m4])
AC_ARG_ENABLE(htp-debug, [ --enable-htp-debug Enable debug output], [ enable_htp_debug=yes ])
if test "$enable_htp_debug" = "yes"; then
AC_ARG_ENABLE(debug, [ --enable-debug Enable debug output], [ enable_debug=yes ])
if test "$enable_debug" = "yes"; then
CFLAGS="${CFLAGS} -DHTP_DEBUG"
echo "Debug mode enabled"
fi

@ -5,7 +5,7 @@ includedir=${prefix}/include
Name: HTP
Description: HTTP parser
Version: 0.3.X
Version: 0.2.X
Libs: -L${libdir} -lhtp
Cflags: -I${includedir}/htp -I${libdir}/htp/include

@ -0,0 +1,14 @@
h_sources = bstr.h dslib.h hooks.h htp.h utf8_decoder.h htp_decompressors.h
c_sources = bstr.c hooks.c htp_config.c htp_connection_parser.c htp_request_apache_2_2.c htp_request_generic.c htp_request_parsers.c htp_response_generic.c htp_util.c dslib.c htp.c htp_connection.c htp_parsers.c htp_request.c htp_response.c htp_transaction.c utf8_decoder.c htp_decompressors.c
library_includedir = $(includedir)/$(GENERIC_LIBRARY_NAME)
library_include_HEADERS = $(h_sources)
INCLUDES = -I$(top_srcdir)
AM_CFLAGS = -D_GNU_SOURCE -g -O2 -Wall -Wextra -std=gnu99 -pedantic
lib_LTLIBRARIES= libhtp.la
libhtp_la_SOURCES= $(h_sources) $(c_sources)
libhtp_la_LDFLAGS= -version-info $(GENERIC_LIBRARY_VERSION) -release $(GENERIC_RELEASE)

@ -15,15 +15,10 @@
#ifndef _BSTR_H
#define _BSTR_H
typedef struct bstr_t bstr_t;
typedef void * bstr;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bstr_builder.h"
// IMPORTANT This binary string library is used internally by the parser and you should
// not rely on it in your code. The implementation may change.
//
@ -31,35 +26,10 @@ typedef void * bstr;
// - Add a function that wraps an existing data
// - Support Unicode bstrings
struct bstr_t {
/** The length of the string stored in the buffer. */
size_t len;
/** The current size of the buffer. If the buffer is bigger than the
* string then it will be able to expand without having to reallocate.
*/
size_t size;
/** Optional buffer pointer. If this pointer is NUL (as it currently is
* in virtually all cases, the string buffer will immediatelly follow
* this structure. If the pointer is not NUL, it points to the actual
* buffer used, and there's no data following this structure.
*/
char *ptr;
};
// Defines
#define bstr_len(X) ((*(bstr_t *)(X)).len)
#define bstr_size(X) ((*(bstr_t *)(X)).size)
#define bstr_ptr(X) ( ((*(bstr_t *)(X)).ptr == NULL) ? (char *)((char *)(X) + sizeof(bstr_t)) : (char *)(*(bstr_t *)(X)).ptr )
// Functions
typedef void * bstr;
bstr *bstr_alloc(size_t newsize);
void bstr_free(bstr *s);
void bstr_free(bstr *s);
bstr *bstr_expand(bstr *s, size_t newsize);
bstr *bstr_cstrdup(char *);
bstr *bstr_memdup(char *data, size_t len);
@ -99,7 +69,28 @@ void bstr_len_adjust(bstr *s, size_t newlen);
char bstr_char_at(bstr *s, size_t pos);
typedef struct bstr_t bstr_t;
struct bstr_t {
/** The length of the string stored in the buffer. */
size_t len;
/** The current size of the buffer. If the buffer is bigger than the
* string then it will be able to expand without having to reallocate.
*/
size_t size;
/** Optional buffer pointer. If this pointer is NUL (as it currently is
* in virtually all cases, the string buffer will immediatelly follow
* this structure. If the pointer is not NUL, it points to the actual
* buffer used, and there's no data following this structure.
*/
char *ptr;
};
#define bstr_len(X) ((*(bstr_t *)(X)).len)
#define bstr_size(X) ((*(bstr_t *)(X)).size)
#define bstr_ptr(X) ( ((*(bstr_t *)(X)).ptr == NULL) ? (char *)((char *)(X) + sizeof(bstr_t)) : (char *)(*(bstr_t *)(X)).ptr )
#endif /* _BSTR_H */

@ -15,12 +15,6 @@
#ifndef _DSLIB_H
#define _DSLIB_H
typedef struct list_t list_t;
typedef struct list_array_t list_array_t;
typedef struct list_linked_element_t list_linked_element_t;
typedef struct list_linked_t list_linked_t;
typedef struct table_t table_t;
#include "bstr.h"
// IMPORTANT This library is used internally by the parser and you should
@ -55,6 +49,13 @@ typedef struct table_t table_t;
void *(*iterator_next)(list_t *); \
void (*destroy)(list_t *)
typedef struct list_t list_t;
typedef struct list_array_t list_array_t;
typedef struct list_linked_element_t list_linked_element_t;
typedef struct list_linked_t list_linked_t;
typedef struct table_t table_t;
struct list_t {
LIST_COMMON;
};

@ -38,12 +38,10 @@ typedef struct htp_urldecoder_t htp_urldecoder_t;
#include "dslib.h"
#include "hooks.h"
#include "htp_decompressors.h"
#include "htp_urlencoded.h"
#include "htp_multipart.h"
// -- Defines -------------------------------------------------------------------------------------
#define HTP_BASE_VERSION_TEXT "Trunk"
#define HTP_BASE_VERSION_TEXT "0.2.x"
#define HTP_ERROR -1
#define HTP_OK 0
@ -1108,7 +1106,6 @@ void htp_log(htp_connp_t *connp, const char *file, int line, int level, int code
void htp_print_log(FILE *stream, htp_log_t *log);
void fprint_raw_data(FILE *stream, const char *name, unsigned char *data, size_t len);
void fprint_raw_data_ex(FILE *stream, const char *name, unsigned char *data, size_t offset, size_t len);
char *htp_connp_in_state_as_string(htp_connp_t *connp);
char *htp_connp_out_state_as_string(htp_connp_t *connp);

@ -97,8 +97,8 @@ int htp_process_request_header_generic(htp_connp_t *connp) {
bstr_add_str_noex(h_existing->value, h->value);
// The header is no longer needed
bstr_free(h->name);
bstr_free(h->value);
free(h->name);
free(h->value);
free(h);
// Keep track of same-name headers

@ -80,6 +80,7 @@ void htp_tx_destroy(htp_tx_t *tx) {
bstr_free(tx->parsed_uri_incomplete->path);
bstr_free(tx->parsed_uri_incomplete->query);
bstr_free(tx->parsed_uri_incomplete->fragment);
free(tx->parsed_uri_incomplete);
}

@ -1575,17 +1575,10 @@ void htp_normalize_uri_path_inplace(bstr *s) {
*
*/
void fprint_raw_data(FILE *stream, const char *name, unsigned char *data, size_t len) {
fprint_raw_data_ex(stream, name, data, 0, len);
}
/**
*
*/
void fprint_raw_data_ex(FILE *stream, const char *name, unsigned char *data, size_t offset, size_t printlen) {
char buf[160];
size_t len = offset + printlen;
size_t offset = 0;
fprintf(stream, "\n%s: offset %zd len %zd\n", name, offset, len);
fprintf(stream, "\n%s: data len %zd (0x%zx)\n", name, len, len);
while (offset < len) {
size_t i;
@ -1644,6 +1637,11 @@ void fprint_raw_data_ex(FILE *stream, const char *name, unsigned char *data, siz
fprintf(stream, "\n");
}
/*
*/
/**
*
*/

@ -0,0 +1,10 @@
>>>
GET http://www.example%64.com/one/two/three.php?p=%64&q=%64#fff HTTP/1.0
<<<
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 12
Hello World!

@ -754,7 +754,7 @@ int main_dir(int argc, char** argv) {
/**
* Entry point; runs a bunch of tests and exits.
*/
int main_tests(int argc, char** argv) {
int main(int argc, char** argv) {
char buf[1025];
int tests = 0, failures = 0;
@ -817,7 +817,6 @@ int main_tests(int argc, char** argv) {
htp_config_set_generate_request_uri_normalized(cfg, 1);
/*
RUN_TEST(test_get, cfg);
RUN_TEST(test_apache_header_parsing, cfg);
RUN_TEST(test_post_urlencoded, cfg);
@ -835,9 +834,8 @@ int main_tests(int argc, char** argv) {
RUN_TEST(test_connect, cfg);
RUN_TEST(test_connect_complete, cfg);
RUN_TEST(test_connect_extra, cfg);
*/
RUN_TEST(test_misc, cfg);
//RUN_TEST(test_misc, cfg);
printf("Tests: %i\n", tests);
printf("Failures: %i\n", failures);
@ -1032,6 +1030,7 @@ int main_utf8_decoder_tests(int argc, char** argv) {
bstr_free(expected); \
bstr_free(input);
int main_path_tests(int argc, char** argv) {
htp_cfg_t *cfg = NULL;
htp_tx_t *tx = NULL;
@ -1364,121 +1363,3 @@ int main_path_tests(int argc, char** argv) {
printf("\n");
printf("Total tests: %i, %i failure(s).\n", tests, failures);
}
int main_urlenp_tests(int argc, char** argv) {
//int main(int argc, char** argv) {
htp_urlenp_t *urlenp = NULL;
urlenp = htp_urlenp_create();
//parts[nput = "A=1&B=2&C=&=4&=";
//htp_urlenp_parse_complete(urlenp, input, strlen(input));
unsigned char *i1 = "A=01234567";
unsigned char *i2 = "89&BB";
htp_urlenp_parse_partial(urlenp, i1, strlen(i1));
htp_urlenp_parse_partial(urlenp, i2, strlen(i2));
htp_urlenp_finalize(urlenp);
htp_urlenp_destroy(urlenp);
/*
bstr_builder_t *bb = bstr_builder_create();
bstr_builder_append_cstr(bb, "|123|");
bstr_builder_append_cstr(bb, "|456|");
bstr_builder_append_cstr(bb, "|789|");
bstr *b = bstr_builder_to_str(bb);
fprint_raw_data(stderr, __FUNCTION__, bstr_ptr(b), bstr_len(b));
*/
}
int main_multipart1(int argc, char** argv) {
//int main(int argc, char** argv) {
htp_mpartp_t *mpartp = NULL;
mpartp = htp_mpartp_create("BBB");
unsigned char *i1 = "x0000x\n--BBB\nx1111x\n--\nx2222x\n--";
unsigned char *i2 = "BBB\nx3333x\n--B";
unsigned char *i3 = "B\nx4444x\n--B";
unsigned char *i4 = "B\n--BBB\n\nx5555x\r";
unsigned char *i5 = "\n--x6666x\r";
unsigned char *i6 = "-";
unsigned char *i7 = "-";
htp_mpartp_parse(mpartp, i1, strlen(i1));
htp_mpartp_parse(mpartp, i2, strlen(i2));
htp_mpartp_parse(mpartp, i3, strlen(i3));
htp_mpartp_parse(mpartp, i4, strlen(i4));
htp_mpartp_parse(mpartp, i5, strlen(i5));
htp_mpartp_parse(mpartp, i6, strlen(i6));
htp_mpartp_parse(mpartp, i7, strlen(i7));
htp_mpartp_finalize(mpartp);
/*
"x0000x"
"x1111x\n--\nx2222x"
"x3333x"
"\n--B"
"B\nx4444x"
"\n--B"
"B" "\nx5555x"
"\r"
"\n--x6666x"
*/
htp_mpartp_destroy(mpartp);
}
//int main_multipart2(int argc, char** argv) {
int main(int argc, char** argv) {
htp_mpartp_t *mpartp = NULL;
mpartp = htp_mpartp_create("---------------------------41184676334");
unsigned char *parts[999];
int i = 1;
parts[i++] = "-----------------------------41184676334\r\n";
parts[i++] = "Content-Disposition: form-data;\n name=\"field1\"\r\n";
parts[i++] = "\r\n";
parts[i++] = "0123456789\r\n-";
parts[i++] = "-------------";
parts[i++] = "---------------41184676334\r\n";
parts[i++] = "Content-Disposition: form-data;\n name=\"field3\"\r\n";
parts[i++] = "\r\n";
parts[i++] = "0123456789\r\n-";
parts[i++] = "-------------";
parts[i++] = "--------------X\r\n";
parts[i++] = "-----------------------------41184676334\r\n";
parts[i++] = "Content-Disposition: form-data;\n";
parts[i++] = " ";
parts[i++] = "name=\"field2\"\r\n";
parts[i++] = "\r\n";
parts[i++] = "9876543210\r\n";
parts[i++] = "-----------------------------41184676334\r\n";
parts[i++] = "Content-Disposition: form-data; name=\"file1\"; filename=\"New Text Document.txt\"\r\nContent-Type: text/plain\r\n\r\n";
parts[i++] = "1FFFFFFFFFFFFFFFFFFFFFFFFFFF\r\n";
parts[i++] = "2FFFFFFFFFFFFFFFFFFFFFFFFFFE\r";
parts[i++] = "3FFFFFFFFFFFFFFFFFFFFFFFFFFF\r\n4FFFFFFFFFFFFFFFFFFFFFFFFF123456789";
parts[i++] = "\r\n";
parts[i++] = "-----------------------------41184676334\r\n";
parts[i++] = "Content-Disposition: form-data; name=\"file2\"; filename=\"New Text Document.txt\"\r\n";
parts[i++] = "Content-Type: text/plain\r\n";
parts[i++] = "\r\n";
parts[i++] = "FFFFFFFFFFFFFFFFFFFFFFFFFFFZ\r\n";
parts[i++] = "-----------------------------41184676334--\r\n";
parts[i++] = NULL;
i = 1;
for (;;) {
if (parts[i] == NULL) break;
htp_mpartp_parse(mpartp, parts[i], strlen(parts[i]));
i++;
}
htp_mpartp_finalize(mpartp);
htp_mpartp_destroy(mpartp);
}

@ -192,8 +192,8 @@ INCLUDES= $(all_includes)
suricata_LDFLAGS = $(all_libraries)
if BUILD_LIBHTP
suricata_LDADD = $(top_builddir)/htp/htp/libhtp.la
INCLUDES += -I$(top_builddir)/htp
suricata_LDADD = $(top_builddir)/libhtp/htp/libhtp.la
INCLUDES += -I$(top_builddir)/libhtp
endif
#suricata_CFLAGS = -Wall -fno-strict-aliasing

Loading…
Cancel
Save