Exemple #1
0
TEST(BstrTest, ExpandSmaller) {
    bstr *p1;
    bstr *p2;

    p1 = bstr_alloc(100);
    p2 = bstr_expand(p1, 10);
    ASSERT_TRUE(p2 == NULL);

    bstr_free(p1);
}
Exemple #2
0
TEST(BstrTest, ExpandLocal) {
    bstr *p1;
    bstr *p2;

    p1 = bstr_alloc(10);
    p2 = bstr_expand(p1, 100);
    ASSERT_NE(reinterpret_cast<bstr*>(NULL), p2);
    EXPECT_EQ(100, bstr_size(p2));
    EXPECT_EQ(0, bstr_len(p2));

    bstr_free(p2);
}
/**
 * Extract one request header. A header can span multiple lines, in
 * which case they will be folded into one before parsing is attempted.
 *
 * @param[in] connp
 * @param[in] data
 * @param[in] len
 * @return HTP_OK or HTP_ERROR
 */
htp_status_t htp_process_request_header_generic(htp_connp_t *connp, unsigned char *data, size_t len) {
    // Create a new header structure.
    htp_header_t *h = calloc(1, sizeof (htp_header_t));
    if (h == NULL) return HTP_ERROR;

    // Now try to parse the header.
    if (htp_parse_request_header_generic(connp, h, data, len) != HTP_OK) {
        free(h);
        return HTP_ERROR;
    }

    #ifdef HTP_DEBUG
    fprint_bstr(stderr, "Header name", h->name);
    fprint_bstr(stderr, "Header value", h->value);
    #endif

    // Do we already have a header with the same name?
    htp_header_t *h_existing = htp_table_get(connp->in_tx->request_headers, h->name);
    if (h_existing != NULL) {
        // TODO Do we want to have a list of the headers that are
        //      allowed to be combined in this way?

        // Add to the existing header.
        bstr *new_value = bstr_expand(h_existing->value, bstr_len(h_existing->value) + 2 + bstr_len(h->value));
        if (new_value == NULL) {
            bstr_free(h->name);
            bstr_free(h->value);
            free(h);
            return HTP_ERROR;
        }

        h_existing->value = new_value;
        bstr_add_mem_noex(h_existing->value, ", ", 2);
        bstr_add_noex(h_existing->value, h->value);

        // The new header structure is no longer needed.
        bstr_free(h->name);
        bstr_free(h->value);
        free(h);

        // Keep track of repeated same-name headers.
        h_existing->flags |= HTP_FIELD_REPEATED;
    } else {
        // Add as a new header.
        htp_table_add(connp->in_tx->request_headers, h->name, h);
    }

    return HTP_OK;
}
Exemple #4
0
TEST(BstrTest, ExpandPtr) {
    bstr *b;
    b = (bstr*) malloc(sizeof(bstr));
    ASSERT_NE((bstr*)NULL, b);
    b->realptr = (unsigned char*) malloc(10);
    b->len = 0;
    b->size = 10;
    ASSERT_NE((unsigned char*)NULL, bstr_ptr(b));

    bstr *p2 = bstr_expand(b, 100);
    EXPECT_TRUE(p2 == NULL);

    free(b->realptr);
    bstr_free(b);
}
/**
 * Extract one request header. A header can span multiple lines, in
 * which case they will be folded into one before parsing is attempted.
 *
 * @param connp
 * @return HTP_OK or HTP_ERROR
 */
