*
* \author Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
* \author Eric Leblond <eric@regit.org>
- * \author Jeff Lucovsky <jeff@lucovsky.org>
+ * \author Jeff Lucovsky <jlucovsky@oisf.net>
*
* App Layer Parser for FTP
*/
static void *FTPRealloc(void *ptr, size_t orig_size, size_t size)
{
- void *rptr = NULL;
-
+ DEBUG_VALIDATE_BUG_ON(size == 0);
if (FTPCheckMemcap((uint32_t)(size - orig_size)) == 0) {
sc_errno = SC_ELIMIT;
return NULL;
}
- rptr = SCRealloc(ptr, size);
+ void *rptr = SCRealloc(ptr, size);
if (rptr == NULL) {
sc_errno = SC_ENOMEM;
return NULL;
FTPDecrMemuse((uint64_t)size);
}
-static FTPString *FTPStringAlloc(void)
+static FTPResponseWrapper *FTPResponseWrapperAlloc(FTPResponseLine *response)
{
- return FTPCalloc(1, sizeof(FTPString));
+ FTPResponseWrapper *wrapper = FTPCalloc(1, sizeof(FTPResponseWrapper));
+ if (likely(wrapper)) {
+ FTPIncrMemuse(response->total_size);
+ wrapper->response = response;
+ }
+ return wrapper;
}
-static void FTPStringFree(FTPString *str)
+static void FTPResponseWrapperFree(FTPResponseWrapper *wrapper)
{
- if (str->str) {
- FTPFree(str->str, str->len);
+ if (wrapper->response) {
+ FTPDecrMemuse(wrapper->response->total_size);
+ SCFTPFreeResponseLine(wrapper->response);
}
- FTPFree(str, sizeof(FTPString));
+ FTPFree(wrapper, sizeof(FTPResponseWrapper));
}
static void *FTPLocalStorageAlloc(void)
FTPFree(tx->request, tx->request_length);
}
- FTPString *str = NULL;
- while ((str = TAILQ_FIRST(&tx->response_list))) {
- TAILQ_REMOVE(&tx->response_list, str, next);
- FTPStringFree(str);
+ FTPResponseWrapper *wrapper;
+ while ((wrapper = TAILQ_FIRST(&tx->response_list))) {
+ TAILQ_REMOVE(&tx->response_list, wrapper, next);
+ FTPResponseWrapperFree(wrapper);
}
FTPFree(tx, sizeof(*tx));
}
if (likely(line.len)) {
- FTPString *response = FTPStringAlloc();
+ FTPResponseLine *response = SCFTPParseResponseLine((const char *)line.buf, line.len);
if (likely(response)) {
- response->len = CopyCommandLine(&response->str, &line);
- response->truncated = state->current_line_truncated_tc;
- if (response->truncated) {
- AppLayerDecoderEventsSetEventRaw(
- &tx->tx_data.events, FtpEventResponseCommandTooLong);
- }
- if (line.lf_found) {
- state->current_line_truncated_tc = false;
+ FTPResponseWrapper *wrapper = FTPResponseWrapperAlloc(response);
+ if (likely(wrapper)) {
+ response->truncated = state->current_line_truncated_tc;
+ if (response->truncated) {
+ AppLayerDecoderEventsSetEventRaw(
+ &tx->tx_data.events, FtpEventResponseCommandTooLong);
+ }
+ if (line.lf_found) {
+ state->current_line_truncated_tc = false;
+ }
+ TAILQ_INSERT_TAIL(&tx->response_list, wrapper, next);
+ } else {
+ SCFTPFreeResponseLine(response);
}
- TAILQ_INSERT_TAIL(&tx->response_list, response, next);
+ } else {
+ SCLogDebug("unable to parse FTP response line \"%s\"", line.buf);
}
}
if (!TAILQ_EMPTY(&tx->response_list)) {
int resp_cnt = 0;
- FTPString *response;
+ FTPResponseWrapper *wrapper;
bool is_cc_array_open = false;
- TAILQ_FOREACH(response, &tx->response_list, next) {
+ TAILQ_FOREACH (wrapper, &tx->response_list, next) {
/* handle multiple lines within the response, \r\n delimited */
- uint8_t *where = response->str;
- uint16_t length = 0;
- uint16_t pos;
- if (response->len > 0 && response->len <= UINT16_MAX) {
- length = (uint16_t)response->len - 1;
- } else if (response->len > UINT16_MAX) {
- length = UINT16_MAX;
+ if (!wrapper->response) {
+ continue;
}
+ FTPResponseLine *response = wrapper->response;
+
if (!reply_truncated && response->truncated) {
reply_truncated = true;
}
- 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])) {
- if (!is_cc_array_open) {
- SCJbOpenArray(jb, "completion_code");
- is_cc_array_open = true;
- }
- SCJbAppendStringFromBytes(jb, (const uint8_t *)where, 3);
- offset = 4;
- }
- }
- /* move past 3 character completion code */
- if (pos >= offset) {
- SCJbAppendStringFromBytes(
- js_resplist, (const uint8_t *)where + offset, pos - offset);
- resp_cnt++;
+ int code_len = strlen((const char *)response->code);
+ if (code_len > 0) {
+ if (!is_cc_array_open) {
+ SCJbOpenArray(jb, "completion_code");
+ is_cc_array_open = true;
}
-
- where += pos;
- length -= pos;
+ SCJbAppendStringFromBytes(jb, (const uint8_t *)response->code, code_len);
+ }
+ if (response->length) {
+ SCJbAppendStringFromBytes(
+ js_resplist, (const uint8_t *)response->response, response->length);
+ resp_cnt++;
}
}