diff --git a/src/output-json-ftp.c b/src/output-json-ftp.c index b8eedf2db7..0bf08daed4 100644 --- a/src/output-json-ftp.c +++ b/src/output-json-ftp.c @@ -37,6 +37,7 @@ #include "util-unittest.h" #include "util-buffer.h" #include "util-debug.h" +#include "util-mem.h" #include "util-byte.h" #include "output.h" @@ -61,6 +62,31 @@ typedef struct LogFTPLogThread_ { MemBuffer *buffer; } LogFTPLogThread; +/* + * \brief Returns the ending offset of the next line. + * + * Here, "next line" is defined as terminating on + * - Newline character + * - Null character + * + * \param buffer Contains zero or more characters. + * \param len Size, in bytes, of buffer. + * + * \retval Offset from the start of buffer indicating the where the + * next "line ends". The characters between the input buffer and this + * value comprise the line. + * + * NULL is found first or a newline isn't found, then + */ +static uint16_t JsonGetNextLineFromBuffer(const char *buffer, const uint16_t len) +{ + if (!buffer || *buffer == '\0') + return UINT16_MAX; + + char *c = strchr(buffer, '\n'); + return c == NULL ? len : c - buffer + 1; +} + static json_t *JsonFTPLogCommand(Flow *f, FTPTransaction *tx) { json_t *cjs = json_object(); @@ -99,21 +125,29 @@ static json_t *JsonFTPLogCommand(Flow *f, FTPTransaction *tx) if (!TAILQ_EMPTY(&tx->response_list)) { FTPString *response; TAILQ_FOREACH(response, &tx->response_list, next) { - int offset = 0; - /* Try to find a completion code if we haven't seen one */ - if (response->len >= 3) { - /* Gather the completion code if present */ - if (isdigit(response->str[0]) && isdigit(response->str[1]) && isdigit(response->str[2])) { - json_array_append_new(js_respcode_list, - JsonAddStringN((const char *)response->str , 3)); - offset = 4; + /* handle multiple lines within the response, \r\n delimited */ + uint8_t *where = response->str; + uint16_t length = response->len; + uint16_t pos; + while ((pos = JsonGetNextLineFromBuffer((const char *)where, length)) != UINT16_MAX) { + uint16_t offset = 0; + /* Try to find a completion code for this line */ + if (pos >= 3) { + /* Gather the completion code if present */ + if (isdigit(where[0]) && isdigit(where[1]) && isdigit(where[2])) { + json_array_append_new(js_respcode_list, + JsonAddStringN((const char *)where, 3)); + offset = 4; + } } - } - /* move past 3 character completion code */ - if (response->len >= offset) { - json_array_append_new(js_resplist, - JsonAddStringN((const char *)response->str + offset, - response->len - offset)); + /* move past 3 character completion code */ + if (pos >= offset) { + json_array_append_new(js_resplist, + JsonAddStringN((const char *)where + offset, pos - offset)); + } + + where += pos; + length -= pos; } } @@ -128,11 +162,11 @@ static json_t *JsonFTPLogCommand(Flow *f, FTPTransaction *tx) if (tx->command_descriptor->command == FTP_COMMAND_PORT || tx->command_descriptor->command == FTP_COMMAND_EPRT) { json_object_set_new(cjs, "mode", - json_string((char*)(tx->active ? "active" : "passive"))); + json_string((char *)(tx->active ? "active" : "passive"))); } json_object_set_new(cjs, "reply_received", - json_string((char*)(tx->done ? "yes" : "no"))); + json_string((char *)(tx->done ? "yes" : "no"))); return cjs; }