int htp_process_request_header_apache_2_2(htp_connp_t *connp) {
    bstr *tempstr = NULL;
    unsigned char *data = NULL;
    size_t len = 0;

    // Create new header structure
    htp_header_t *h = calloc(1, sizeof (htp_header_t));
    if (h == NULL) return HTP_ERROR;

    // Ensure we have the necessary header data in a single buffer
    if (connp->in_header_line_index + 1 == connp->in_header_line_counter) {
        // Single line
        htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines,
            connp->in_header_line_index);
        if (hl == NULL) {
            // Internal error
            htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
                "Process request header (Apache 2.2): Internal error");
            free(h);
            return HTP_ERROR;
        }

        data = (unsigned char *) bstr_ptr(hl->line);
        len = bstr_len(hl->line);
        hl->header = h;
    } else {
        // Multiple lines (folded)
        int i = 0;

        for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) {
            htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines, i);
            if (hl == NULL) {
                // Internal error
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
                        "Process request header (Apache 2.2): Internal error");
                free(h);
                return HTP_ERROR;
            }
            len += bstr_len(hl->line);
        }

        tempstr = bstr_alloc(len);
        if (tempstr == NULL) {
            htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
                "Process request header (Apache 2.2): Failed to allocate bstring of %d bytes", len);
            free(h);
            return HTP_ERROR;
        }

        for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) {
            htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines, i);
            if (hl == NULL) {
                // Internal error
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
                        "Process request header (Apache 2.2): Internal error");
                bstr_free(tempstr);
                free(h);
                return HTP_ERROR;
            }
            char *data = bstr_ptr(hl->line);
            size_t len = bstr_len(hl->line);
            htp_chomp((unsigned char *)data, &len);
            bstr_add_mem_noex(tempstr, data, len);
            hl->header = h;
        }

        data = (unsigned char *) bstr_ptr(tempstr);
    }

    // Now try to parse the header
    if (htp_parse_request_header_apache_2_2(connp, h, data, len) != HTP_OK) {
        // Note: downstream responsible for error logging
        if (tempstr != NULL) {
            free(tempstr);
        }
        free(h);
        return HTP_ERROR;
    }

    // Do we already have a header with the same name?
    htp_header_t *h_existing = table_get(connp->in_tx->request_headers, h->name);
    if (h_existing != NULL) {
        // TODO Do we want to keep a list of the headers that are
        //      allowed to be combined in this way?

        // 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
        if (h->name != NULL)
            free(h->name);
        if (h->value != NULL)
            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(connp->in_tx->request_headers, h->name, h);
    }

    if (tempstr != NULL) {
        free(tempstr);
    }

    return HTP_OK;
}
/**
 * Generic response header line(s) processor, which assembles folded lines
 * into a single buffer before invoking the parsing function.
 * 
 * @param[in] connp
 * @param[in] data
 * @param[in] len
 * @return HTP status
 */
htp_status_t htp_process_response_header_generic(htp_connp_t *connp, unsigned char *data, size_t len) {
    // Create a new header structure.
    htp_header_t *h = calloc(1, sizeof (htp_header_t));
    if (h == NULL) return HTP_ERROR;

    if (htp_parse_response_header_generic(connp, h, data, len) != HTP_OK) {
        free(h);
        return HTP_ERROR;
    }

    #ifdef HTP_DEBUG
    fprint_bstr(stderr, "Header name", h->name);
    fprint_bstr(stderr, "Header value", h->value);
    #endif

    // Do we already have a header with the same name?
    htp_header_t *h_existing = htp_table_get(connp->out_tx->response_headers, h->name);
    if (h_existing != NULL) {
        // Keep track of repeated same-name headers.
        h_existing->flags |= HTP_FIELD_REPEATED;
                
        // Having multiple C-L headers is against the RFC but many
        // browsers ignore the subsequent headers if the values are the same.
        if (bstr_cmp_c_nocase(h->name, "Content-Length") == 0) {
            // Don't use string comparison here because we want to
            // ignore small formatting differences.

            int64_t existing_cl, new_cl;

            existing_cl = htp_parse_content_length(h_existing->value);
            new_cl = htp_parse_content_length(h->value);
            if ((existing_cl == -1) || (new_cl == -1) || (existing_cl != new_cl)) {
                // Ambiguous response C-L value.
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Ambiguous response C-L value");

                bstr_free(h->name);
                bstr_free(h->value);
                free(h);
                
                return HTP_ERROR;
            }

            // Ignoring the new C-L header that has the same value as the previous ones.
        } else {            
            // Add to the existing header.

            bstr *new_value = bstr_expand(h_existing->value, bstr_len(h_existing->value) + 2 + bstr_len(h->value));
            if (new_value == NULL) {
                bstr_free(h->name);
                bstr_free(h->value);
                free(h);
                return HTP_ERROR;
            }

            h_existing->value = new_value;
            bstr_add_mem_noex(h_existing->value, (unsigned char *) ", ", 2);
            bstr_add_noex(h_existing->value, h->value);
        }

        // The new header structure is no longer needed.
        bstr_free(h->name);
        bstr_free(h->value);
        free(h);       
    } else {
        // Add as a new header.
        if (htp_table_add(connp->out_tx->response_headers, h->name, h) != HTP_OK) {
            bstr_free(h->name);
            bstr_free(h->value);
            free(h);
            return HTP_ERROR;
        }
    }
   
    return HTP_OK;
}
Exemple #7
0
/**
 * 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;
    while ((prev > name_start) && (htp_is_lws(data[prev - 1]))) {
        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_dup_mem((char *) data + name_start, name_end - name_start);
    h->value = bstr_dup_mem((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
        bstr *new_value = bstr_expand(h_existing->value, bstr_len(h_existing->value)
            + 2 + bstr_len(h->value));
        if (new_value == NULL) {
            bstr_free(&h->name);
            bstr_free(&h->value);
            free(h);
            return -1;
        }

        h_existing->value = new_value;
        bstr_add_mem_noex(h_existing->value, ", ", 2);
        bstr_add_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;
}
/**
 * Extract one request header. A header can span multiple lines, in
 * which case they will be folded into one before parsing is attempted.
 *
 * @param[in] connp
 * @return HTP_OK or HTP_ERROR
 */
