mirror of https://github.com/OISF/suricata
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
243 lines
9.5 KiB
C
243 lines
9.5 KiB
C
/* Copyright (C) 2012 BAE Systems
|
|
* Copyright (C) 2021 Open Information Security Foundation
|
|
*
|
|
* You can copy, redistribute or modify this Program under the terms of
|
|
* the GNU General Public License version 2 as published by the Free
|
|
* Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* version 2 along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*/
|
|
|
|
/**
|
|
* \file
|
|
*
|
|
* \author David Abarbanel <david.abarbanel@baesystems.com>
|
|
*
|
|
*/
|
|
|
|
#ifndef MIME_DECODE_H_
|
|
#define MIME_DECODE_H_
|
|
|
|
#include "conf.h"
|
|
#include "util-base64.h"
|
|
#include "util-file.h"
|
|
|
|
/* Content Flags */
|
|
#define CTNT_IS_MSG 1
|
|
#define CTNT_IS_ENV 2
|
|
#define CTNT_IS_ENCAP 4
|
|
#define CTNT_IS_BODYPART 8
|
|
#define CTNT_IS_MULTIPART 16
|
|
#define CTNT_IS_ATTACHMENT 32
|
|
#define CTNT_IS_BASE64 64
|
|
#define CTNT_IS_QP 128
|
|
#define CTNT_IS_TEXT 256
|
|
#define CTNT_IS_HTML 512
|
|
|
|
/* URL Flags */
|
|
#define URL_IS_IP4 1
|
|
#define URL_IS_IP6 2
|
|
#define URL_IS_EXE 4
|
|
|
|
/* Anomaly Flags */
|
|
#define ANOM_INVALID_BASE64 1 /* invalid base64 chars */
|
|
#define ANOM_INVALID_QP 2 /* invalid quoted-printable chars */
|
|
#define ANOM_LONG_HEADER_NAME 4 /* header is abnormally long */
|
|
#define ANOM_LONG_HEADER_VALUE 8 /* header value is abnormally long
|
|
* (includes multi-line) */
|
|
#define ANOM_LONG_LINE 16 /* Lines that exceed 998 octets */
|
|
#define ANOM_LONG_ENC_LINE 32 /* Lines that exceed 76 octets */
|
|
#define ANOM_MALFORMED_MSG 64 /* Misc msg format errors found */
|
|
#define ANOM_LONG_BOUNDARY 128 /* Boundary too long */
|
|
#define ANOM_LONG_FILENAME 256 /* filename truncated */
|
|
|
|
/* Publicly exposed size constants */
|
|
#define DATA_CHUNK_SIZE 3072 /* Should be divisible by 3 */
|
|
|
|
/* Mime Parser Constants */
|
|
#define HEADER_READY 0x01
|
|
#define HEADER_STARTED 0x02
|
|
#define HEADER_DONE 0x03
|
|
#define BODY_STARTED 0x04
|
|
#define BODY_DONE 0x05
|
|
#define BODY_END_BOUND 0x06
|
|
#define PARSE_DONE 0x07
|
|
#define PARSE_ERROR 0x08
|
|
|
|
/**
|
|
* \brief Mime Decoder Error Codes
|
|
*/
|
|
typedef enum MimeDecRetCode {
|
|
MIME_DEC_OK = 0,
|
|
MIME_DEC_MORE = 1,
|
|
MIME_DEC_ERR_DATA = -1,
|
|
MIME_DEC_ERR_MEM = -2,
|
|
MIME_DEC_ERR_PARSE = -3,
|
|
MIME_DEC_ERR_STATE = -4, /**< parser in error state */
|
|
MIME_DEC_ERR_OVERFLOW = -5,
|
|
} MimeDecRetCode;
|
|
|
|
/**
|
|
* \brief Structure for containing configuration options
|
|
*
|
|
*/
|
|
typedef struct MimeDecConfig {
|
|
bool decode_base64; /**< Decode base64 bodies */
|
|
bool decode_quoted_printable; /**< Decode quoted-printable bodies */
|
|
bool extract_urls; /**< Extract and store URLs in data structure */
|
|
ConfNode *extract_urls_schemes; /**< List of schemes of which to
|
|
extract urls */
|
|
bool log_url_scheme; /**< Log the scheme of extracted URLs */
|
|
bool body_md5; /**< Compute md5 sum of body */
|
|
uint32_t header_value_depth; /**< Depth of which to store header values
|
|
(Default is 2000) */
|
|
} MimeDecConfig;
|
|
|
|
/**
|
|
* \brief This represents a header field name and associated value
|
|
*/
|
|
typedef struct MimeDecField {
|
|
uint8_t *name; /**< Name of the header field */
|
|
uint32_t name_len; /**< Length of the name */
|
|
uint32_t value_len; /**< Length of the value */
|
|
uint8_t *value; /**< Value of the header field */
|
|
struct MimeDecField *next; /**< Pointer to next field */
|
|
} MimeDecField;
|
|
|
|
/**
|
|
* \brief This represents a URL value node in a linked list
|
|
*
|
|
* Since HTML can sometimes contain a high number of URLs, this
|
|
* structure only features the URL host name/IP or those that are
|
|
* pointing to an executable file (see url_flags to determine which).
|
|
*/
|
|
typedef struct MimeDecUrl {
|
|
uint8_t *url; /**< String representation of full or partial URL (lowercase) */
|
|
uint32_t url_len; /**< Length of the URL string */
|
|
uint32_t url_flags; /**< Flags indicating type of URL */
|
|
struct MimeDecUrl *next; /**< Pointer to next URL */
|
|
} MimeDecUrl;
|
|
|
|
/**
|
|
* \brief This represents the MIME Entity (or also top level message) in a
|
|
* child-sibling tree
|
|
*/
|
|
typedef struct MimeDecEntity {
|
|
MimeDecField *field_list; /**< Pointer to list of header fields */
|
|
MimeDecUrl *url_list; /**< Pointer to list of URLs */
|
|
uint32_t header_flags; /**< Flags indicating header characteristics */
|
|
uint32_t ctnt_flags; /**< Flags indicating type of content */
|
|
uint32_t anomaly_flags; /**< Flags indicating an anomaly in the message */
|
|
uint32_t filename_len; /**< Length of file attachment name */
|
|
uint8_t *filename; /**< Name of file attachment */
|
|
uint8_t *ctnt_type; /**< Quick access pointer to short-hand content type field */
|
|
uint32_t ctnt_type_len; /**< Length of content type field value */
|
|
uint32_t msg_id_len; /**< Quick access pointer to message Id */
|
|
uint8_t *msg_id; /**< Quick access pointer to message Id */
|
|
struct MimeDecEntity *next; /**< Pointer to list of sibling entities */
|
|
struct MimeDecEntity *child; /**< Pointer to list of child entities */
|
|
} MimeDecEntity;
|
|
|
|
/**
|
|
* \brief Structure contains boundary and entity for the current node (entity)
|
|
* in the stack
|
|
*
|
|
*/
|
|
typedef struct MimeDecStackNode {
|
|
MimeDecEntity *data; /**< Pointer to the entity data structure */
|
|
uint8_t *bdef; /**< Copy of boundary definition for child entity */
|
|
uint16_t bdef_len; /**< Boundary length for child entity */
|
|
bool is_encap; /**< Flag indicating entity is encapsulated in message */
|
|
struct MimeDecStackNode *next; /**< Pointer to next item on the stack */
|
|
} MimeDecStackNode;
|
|
|
|
/**
|
|
* \brief Structure holds the top of the stack along with some free reusable nodes
|
|
*
|
|
*/
|
|
typedef struct MimeDecStack {
|
|
MimeDecStackNode *top; /**< Pointer to the top of the stack */
|
|
MimeDecStackNode *free_nodes; /**< Pointer to the list of free nodes */
|
|
uint32_t free_nodes_cnt; /**< Count of free nodes in the list */
|
|
} MimeDecStack;
|
|
|
|
/**
|
|
* \brief Structure contains a list of value and lengths for robust data processing
|
|
*
|
|
*/
|
|
typedef struct DataValue {
|
|
uint8_t *value; /**< Copy of data value */
|
|
uint32_t value_len; /**< Length of data value */
|
|
struct DataValue *next; /**< Pointer to next value in the list */
|
|
} DataValue;
|
|
|
|
/**
|
|
* \brief Structure contains the current state of the MIME parser
|
|
*
|
|
*/
|
|
typedef struct MimeDecParseState {
|
|
MimeDecEntity *msg; /**< Pointer to the top-level message entity */
|
|
MimeDecStack *stack; /**< Pointer to the top of the entity stack */
|
|
uint8_t *hname; /**< Copy of the last known header name */
|
|
uint32_t hlen; /**< Length of the last known header name */
|
|
uint32_t hvlen; /**< Total length of value list */
|
|
DataValue *hvalue; /**< Pointer to the incomplete header value list */
|
|
uint8_t bvremain[B64_BLOCK]; /**< Remainder from base64-decoded line */
|
|
uint8_t bvr_len; /**< Length of remainder from base64-decoded line */
|
|
uint8_t data_chunk[DATA_CHUNK_SIZE]; /**< Buffer holding data chunk */
|
|
SCMd5 *md5_ctx;
|
|
uint8_t md5[SC_MD5_LEN];
|
|
bool has_md5;
|
|
uint8_t state_flag; /**< Flag representing current state of parser */
|
|
uint32_t data_chunk_len; /**< Length of data chunk */
|
|
int found_child; /**< Flag indicating a child entity was found */
|
|
int body_begin; /**< Currently at beginning of body */
|
|
int body_end; /**< Currently at end of body */
|
|
uint8_t current_line_delimiter_len; /**< Length of line delimiter */
|
|
void *data; /**< Pointer to data specific to the caller */
|
|
int (*DataChunkProcessorFunc) (const uint8_t *chunk, uint32_t len,
|
|
struct MimeDecParseState *state); /**< Data chunk processing function callback */
|
|
} MimeDecParseState;
|
|
|
|
/* Config functions */
|
|
void MimeDecSetConfig(MimeDecConfig *config);
|
|
MimeDecConfig * MimeDecGetConfig(void);
|
|
|
|
/* Memory functions */
|
|
void MimeDecFreeEntity(MimeDecEntity *entity);
|
|
void MimeDecFreeField(MimeDecField *field);
|
|
void MimeDecFreeUrl(MimeDecUrl *url);
|
|
|
|
/* List functions */
|
|
MimeDecField * MimeDecAddField(MimeDecEntity *entity);
|
|
MimeDecField * MimeDecFindField(const MimeDecEntity *entity, const char *name);
|
|
int MimeDecFindFieldsForEach(const MimeDecEntity *entity, const char *name, int (*DataCallback)(const uint8_t *val, const size_t, void *data), void *data);
|
|
MimeDecEntity * MimeDecAddEntity(MimeDecEntity *parent);
|
|
|
|
/* Helper functions */
|
|
//MimeDecField * MimeDecFillField(MimeDecEntity *entity, const char *name,
|
|
// uint32_t nlen, const char *value, uint32_t vlen, int copy_name_value);
|
|
|
|
/* Parser functions */
|
|
MimeDecParseState * MimeDecInitParser(void *data, int (*dcpfunc)(const uint8_t *chunk,
|
|
uint32_t len, MimeDecParseState *state));
|
|
void MimeDecDeInitParser(MimeDecParseState *state);
|
|
int MimeDecParseComplete(MimeDecParseState *state);
|
|
int MimeDecParseLine(const uint8_t *line, const uint32_t len, const uint8_t delim_len, MimeDecParseState *state);
|
|
MimeDecEntity * MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *data,
|
|
int (*DataChunkProcessorFunc)(const uint8_t *chunk, uint32_t len, MimeDecParseState *state));
|
|
const char *MimeDecParseStateGetStatus(MimeDecParseState *state);
|
|
|
|
/* Test functions */
|
|
void MimeDecRegisterTests(void);
|
|
|
|
#endif
|