int htp_process_request_header_generic(htp_connp_t *connp) {
    bstr *tempstr = NULL;
    unsigned char *data = NULL;
    size_t len = 0;

    // Create new header structure
    htp_header_t *h = calloc(1, sizeof (htp_header_t));
    if (h == NULL) {        
        return HTP_ERROR;
    }

    // Ensure we have the necessary header data in a single buffer
    if (connp->in_header_line_index + 1 == connp->in_header_line_counter) {
        // Single line
        htp_header_line_t *hl = htp_list_get(connp->in_tx->request_header_lines,
            connp->in_header_line_index);
        if (hl == NULL) {
            // Internal error            
            free(h);
            return HTP_ERROR;
        }

        data = (unsigned char *)bstr_ptr(hl->line);
        len = bstr_len(hl->line);
        hl->header = h;
    } else {
        // Multiple lines (folded)
        int i = 0;

        for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) {
            htp_header_line_t *hl = htp_list_get(connp->in_tx->request_header_lines, i);
            len += bstr_len(hl->line);
        }

        tempstr = bstr_alloc(len);
        if (tempstr == NULL) {            
            free(h);
            return HTP_ERROR;
        }

        for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) {
            htp_header_line_t *hl = htp_list_get(connp->in_tx->request_header_lines, i);
            unsigned char *line = bstr_ptr(hl->line);
            size_t llen = bstr_len(hl->line);
            htp_chomp((unsigned char *)line, &llen);
            bstr_add_mem_noex(tempstr, line, llen);
            hl->header = h;

            if (i != connp->in_header_line_index) {
                hl->flags |= HTP_FIELD_FOLDED;
            }
        }

        h->flags |= HTP_FIELD_FOLDED;

        data = (unsigned char *)bstr_ptr(tempstr);
        len = bstr_len(tempstr);
    }

    // Now try to parse the header
    if (htp_parse_request_header_generic(connp, h, data, len) != HTP_OK) {
        bstr_free(tempstr);
        free(h);
        return HTP_ERROR;
    }

    // Do we already have a header with the same name?
    htp_header_t *h_existing = htp_table_get(connp->in_tx->request_headers, h->name);
    if (h_existing != NULL) {
        // repeated header
        int i = 0;

        // TODO Do we want to keep a list of the headers that are
        //      allowed to be combined in this way?

        // Add to existing header
        bstr *new_value = bstr_expand(h_existing->value, bstr_len(h_existing->value)
            + 2 + bstr_len(h->value));        
        if (new_value == NULL) {
            bstr_free(h->name);
            bstr_free(h->value);
            free(h);
            bstr_free(tempstr);
            return HTP_ERROR;
        }

        h_existing->value = new_value;
        bstr_add_mem_noex(h_existing->value, (unsigned char *)", ", 2);
        bstr_add_noex(h_existing->value, h->value);

        // replace the header references in all lines
        for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) {
          htp_header_line_t *hl = htp_list_get(connp->in_tx->request_header_lines, i);
          hl->header = h_existing;
        }

        // The header fields are 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
        htp_table_add(connp->in_tx->request_headers, h->name, h);
    }

    bstr_free(tempstr);

    return HTP_OK;
}