suricata
app-layer-ftp.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2017 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
22  * \author Eric Leblond <eric@regit.org>
23  * \author Jeff Lucovsky <jeff@lucovsky.org>
24  *
25  * App Layer Parser for FTP
26  */
27 
28 #include "suricata-common.h"
29 #include "debug.h"
30 #include "decode.h"
31 #include "threads.h"
32 
33 #include "util-print.h"
34 #include "util-pool.h"
35 
36 #include "flow-util.h"
37 #include "flow-storage.h"
38 
39 #include "detect-engine-state.h"
40 
41 #include "stream-tcp-private.h"
42 #include "stream-tcp-reassemble.h"
43 #include "stream-tcp.h"
44 #include "stream.h"
45 
46 #include "app-layer.h"
47 #include "app-layer-protos.h"
48 #include "app-layer-parser.h"
49 #include "app-layer-ftp.h"
50 #include "app-layer-expectation.h"
51 
52 #include "util-spm.h"
53 #include "util-mpm.h"
54 #include "util-unittest.h"
55 #include "util-debug.h"
56 #include "util-memcmp.h"
57 #include "util-memrchr.h"
58 #include "util-byte.h"
59 #include "util-mem.h"
60 #include "util-misc.h"
61 
62 #include "rust-ftp-mod-gen.h"
63 
64 #include "output-json.h"
65 
66 typedef struct FTPThreadCtx_ {
69 } FTPThreadCtx;
70 
71 #define FTP_MPM mpm_default_matcher
72 
73 static MpmCtx *ftp_mpm_ctx = NULL;
74 
76  /* Parsed and handled */
77  { FTP_COMMAND_PORT, "PORT", 4},
78  { FTP_COMMAND_EPRT, "EPRT", 4},
79  { FTP_COMMAND_AUTH_TLS, "AUTH TLS", 8},
80  { FTP_COMMAND_PASV, "PASV", 4},
81  { FTP_COMMAND_RETR, "RETR", 4},
82  { FTP_COMMAND_EPSV, "EPSV", 4},
83  { FTP_COMMAND_STOR, "STOR", 4},
84 
85  /* Parsed, but not handled */
86  { FTP_COMMAND_ABOR, "ABOR", 4},
87  { FTP_COMMAND_ACCT, "ACCT", 4},
88  { FTP_COMMAND_ALLO, "ALLO", 4},
89  { FTP_COMMAND_APPE, "APPE", 4},
90  { FTP_COMMAND_CDUP, "CDUP", 4},
91  { FTP_COMMAND_CHMOD, "CHMOD", 5},
92  { FTP_COMMAND_CWD, "CWD", 3},
93  { FTP_COMMAND_DELE, "DELE", 4},
94  { FTP_COMMAND_HELP, "HELP", 4},
95  { FTP_COMMAND_IDLE, "IDLE", 4},
96  { FTP_COMMAND_LIST, "LIST", 4},
97  { FTP_COMMAND_MAIL, "MAIL", 4},
98  { FTP_COMMAND_MDTM, "MDTM", 4},
99  { FTP_COMMAND_MKD, "MKD", 3},
100  { FTP_COMMAND_MLFL, "MLFL", 4},
101  { FTP_COMMAND_MODE, "MODE", 4},
102  { FTP_COMMAND_MRCP, "MRCP", 4},
103  { FTP_COMMAND_MRSQ, "MRSQ", 4},
104  { FTP_COMMAND_MSAM, "MSAM", 4},
105  { FTP_COMMAND_MSND, "MSND", 4},
106  { FTP_COMMAND_MSOM, "MSOM", 4},
107  { FTP_COMMAND_NLST, "NLST", 4},
108  { FTP_COMMAND_NOOP, "NOOP", 4},
109  { FTP_COMMAND_PASS, "PASS", 4},
110  { FTP_COMMAND_PWD, "PWD", 3},
111  { FTP_COMMAND_QUIT, "QUIT", 4},
112  { FTP_COMMAND_REIN, "REIN", 4},
113  { FTP_COMMAND_REST, "REST", 4},
114  { FTP_COMMAND_RMD, "RMD", 3},
115  { FTP_COMMAND_RNFR, "RNFR", 4},
116  { FTP_COMMAND_RNTO, "RNTO", 4},
117  { FTP_COMMAND_SITE, "SITE", 4},
118  { FTP_COMMAND_SIZE, "SIZE", 4},
119  { FTP_COMMAND_SMNT, "SMNT", 4},
120  { FTP_COMMAND_STAT, "STAT", 4},
121  { FTP_COMMAND_STOU, "STOU", 4},
122  { FTP_COMMAND_STRU, "STRU", 4},
123  { FTP_COMMAND_SYST, "SYST", 4},
124  { FTP_COMMAND_TYPE, "TYPE", 4},
125  { FTP_COMMAND_UMASK, "UMASK", 5},
126  { FTP_COMMAND_USER, "USER", 4},
127  { FTP_COMMAND_UNKNOWN, NULL, 0}
128 };
129 uint64_t ftp_config_memcap = 0;
130 
131 SC_ATOMIC_DECLARE(uint64_t, ftp_memuse);
132 SC_ATOMIC_DECLARE(uint64_t, ftp_memcap);
133 
134 static FTPTransaction *FTPGetOldestTx(FtpState *);
135 
136 static void FTPParseMemcap(void)
137 {
138  const char *conf_val;
139 
140  /** set config values for memcap, prealloc and hash_size */
141  if ((ConfGet("app-layer.protocols.ftp.memcap", &conf_val)) == 1)
142  {
143  if (ParseSizeStringU64(conf_val, &ftp_config_memcap) < 0) {
144  SCLogError(SC_ERR_SIZE_PARSE, "Error parsing ftp.memcap "
145  "from conf file - %s. Killing engine",
146  conf_val);
147  exit(EXIT_FAILURE);
148  }
149  SCLogInfo("FTP memcap: %"PRIu64, ftp_config_memcap);
150  } else {
151  /* default to unlimited */
152  ftp_config_memcap = 0;
153  }
154 
155  SC_ATOMIC_INIT(ftp_memuse);
156  SC_ATOMIC_INIT(ftp_memcap);
157 }
158 
159 static void FTPIncrMemuse(uint64_t size)
160 {
161  (void) SC_ATOMIC_ADD(ftp_memuse, size);
162  return;
163 }
164 
165 static void FTPDecrMemuse(uint64_t size)
166 {
167  (void) SC_ATOMIC_SUB(ftp_memuse, size);
168  return;
169 }
170 
172 {
173  uint64_t tmpval = SC_ATOMIC_GET(ftp_memuse);
174  return tmpval;
175 }
176 
178 {
179  uint64_t tmpval = SC_ATOMIC_GET(ftp_memcap);
180  return tmpval;
181 }
182 
183 /**
184  * \brief Check if alloc'ing "size" would mean we're over memcap
185  *
186  * \retval 1 if in bounds
187  * \retval 0 if not in bounds
188  */
189 static int FTPCheckMemcap(uint64_t size)
190 {
191  if (ftp_config_memcap == 0 || size + SC_ATOMIC_GET(ftp_memuse) <= ftp_config_memcap)
192  return 1;
193  (void) SC_ATOMIC_ADD(ftp_memcap, 1);
194  return 0;
195 }
196 
197 static void *FTPMalloc(size_t size)
198 {
199  void *ptr = NULL;
200 
201  if (FTPCheckMemcap((uint32_t)size) == 0)
202  return NULL;
203 
204  ptr = SCMalloc(size);
205 
206  if (unlikely(ptr == NULL))
207  return NULL;
208 
209  FTPIncrMemuse((uint64_t)size);
210 
211  return ptr;
212 }
213 
214 static void *FTPCalloc(size_t n, size_t size)
215 {
216  void *ptr = NULL;
217 
218  if (FTPCheckMemcap((uint32_t)(n * size)) == 0)
219  return NULL;
220 
221  ptr = SCCalloc(n, size);
222 
223  if (unlikely(ptr == NULL))
224  return NULL;
225 
226  FTPIncrMemuse((uint64_t)(n * size));
227 
228  return ptr;
229 }
230 
231 static void *FTPRealloc(void *ptr, size_t orig_size, size_t size)
232 {
233  void *rptr = NULL;
234 
235  if (FTPCheckMemcap((uint32_t)(size - orig_size)) == 0)
236  return NULL;
237 
238  rptr = SCRealloc(ptr, size);
239  if (rptr == NULL)
240  return NULL;
241 
242  if (size > orig_size) {
243  FTPIncrMemuse(size - orig_size);
244  } else {
245  FTPDecrMemuse(orig_size - size);
246  }
247 
248  return rptr;
249 }
250 
251 static void FTPFree(void *ptr, size_t size)
252 {
253  SCFree(ptr);
254 
255  FTPDecrMemuse((uint64_t)size);
256 }
257 
258 static FTPString *FTPStringAlloc(void)
259 {
260  return FTPCalloc(1, sizeof(FTPString));
261 }
262 
263 static void FTPStringFree(FTPString *str)
264 {
265  if (str->str) {
266  FTPFree(str->str, str->len);
267  }
268 
269  FTPFree(str, sizeof(FTPString));
270 }
271 
272 static void *FTPLocalStorageAlloc(void)
273 {
274  /* needed by the mpm */
275  FTPThreadCtx *td = SCCalloc(1, sizeof(*td));
276  if (td == NULL) {
277  exit(EXIT_FAILURE);
278  }
279 
280  td->pmq = SCCalloc(1, sizeof(*td->pmq));
281  if (td->pmq == NULL) {
282  exit(EXIT_FAILURE);
283  }
284  PmqSetup(td->pmq);
285 
286  td->ftp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx));
287  if (unlikely(td->ftp_mpm_thread_ctx == NULL)) {
288  exit(EXIT_FAILURE);
289  }
291  return td;
292 }
293 
294 static void FTPLocalStorageFree(void *ptr)
295 {
296  FTPThreadCtx *td = ptr;
297  if (td != NULL) {
298  if (td->pmq != NULL) {
299  PmqFree(td->pmq);
300  SCFree(td->pmq);
301  }
302 
303  if (td->ftp_mpm_thread_ctx != NULL) {
306  }
307 
308  SCFree(td);
309  }
310 
311  return;
312 }
313 static FTPTransaction *FTPTransactionCreate(FtpState *state)
314 {
315  SCEnter();
316  FTPTransaction *tx = FTPCalloc(1, sizeof(*tx));
317  if (tx == NULL) {
318  return NULL;
319  }
320 
321  TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
322  tx->tx_id = state->tx_cnt++;
323 
324  TAILQ_INIT(&tx->response_list);
325 
326  SCLogDebug("new transaction %p (state tx cnt %"PRIu64")", tx, state->tx_cnt);
327  return tx;
328 }
329 
330 static void FTPTransactionFree(FTPTransaction *tx)
331 {
332  SCEnter();
333 
334  if (tx->de_state != NULL) {
336  }
337 
338  if (tx->request) {
339  FTPFree(tx->request, tx->request_length);
340  }
341 
342  FTPString *str = NULL;
343  while ((str = TAILQ_FIRST(&tx->response_list))) {
344  TAILQ_REMOVE(&tx->response_list, str, next);
345  FTPStringFree(str);
346  }
347 
348  SCFree(tx);
349 }
350 
351 static int FTPGetLineForDirection(FtpState *state, FtpLineState *line_state)
352 {
353  void *ptmp;
354  if (line_state->current_line_lf_seen == 1) {
355  /* we have seen the lf for the previous line. Clear the parser
356  * details to parse new line */
357  line_state->current_line_lf_seen = 0;
358  if (line_state->current_line_db == 1) {
359  line_state->current_line_db = 0;
360  FTPFree(line_state->db, line_state->db_len);
361  line_state->db = NULL;
362  line_state->db_len = 0;
363  state->current_line = NULL;
364  state->current_line_len = 0;
365  }
366  }
367 
368  uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len);
369 
370  if (lf_idx == NULL) {
371  /* fragmented lines. Decoder event for special cases. Not all
372  * fragmented lines should be treated as a possible evasion
373  * attempt. With multi payload ftp chunks we can have valid
374  * cases of fragmentation. But within the same segment chunk
375  * if we see fragmentation then it's definitely something you
376  * should alert about */
377  if (line_state->current_line_db == 0) {
378  line_state->db = FTPMalloc(state->input_len);
379  if (line_state->db == NULL) {
380  return -1;
381  }
382  line_state->current_line_db = 1;
383  memcpy(line_state->db, state->input, state->input_len);
384  line_state->db_len = state->input_len;
385  } else {
386  ptmp = FTPRealloc(line_state->db, line_state->db_len,
387  (line_state->db_len + state->input_len));
388  if (ptmp == NULL) {
389  FTPFree(line_state->db, line_state->db_len);
390  line_state->db = NULL;
391  line_state->db_len = 0;
392  return -1;
393  }
394  line_state->db = ptmp;
395 
396  memcpy(line_state->db + line_state->db_len,
397  state->input, state->input_len);
398  line_state->db_len += state->input_len;
399  }
400  state->input += state->input_len;
401  state->input_len = 0;
402 
403  return -1;
404 
405  } else {
406  line_state->current_line_lf_seen = 1;
407 
408  if (line_state->current_line_db == 1) {
409  ptmp = FTPRealloc(line_state->db, line_state->db_len,
410  (line_state->db_len + (lf_idx + 1 - state->input)));
411  if (ptmp == NULL) {
412  FTPFree(line_state->db, line_state->db_len);
413  line_state->db = NULL;
414  line_state->db_len = 0;
415  return -1;
416  }
417  line_state->db = ptmp;
418 
419  memcpy(line_state->db + line_state->db_len,
420  state->input, (lf_idx + 1 - state->input));
421  line_state->db_len += (lf_idx + 1 - state->input);
422 
423  if (line_state->db_len > 1 &&
424  line_state->db[line_state->db_len - 2] == 0x0D) {
425  line_state->db_len -= 2;
426  state->current_line_delimiter_len = 2;
427  } else {
428  line_state->db_len -= 1;
429  state->current_line_delimiter_len = 1;
430  }
431 
432  state->current_line = line_state->db;
433  state->current_line_len = line_state->db_len;
434 
435  } else {
436  state->current_line = state->input;
437  state->current_line_len = lf_idx - state->input;
438 
439  if (state->input != lf_idx &&
440  *(lf_idx - 1) == 0x0D) {
441  state->current_line_len--;
442  state->current_line_delimiter_len = 2;
443  } else {
444  state->current_line_delimiter_len = 1;
445  }
446  }
447 
448  state->input_len -= (lf_idx - state->input) + 1;
449  state->input = (lf_idx + 1);
450 
451  return 0;
452  }
453 
454 }
455 
456 static int FTPGetLine(FtpState *state)
457 {
458  SCEnter();
459 
460  /* we have run out of input */
461  if (state->input_len <= 0)
462  return -1;
463 
464  /* toserver */
465  if (state->direction == 0)
466  return FTPGetLineForDirection(state, &state->line_state[0]);
467  else
468  return FTPGetLineForDirection(state, &state->line_state[1]);
469 }
470 
471 /**
472  * \brief This function is called to determine and set which command is being
473  * transferred to the ftp server
474  * \param thread context
475  * \param input input line of the command
476  * \param len of the command
477  * \param cmd_descriptor when the command has been parsed
478  *
479  * \retval 1 when the command is parsed, 0 otherwise
480  */
481 static int FTPParseRequestCommand(FTPThreadCtx *td,
482  const uint8_t *input, uint32_t input_len,
483  const FtpCommand **cmd_descriptor)
484 {
485  SCEnter();
486 
487  /* I don't like this pmq reset here. We'll devise a method later, that
488  * should make the use of the mpm very efficient */
489  PmqReset(td->pmq);
490  int mpm_cnt = mpm_table[FTP_MPM].Search(ftp_mpm_ctx, td->ftp_mpm_thread_ctx,
491  td->pmq, input, input_len);
492  if (mpm_cnt) {
493  *cmd_descriptor = &FtpCommands[td->pmq->rule_id_array[0]];
494  SCReturnInt(1);
495  }
496 
497  *cmd_descriptor = NULL;
498  SCReturnInt(0);
499 }
500 
502  /** Need to look like a ExpectationData so DFree must
503  * be first field . */
504  void (*DFree)(void *);
505  uint64_t flow_id;
506  uint8_t *file_name;
507  uint16_t file_len;
509 };
510 
511 static void FtpTransferCmdFree(void *data)
512 {
513  struct FtpTransferCmd *cmd = (struct FtpTransferCmd *) data;
514  if (cmd == NULL)
515  return;
516  if (cmd->file_name) {
517  FTPFree(cmd->file_name, cmd->file_len);
518  }
519  FTPFree(cmd, sizeof(struct FtpTransferCmd));
520 }
521 
522 static uint32_t CopyCommandLine(uint8_t **dest, const uint8_t *src, uint32_t length)
523 {
524  if (likely(length)) {
525  uint8_t *where = FTPCalloc(length + 1, sizeof(char));
526  if (unlikely(where == NULL)) {
527  return 0;
528  }
529  memcpy(where, src, length);
530 
531  /* Remove trailing newlines/carriage returns */
532  while (length && isspace((unsigned char) where[length - 1])) {
533  length--;
534  }
535 
536  where[length] = '\0';
537  *dest = where;
538  }
539  /* either 0 or actual */
540  return length;
541 }
542 
543 
544 /**
545  * \brief This function is called to retrieve a ftp request
546  * \param ftp_state the ftp state structure for the parser
547  * \param input input line of the command
548  * \param input_len length of the request
549  * \param output the resulting output
550  *
551  * \retval 1 when the command is parsed, 0 otherwise
552  */
553 static int FTPParseRequest(Flow *f, void *ftp_state,
554  AppLayerParserState *pstate,
555  const uint8_t *input, uint32_t input_len,
556  void *local_data, const uint8_t flags)
557 {
558  FTPThreadCtx *thread_data = local_data;
559 
560  SCEnter();
561  /* PrintRawDataFp(stdout, input,input_len); */
562 
563  FtpState *state = (FtpState *)ftp_state;
564  void *ptmp;
565 
566  if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
567  SCReturnInt(1);
568  } else if (input == NULL || input_len == 0) {
569  SCReturnInt(-1);
570  }
571 
572  state->input = input;
573  state->input_len = input_len;
574  /* toserver stream */
575  state->direction = 0;
576 
577  int direction = STREAM_TOSERVER;
578  while (FTPGetLine(state) >= 0) {
579  const FtpCommand *cmd_descriptor;
580 
581  if (!FTPParseRequestCommand(thread_data, state->current_line, state->current_line_len, &cmd_descriptor)) {
582  state->command = FTP_COMMAND_UNKNOWN;
583  continue;
584  }
585 
586  state->command = cmd_descriptor->command;
587 
588  FTPTransaction *tx = FTPTransactionCreate(state);
589  if (unlikely(tx == NULL))
590  return -1;
591  state->curr_tx = tx;
592 
593  tx->command_descriptor = cmd_descriptor;
594  tx->request_length = CopyCommandLine(&tx->request, state->current_line, state->current_line_len);
595 
596  switch (state->command) {
597  case FTP_COMMAND_EPRT:
598  // fallthrough
599  case FTP_COMMAND_PORT:
600  if (state->current_line_len + 1 > state->port_line_size) {
601  /* Allocate an extra byte for a NULL terminator */
602  ptmp = FTPRealloc(state->port_line, state->port_line_size,
603  state->current_line_len);
604  if (ptmp == NULL) {
605  if (state->port_line) {
606  FTPFree(state->port_line, state->port_line_size);
607  state->port_line = NULL;
608  state->port_line_size = 0;
609  }
610  return 0;
611  }
612  state->port_line = ptmp;
613  state->port_line_size = state->current_line_len;
614  }
615  memcpy(state->port_line, state->current_line,
616  state->current_line_len);
617  state->port_line_len = state->current_line_len;
618  break;
619  case FTP_COMMAND_RETR:
620  /* change direction (default to server) so expectation will handle
621  * the correct message when expectation will match.
622  */
623  direction = STREAM_TOCLIENT;
624  // fallthrough
625  case FTP_COMMAND_STOR:
626  {
627  /* Ensure that there is a negotiated dyn port and a file
628  * name -- need more than 5 chars: cmd [4], space, <filename>
629  */
630  if (state->dyn_port == 0 || state->current_line_len < 6) {
631  SCReturnInt(-1);
632  }
633  struct FtpTransferCmd *data = FTPCalloc(1, sizeof(struct FtpTransferCmd));
634  if (data == NULL)
635  SCReturnInt(-1);
636  data->DFree = FtpTransferCmdFree;
637  /* Min size has been checked in FTPParseRequestCommand */
638  data->file_name = FTPCalloc(state->current_line_len - 4, sizeof(char));
639  if (data->file_name == NULL) {
640  FtpTransferCmdFree(data);
641  SCReturnInt(-1);
642  }
643  data->file_name[state->current_line_len - 5] = 0;
644  data->file_len = state->current_line_len - 5;
645  memcpy(data->file_name, state->current_line + 5, state->current_line_len - 5);
646  data->cmd = state->command;
647  data->flow_id = FlowGetId(f);
648  int ret = AppLayerExpectationCreate(f,
649  state->active ? STREAM_TOSERVER : direction,
650  0, state->dyn_port, ALPROTO_FTPDATA, data);
651  if (ret == -1) {
652  FtpTransferCmdFree(data);
653  SCLogDebug("No expectation created.");
654  SCReturnInt(-1);
655  } else {
656  SCLogDebug("Expectation created [direction: %s, dynamic port %"PRIu16"].",
657  state->active ? "to server" : "to client",
658  state->dyn_port);
659  }
660 
661  /* reset the dyn port to avoid duplicate */
662  state->dyn_port = 0;
663  /* reset active/passive indicator */
664  state->active = false;
665  }
666  break;
667  default:
668  break;
669  }
670  }
671 
672  return 1;
673 }
674 
675 static int FTPParsePassiveResponse(Flow *f, FtpState *state, const uint8_t *input, uint32_t input_len)
676 {
677  uint16_t dyn_port = rs_ftp_pasv_response(input, input_len);
678  if (dyn_port == 0) {
679  return -1;
680  }
681  SCLogDebug("FTP passive mode (v4): dynamic port %"PRIu16"", dyn_port);
682  state->active = false;
683  state->dyn_port = dyn_port;
684  state->curr_tx->dyn_port = dyn_port;
685  state->curr_tx->active = false;
686 
687  return 0;
688 }
689 
690 static int FTPParsePassiveResponseV6(Flow *f, FtpState *state, const uint8_t *input, uint32_t input_len)
691 {
692  uint16_t dyn_port = rs_ftp_epsv_response(input, input_len);
693  if (dyn_port == 0) {
694  return -1;
695  }
696  SCLogDebug("FTP passive mode (v6): dynamic port %"PRIu16"", dyn_port);
697  state->active = false;
698  state->dyn_port = dyn_port;
699  state->curr_tx->dyn_port = dyn_port;
700  state->curr_tx->active = false;
701  return 0;
702 }
703 
704 /**
705  * \brief Handle preliminary replies -- keep tx open
706  * \retval: True for a positive preliminary reply; false otherwise
707  *
708  * 1yz Positive Preliminary reply
709  *
710  * The requested action is being initiated; expect another
711  * reply before proceeding with a new command
712  */
713 static inline bool FTPIsPPR(const uint8_t *input, uint32_t input_len)
714 {
715  return input_len >= 4 && isdigit(input[0]) && input[0] == '1' &&
716  isdigit(input[1]) && isdigit(input[2]) && isspace(input[3]);
717 }
718 
719 /**
720  * \brief This function is called to retrieve a ftp response
721  * \param ftp_state the ftp state structure for the parser
722  * \param input input line of the command
723  * \param input_len length of the request
724  * \param output the resulting output
725  *
726  * \retval 1 when the command is parsed, 0 otherwise
727  */
728 static int FTPParseResponse(Flow *f, void *ftp_state, AppLayerParserState *pstate,
729  const uint8_t *input, uint32_t input_len,
730  void *local_data, const uint8_t flags)
731 {
732  FtpState *state = (FtpState *)ftp_state;
733  int retcode = 1;
734 
735  if (unlikely(input_len == 0)) {
736  return 1;
737  }
738 
739  FTPTransaction *tx = FTPGetOldestTx(state);
740  if (tx == NULL) {
741  tx = FTPTransactionCreate(state);
742  }
743  if (unlikely(tx == NULL)) {
744  return -1;
745  }
746  if (state->command == FTP_COMMAND_UNKNOWN || tx->command_descriptor == NULL) {
747  /* unknown */
748  tx->command_descriptor = &FtpCommands[FTP_COMMAND_MAX -1];
749  }
750 
751  state->curr_tx = tx;
752  if (state->command == FTP_COMMAND_AUTH_TLS) {
753  if (input_len >= 4 && SCMemcmp("234 ", input, 4) == 0) {
755  }
756  }
757 
758  if (state->command == FTP_COMMAND_EPRT) {
759  uint16_t dyn_port = rs_ftp_active_eprt(state->port_line, state->port_line_len);
760  if (dyn_port == 0) {
761  retcode = 0;
762  goto tx_complete;
763  }
764  state->dyn_port = dyn_port;
765  state->active = true;
766  tx->dyn_port = dyn_port;
767  tx->active = true;
768  SCLogDebug("FTP active mode (v6): dynamic port %"PRIu16"", dyn_port);
769  }
770 
771  if (state->command == FTP_COMMAND_PORT) {
772  if ((flags & STREAM_TOCLIENT)) {
773  uint16_t dyn_port = rs_ftp_active_port(state->port_line, state->port_line_len);
774  if (dyn_port == 0) {
775  retcode = 0;
776  goto tx_complete;
777  }
778  state->dyn_port = dyn_port;
779  state->active = true;
780  tx->dyn_port = state->dyn_port;
781  tx->active = true;
782  SCLogDebug("FTP active mode (v4): dynamic port %"PRIu16"", dyn_port);
783  }
784  }
785 
786  if (state->command == FTP_COMMAND_PASV) {
787  if (input_len >= 4 && SCMemcmp("227 ", input, 4) == 0) {
788  FTPParsePassiveResponse(f, ftp_state, input, input_len);
789  }
790  }
791 
792  if (state->command == FTP_COMMAND_EPSV) {
793  if (input_len >= 4 && SCMemcmp("229 ", input, 4) == 0) {
794  FTPParsePassiveResponseV6(f, ftp_state, input, input_len);
795  }
796  }
797 
798  if (likely(input_len)) {
799  FTPString *response = FTPStringAlloc();
800  if (likely(response)) {
801  response->len = CopyCommandLine(&response->str, input, input_len);
802  TAILQ_INSERT_TAIL(&tx->response_list, response, next);
803  }
804  }
805 
806  /* Handle preliminary replies -- keep tx open */
807  if (FTPIsPPR(input, input_len)) {
808  return retcode;
809  }
810 
811 tx_complete:
812  tx->done = true;
813  return retcode;
814 }
815 
816 
817 #ifdef DEBUG
818 static SCMutex ftp_state_mem_lock = SCMUTEX_INITIALIZER;
819 static uint64_t ftp_state_memuse = 0;
820 static uint64_t ftp_state_memcnt = 0;
821 #endif
822 
823 static void *FTPStateAlloc(void)
824 {
825  void *s = FTPCalloc(1, sizeof(FtpState));
826  if (unlikely(s == NULL))
827  return NULL;
828 
829  FtpState *ftp_state = (FtpState *) s;
830  TAILQ_INIT(&ftp_state->tx_list);
831 
832 #ifdef DEBUG
833  SCMutexLock(&ftp_state_mem_lock);
834  ftp_state_memcnt++;
835  ftp_state_memuse+=sizeof(FtpState);
836  SCMutexUnlock(&ftp_state_mem_lock);
837 #endif
838  return s;
839 }
840 
841 static void FTPStateFree(void *s)
842 {
843  FtpState *fstate = (FtpState *) s;
844  if (fstate->port_line != NULL)
845  FTPFree(fstate->port_line, fstate->port_line_size);
846  if (fstate->line_state[0].db)
847  FTPFree(fstate->line_state[0].db, fstate->line_state[0].db_len);
848  if (fstate->line_state[1].db)
849  FTPFree(fstate->line_state[1].db, fstate->line_state[1].db_len);
850 
851  //AppLayerDecoderEventsFreeEvents(&s->decoder_events);
852 
853  FTPTransaction *tx = NULL;
854  while ((tx = TAILQ_FIRST(&fstate->tx_list))) {
855  TAILQ_REMOVE(&fstate->tx_list, tx, next);
856  SCLogDebug("[%s] state %p id %"PRIu64", Freeing %d bytes at %p",
858  s, tx->tx_id,
859  tx->request_length, tx->request);
860  FTPTransactionFree(tx);
861  }
862 
863  FTPFree(s, sizeof(FtpState));
864 #ifdef DEBUG
865  SCMutexLock(&ftp_state_mem_lock);
866  ftp_state_memcnt--;
867  ftp_state_memuse-=sizeof(FtpState);
868  SCMutexUnlock(&ftp_state_mem_lock);
869 #endif
870 }
871 
872 static int FTPSetTxDetectState(void *vtx, DetectEngineState *de_state)
873 {
874  FTPTransaction *tx = (FTPTransaction *)vtx;
875  tx->de_state = de_state;
876  return 0;
877 }
878 
879 /**
880  * \brief This function returns the oldest open transaction; if none
881  * are open, then the oldest transaction is returned
882  * \param ftp_state the ftp state structure for the parser
883  *
884  * \retval transaction pointer when a transaction was found; NULL otherwise.
885  */
886 static FTPTransaction *FTPGetOldestTx(FtpState *ftp_state)
887 {
888  if (unlikely(!ftp_state)) {
889  SCLogDebug("NULL state object; no transactions available");
890  return NULL;
891  }
892  FTPTransaction *tx = NULL;
893  FTPTransaction *lasttx = NULL;
894  TAILQ_FOREACH(tx, &ftp_state->tx_list, next) {
895  /* Return oldest open tx */
896  if (!tx->done) {
897  SCLogDebug("Returning tx %p id %"PRIu64, tx, tx->tx_id);
898  return tx;
899  }
900  /* save for the end */
901  lasttx = tx;
902  }
903  /* All tx are closed; return last element */
904  if (lasttx)
905  SCLogDebug("Returning OLDEST tx %p id %"PRIu64, lasttx, lasttx->tx_id);
906  return lasttx;
907 }
908 
909 static void *FTPGetTx(void *state, uint64_t tx_id)
910 {
911  FtpState *ftp_state = (FtpState *)state;
912  if (ftp_state) {
913  FTPTransaction *tx = NULL;
914 
915  if (ftp_state->curr_tx == NULL)
916  return NULL;
917  if (ftp_state->curr_tx->tx_id == tx_id)
918  return ftp_state->curr_tx;
919 
920  TAILQ_FOREACH(tx, &ftp_state->tx_list, next) {
921  if (tx->tx_id == tx_id)
922  return tx;
923  }
924  }
925  return NULL;
926 }
927 
928 static DetectEngineState *FTPGetTxDetectState(void *vtx)
929 {
930  FTPTransaction *tx = (FTPTransaction *)vtx;
931  return tx->de_state;
932 }
933 
934 
935 static uint64_t FTPGetTxDetectFlags(void *vtx, uint8_t dir)
936 {
937  FTPTransaction *tx = (FTPTransaction *)vtx;
938  if (dir & STREAM_TOSERVER) {
939  return tx->detect_flags_ts;
940  } else {
941  return tx->detect_flags_tc;
942  }
943 }
944 
945 static void FTPSetTxDetectFlags(void *vtx, uint8_t dir, uint64_t flags)
946 {
947  FTPTransaction *tx = (FTPTransaction *)vtx;
948  if (dir & STREAM_TOSERVER) {
949  tx->detect_flags_ts = flags;
950  } else {
951  tx->detect_flags_tc = flags;
952  }
953 }
954 
955 static void FTPStateTransactionFree(void *state, uint64_t tx_id)
956 {
957  FtpState *ftp_state = state;
958  FTPTransaction *tx = NULL;
959  TAILQ_FOREACH(tx, &ftp_state->tx_list, next) {
960  if (tx_id < tx->tx_id)
961  break;
962  else if (tx_id > tx->tx_id)
963  continue;
964 
965  if (tx == ftp_state->curr_tx)
966  ftp_state->curr_tx = NULL;
967  TAILQ_REMOVE(&ftp_state->tx_list, tx, next);
968  FTPTransactionFree(tx);
969  break;
970  }
971 }
972 
973 static uint64_t FTPGetTxCnt(void *state)
974 {
975  uint64_t cnt = 0;
976  FtpState *ftp_state = state;
977  if (ftp_state) {
978  cnt = ftp_state->tx_cnt;
979  }
980  SCLogDebug("returning state %p %"PRIu64, state, cnt);
981  return cnt;
982 }
983 
984 static int FTPGetAlstateProgressCompletionStatus(uint8_t direction)
985 {
986  return FTP_STATE_FINISHED;
987 }
988 
989 static int FTPGetAlstateProgress(void *vtx, uint8_t direction)
990 {
991  SCLogDebug("tx %p", vtx);
992  FTPTransaction *tx = vtx;
993 
994  if (direction == STREAM_TOSERVER &&
996  return FTP_STATE_PORT_DONE;
997  }
998 
999  if (!tx->done)
1000  return FTP_STATE_IN_PROGRESS;
1001 
1002  return FTP_STATE_FINISHED;
1003 }
1004 
1005 
1006 static int FTPRegisterPatternsForProtocolDetection(void)
1007 {
1009  "220 (", 5, 0, STREAM_TOCLIENT) < 0)
1010  {
1011  return -1;
1012  }
1014  "FEAT", 4, 0, STREAM_TOSERVER) < 0)
1015  {
1016  return -1;
1017  }
1019  "USER ", 5, 0, STREAM_TOSERVER) < 0)
1020  {
1021  return -1;
1022  }
1024  "PASS ", 5, 0, STREAM_TOSERVER) < 0)
1025  {
1026  return -1;
1027  }
1029  "PORT ", 5, 0, STREAM_TOSERVER) < 0)
1030  {
1031  return -1;
1032  }
1033 
1034  return 0;
1035 }
1036 
1037 
1039 
1040 /**
1041  * \brief This function is called to retrieve a ftp request
1042  * \param ftp_state the ftp state structure for the parser
1043  * \param input input line of the command
1044  * \param input_len length of the request
1045  * \param output the resulting output
1046  *
1047  * \retval 1 when the command is parsed, 0 otherwise
1048  */
1049 static int FTPDataParse(Flow *f, FtpDataState *ftpdata_state,
1050  AppLayerParserState *pstate,
1051  const uint8_t *input, uint32_t input_len,
1052  void *local_data, int direction)
1053 {
1054  uint16_t flags = FileFlowToFlags(f, direction);
1055  int ret = 0;
1056  /* we depend on detection engine for file pruning */
1057  flags |= FILE_USE_DETECT;
1058  if (ftpdata_state->files == NULL) {
1060  if (data == NULL) {
1061  SCReturnInt(-1);
1062  }
1063 
1064  ftpdata_state->files = FileContainerAlloc();
1065  if (ftpdata_state->files == NULL) {
1067  SCReturnInt(-1);
1068  }
1069 
1070  ftpdata_state->file_name = data->file_name;
1071  ftpdata_state->file_len = data->file_len;
1072  data->file_name = NULL;
1073  data->file_len = 0;
1074  f->parent_id = data->flow_id;
1075  ftpdata_state->command = data->cmd;
1076  switch (data->cmd) {
1077  case FTP_COMMAND_STOR:
1078  ftpdata_state->direction = STREAM_TOSERVER;
1079  break;
1080  case FTP_COMMAND_RETR:
1081  ftpdata_state->direction = STREAM_TOCLIENT;
1082  break;
1083  default:
1084  break;
1085  }
1086 
1087  /* open with fixed track_id 0 as we can have just one
1088  * file per ftp-data flow. */
1089  if (FileOpenFileWithId(ftpdata_state->files, &sbcfg,
1090  0ULL, (uint8_t *) ftpdata_state->file_name,
1091  ftpdata_state->file_len,
1092  input, input_len, flags) != 0) {
1093  SCLogDebug("Can't open file");
1094  ret = -1;
1095  }
1097  } else {
1098  if (input_len != 0) {
1099  ret = FileAppendData(ftpdata_state->files, input, input_len);
1100  if (ret == -2) {
1101  ret = 0;
1102  SCLogDebug("FileAppendData() - file no longer being extracted");
1103  goto out;
1104  } else if (ret < 0) {
1105  SCLogDebug("FileAppendData() failed: %d", ret);
1106  ret = -2;
1107  goto out;
1108  }
1109  } else {
1110  ret = FileCloseFile(ftpdata_state->files, NULL, 0, flags);
1111  ftpdata_state->state = FTPDATA_STATE_FINISHED;
1112  if (ret < 0)
1113  goto out;
1114  }
1115  }
1116 
1117  if (input_len && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
1118  ret = FileCloseFile(ftpdata_state->files, (uint8_t *) NULL, 0, flags);
1119  ftpdata_state->state = FTPDATA_STATE_FINISHED;
1120  }
1121 
1122 out:
1123  return ret;
1124 }
1125 
1126 static void FTPStateSetTxLogged(void *state, void *vtx, LoggerId logged)
1127 {
1128  FTPTransaction *tx = vtx;
1129  tx->logged = logged;
1130 }
1131 
1132 static LoggerId FTPStateGetTxLogged(void *state, void *vtx)
1133 {
1134  FTPTransaction *tx = vtx;
1135  return tx->logged;
1136 }
1137 static int FTPDataParseRequest(Flow *f, void *ftp_state,
1138  AppLayerParserState *pstate,
1139  const uint8_t *input, uint32_t input_len,
1140  void *local_data, const uint8_t flags)
1141 {
1142  return FTPDataParse(f, ftp_state, pstate, input, input_len,
1143  local_data, STREAM_TOSERVER);
1144 }
1145 
1146 static int FTPDataParseResponse(Flow *f, void *ftp_state,
1147  AppLayerParserState *pstate,
1148  const uint8_t *input, uint32_t input_len,
1149  void *local_data, const uint8_t flags)
1150 {
1151  return FTPDataParse(f, ftp_state, pstate, input, input_len,
1152  local_data, STREAM_TOCLIENT);
1153 }
1154 
1155 #ifdef DEBUG
1156 static SCMutex ftpdata_state_mem_lock = SCMUTEX_INITIALIZER;
1157 static uint64_t ftpdata_state_memuse = 0;
1158 static uint64_t ftpdata_state_memcnt = 0;
1159 #endif
1160 
1161 static void *FTPDataStateAlloc(void)
1162 {
1163  void *s = FTPCalloc(1, sizeof(FtpDataState));
1164  if (unlikely(s == NULL))
1165  return NULL;
1166 
1167  FtpDataState *state = (FtpDataState *) s;
1169 
1170 #ifdef DEBUG
1171  SCMutexLock(&ftpdata_state_mem_lock);
1172  ftpdata_state_memcnt++;
1173  ftpdata_state_memuse+=sizeof(FtpDataState);
1174  SCMutexUnlock(&ftpdata_state_mem_lock);
1175 #endif
1176  return s;
1177 }
1178 
1179 static void FTPDataStateFree(void *s)
1180 {
1181  FtpDataState *fstate = (FtpDataState *) s;
1182 
1183  if (fstate->de_state != NULL) {
1185  }
1186  if (fstate->file_name != NULL) {
1187  FTPFree(fstate->file_name, fstate->file_len);
1188  }
1189 
1190  FileContainerFree(fstate->files);
1191 
1192  SCFree(s);
1193 #ifdef DEBUG
1194  SCMutexLock(&ftpdata_state_mem_lock);
1195  ftpdata_state_memcnt--;
1196  ftpdata_state_memuse-=sizeof(FtpDataState);
1197  SCMutexUnlock(&ftpdata_state_mem_lock);
1198 #endif
1199 }
1200 
1201 static int FTPDataSetTxDetectState(void *vtx, DetectEngineState *de_state)
1202 {
1203  FtpDataState *ftp_state = (FtpDataState *)vtx;
1204  ftp_state->de_state = de_state;
1205  return 0;
1206 }
1207 
1208 static DetectEngineState *FTPDataGetTxDetectState(void *vtx)
1209 {
1210  FtpDataState *ftp_state = (FtpDataState *)vtx;
1211  return ftp_state->de_state;
1212 }
1213 
1214 static void FTPDataSetTxDetectFlags(void *vtx, uint8_t dir, uint64_t flags)
1215 {
1216  FtpDataState *ftp_state = (FtpDataState *)vtx;
1217  if (dir & STREAM_TOSERVER) {
1218  ftp_state->detect_flags_ts = flags;
1219  } else {
1220  ftp_state->detect_flags_tc = flags;
1221  }
1222 }
1223 
1224 static uint64_t FTPDataGetTxDetectFlags(void *vtx, uint8_t dir)
1225 {
1226  FtpDataState *ftp_state = (FtpDataState *)vtx;
1227  if (dir & STREAM_TOSERVER) {
1228  return ftp_state->detect_flags_ts;
1229  } else {
1230  return ftp_state->detect_flags_tc;
1231  }
1232 }
1233 
1234 static void FTPDataStateTransactionFree(void *state, uint64_t tx_id)
1235 {
1236  /* do nothing */
1237 }
1238 
1239 static void *FTPDataGetTx(void *state, uint64_t tx_id)
1240 {
1241  FtpDataState *ftp_state = (FtpDataState *)state;
1242  return ftp_state;
1243 }
1244 
1245 static uint64_t FTPDataGetTxCnt(void *state)
1246 {
1247  /* ftp-data is single tx */
1248  return 1;
1249 }
1250 
1251 static int FTPDataGetAlstateProgressCompletionStatus(uint8_t direction)
1252 {
1253  return FTPDATA_STATE_FINISHED;
1254 }
1255 
1256 static int FTPDataGetAlstateProgress(void *tx, uint8_t direction)
1257 {
1258  FtpDataState *ftpdata_state = (FtpDataState *)tx;
1259  return ftpdata_state->state;
1260 }
1261 
1262 static FileContainer *FTPDataStateGetFiles(void *state, uint8_t direction)
1263 {
1264  FtpDataState *ftpdata_state = (FtpDataState *)state;
1265 
1266  if (direction != ftpdata_state->direction)
1267  SCReturnPtr(NULL, "FileContainer");
1268 
1269  SCReturnPtr(ftpdata_state->files, "FileContainer");
1270 }
1271 
1272 static void FTPSetMpmState(void)
1273 {
1274  ftp_mpm_ctx = SCMalloc(sizeof(MpmCtx));
1275  if (unlikely(ftp_mpm_ctx == NULL)) {
1276  exit(EXIT_FAILURE);
1277  }
1278  memset(ftp_mpm_ctx, 0, sizeof(MpmCtx));
1279  MpmInitCtx(ftp_mpm_ctx, FTP_MPM);
1280 
1281  uint32_t i = 0;
1282  for (i = 0; i < sizeof(FtpCommands)/sizeof(FtpCommand) - 1; i++) {
1283  const FtpCommand *cmd = &FtpCommands[i];
1284  if (cmd->command_length == 0)
1285  continue;
1286 
1287  MpmAddPatternCI(ftp_mpm_ctx,
1288  (uint8_t *)cmd->command_name,
1289  cmd->command_length,
1290  0 /* defunct */, 0 /* defunct */,
1291  i /* id */, i /* rule id */ , 0 /* no flags */);
1292  }
1293 
1294  mpm_table[FTP_MPM].Prepare(ftp_mpm_ctx);
1295 
1296 }
1297 
1298 static void FTPFreeMpmState(void)
1299 {
1300  if (ftp_mpm_ctx != NULL) {
1301  mpm_table[FTP_MPM].DestroyCtx(ftp_mpm_ctx);
1302  SCFree(ftp_mpm_ctx);
1303  ftp_mpm_ctx = NULL;
1304  }
1305 }
1306 
1308 {
1309  const char *proto_name = "ftp";
1310  const char *proto_data_name = "ftp-data";
1311 
1312  /** FTP */
1313  if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
1315  if (FTPRegisterPatternsForProtocolDetection() < 0 )
1316  return;
1318  }
1319 
1320  if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
1322  FTPParseRequest);
1324  FTPParseResponse);
1325  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_FTP, FTPStateAlloc, FTPStateFree);
1327 
1328  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTP, FTPStateTransactionFree);
1329 
1331  FTPGetTxDetectState, FTPSetTxDetectState);
1332 
1334  FTPGetTxDetectFlags, FTPSetTxDetectFlags);
1335 
1336  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTP, FTPGetTx);
1337  AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_FTP, FTPStateGetTxLogged,
1338  FTPStateSetTxLogged);
1339 
1340  AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_FTP, FTPLocalStorageAlloc,
1341  FTPLocalStorageFree);
1342  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxCnt);
1343 
1344  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetAlstateProgress);
1345 
1347  FTPGetAlstateProgressCompletionStatus);
1348 
1349 
1352  FTPDataParseRequest);
1354  FTPDataParseResponse);
1355  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateAlloc, FTPDataStateFree);
1357  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateTransactionFree);
1359  FTPDataGetTxDetectState, FTPDataSetTxDetectState);
1361  FTPDataGetTxDetectFlags, FTPDataSetTxDetectFlags);
1362 
1363  AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateGetFiles);
1364 
1365  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTx);
1366 
1367  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTxCnt);
1368 
1369  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetAlstateProgress);
1370 
1372  FTPDataGetAlstateProgressCompletionStatus);
1373 
1374  sbcfg.buf_size = 4096;
1375  sbcfg.Malloc = FTPMalloc;
1376  sbcfg.Calloc = FTPCalloc;
1377  sbcfg.Realloc = FTPRealloc;
1378  sbcfg.Free = FTPFree;
1379 
1380  FTPParseMemcap();
1381  } else {
1382  SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
1383  "still on.", proto_name);
1384  }
1385 
1386  FTPSetMpmState();
1387 
1388 #ifdef UNITTESTS
1390 #endif
1391 }
1392 
1394 {
1395 #ifdef DEBUG
1396  SCMutexLock(&ftp_state_mem_lock);
1397  SCLogDebug("ftp_state_memcnt %"PRIu64", ftp_state_memuse %"PRIu64"",
1398  ftp_state_memcnt, ftp_state_memuse);
1399  SCMutexUnlock(&ftp_state_mem_lock);
1400 #endif
1401 }
1402 
1403 
1404 /*
1405  * \brief Returns the ending offset of the next line from a multi-line buffer.
1406  *
1407  * "Buffer" refers to a FTP response in a single buffer containing multiple lines.
1408  * Here, "next line" is defined as terminating on
1409  * - Newline character
1410  * - Null character
1411  *
1412  * \param buffer Contains zero or more characters.
1413  * \param len Size, in bytes, of buffer.
1414  *
1415  * \retval Offset from the start of buffer indicating the where the
1416  * next "line ends". The characters between the input buffer and this
1417  * value comprise the line.
1418  *
1419  * NULL is found first or a newline isn't found, then UINT16_MAX is returned.
1420  */
1421 uint16_t JsonGetNextLineFromBuffer(const char *buffer, const uint16_t len)
1422 {
1423  if (!buffer || *buffer == '\0') {
1424  return UINT16_MAX;
1425  }
1426 
1427  char *c = strchr(buffer, '\n');
1428  return c == NULL ? len : c - buffer + 1;
1429 }
1430 
1431 json_t *JsonFTPDataAddMetadata(const Flow *f)
1432 {
1433  const FtpDataState *ftp_state = NULL;
1434  if (f->alstate == NULL)
1435  return NULL;
1436  ftp_state = (FtpDataState *)f->alstate;
1437  json_t *ftpd = json_object();
1438  if (ftpd == NULL)
1439  return NULL;
1440  if (ftp_state->file_name) {
1441  size_t size = ftp_state->file_len * 2 + 1;
1442  char string[size];
1443  BytesToStringBuffer(ftp_state->file_name, ftp_state->file_len, string, size);
1444  json_object_set_new(ftpd, "filename", SCJsonString(string));
1445  }
1446  switch (ftp_state->command) {
1447  case FTP_COMMAND_STOR:
1448  json_object_set_new(ftpd, "command", json_string("STOR"));
1449  break;
1450  case FTP_COMMAND_RETR:
1451  json_object_set_new(ftpd, "command", json_string("RETR"));
1452  break;
1453  default:
1454  break;
1455  }
1456  return ftpd;
1457 }
1458 
1459 /**
1460  * \brief Free memory allocated for global SMTP parser state.
1461  */
1463 {
1464  FTPFreeMpmState();
1465 }
1466 
1467 /* UNITTESTS */
1468 #ifdef UNITTESTS
1469 
1470 /** \test Send a get request in one chunk. */
1471 static int FTPParserTest01(void)
1472 {
1473  int result = 1;
1474  Flow f;
1475  uint8_t ftpbuf[] = "PORT 192,168,1,1,0,80\r\n";
1476  uint32_t ftplen = sizeof(ftpbuf) - 1; /* minus the \0 */
1477  TcpSession ssn;
1479 
1480  memset(&f, 0, sizeof(f));
1481  memset(&ssn, 0, sizeof(ssn));
1482 
1483  FLOW_INITIALIZE(&f);
1484  f.protoctx = (void *)&ssn;
1485  f.proto = IPPROTO_TCP;
1486  f.alproto = ALPROTO_FTP;
1487 
1489 
1490  FLOWLOCK_WRLOCK(&f);
1491  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1492  STREAM_TOSERVER | STREAM_EOF, ftpbuf, ftplen);
1493  if (r != 0) {
1494  SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1495  result = 0;
1496  FLOWLOCK_UNLOCK(&f);
1497  goto end;
1498  }
1499  FLOWLOCK_UNLOCK(&f);
1500 
1501  FtpState *ftp_state = f.alstate;
1502  if (ftp_state == NULL) {
1503  SCLogDebug("no ftp state: ");
1504  result = 0;
1505  goto end;
1506  }
1507 
1508  if (ftp_state->command != FTP_COMMAND_PORT) {
1509  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_PORT, ftp_state->command);
1510  result = 0;
1511  goto end;
1512  }
1513 
1514 end:
1515  if (alp_tctx != NULL)
1516  AppLayerParserThreadCtxFree(alp_tctx);
1518  FLOW_DESTROY(&f);
1519  return result;
1520 }
1521 
1522 /** \test Send a split get request. */
1523 static int FTPParserTest03(void)
1524 {
1525  int result = 1;
1526  Flow f;
1527  uint8_t ftpbuf1[] = "POR";
1528  uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */
1529  uint8_t ftpbuf2[] = "T 192,168,1";
1530  uint32_t ftplen2 = sizeof(ftpbuf2) - 1; /* minus the \0 */
1531  uint8_t ftpbuf3[] = "1,1,10,20\r\n";
1532  uint32_t ftplen3 = sizeof(ftpbuf3) - 1; /* minus the \0 */
1533  TcpSession ssn;
1535 
1536  memset(&f, 0, sizeof(f));
1537  memset(&ssn, 0, sizeof(ssn));
1538 
1539  FLOW_INITIALIZE(&f);
1540  f.protoctx = (void *)&ssn;
1541  f.proto = IPPROTO_TCP;
1542  f.alproto = ALPROTO_FTP;
1543 
1545 
1546  FLOWLOCK_WRLOCK(&f);
1547  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1548  STREAM_TOSERVER | STREAM_START, ftpbuf1,
1549  ftplen1);
1550  if (r != 0) {
1551  SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1552  result = 0;
1553  FLOWLOCK_UNLOCK(&f);
1554  goto end;
1555  }
1556  FLOWLOCK_UNLOCK(&f);
1557 
1558  FLOWLOCK_WRLOCK(&f);
1559  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER,
1560  ftpbuf2, ftplen2);
1561  if (r != 0) {
1562  SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1563  result = 0;
1564  FLOWLOCK_UNLOCK(&f);
1565  goto end;
1566  }
1567  FLOWLOCK_UNLOCK(&f);
1568 
1569  FLOWLOCK_WRLOCK(&f);
1570  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1571  STREAM_TOSERVER | STREAM_EOF, ftpbuf3, ftplen3);
1572  if (r != 0) {
1573  SCLogDebug("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1574  result = 0;
1575  FLOWLOCK_UNLOCK(&f);
1576  goto end;
1577  }
1578  FLOWLOCK_UNLOCK(&f);
1579 
1580  FtpState *ftp_state = f.alstate;
1581  if (ftp_state == NULL) {
1582  SCLogDebug("no ftp state: ");
1583  result = 0;
1584  goto end;
1585  }
1586 
1587  if (ftp_state->command != FTP_COMMAND_PORT) {
1588  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_PORT, ftp_state->command);
1589  result = 0;
1590  goto end;
1591  }
1592 
1593 end:
1594  if (alp_tctx != NULL)
1595  AppLayerParserThreadCtxFree(alp_tctx);
1597  return result;
1598 }
1599 
1600 /** \test See how it deals with an incomplete request. */
1601 static int FTPParserTest06(void)
1602 {
1603  int result = 1;
1604  Flow f;
1605  uint8_t ftpbuf1[] = "PORT";
1606  uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */
1607  TcpSession ssn;
1609 
1610  memset(&f, 0, sizeof(f));
1611  memset(&ssn, 0, sizeof(ssn));
1612 
1613  FLOW_INITIALIZE(&f);
1614  f.protoctx = (void *)&ssn;
1615  f.proto = IPPROTO_TCP;
1616  f.alproto = ALPROTO_FTP;
1617 
1619 
1620  FLOWLOCK_WRLOCK(&f);
1621  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1623  ftpbuf1,
1624  ftplen1);
1625  if (r != 0) {
1626  SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1627  result = 0;
1628  FLOWLOCK_UNLOCK(&f);
1629  goto end;
1630  }
1631  FLOWLOCK_UNLOCK(&f);
1632 
1633  FtpState *ftp_state = f.alstate;
1634  if (ftp_state == NULL) {
1635  SCLogDebug("no ftp state: ");
1636  result = 0;
1637  goto end;
1638  }
1639 
1640  if (ftp_state->command != FTP_COMMAND_UNKNOWN) {
1641  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_UNKNOWN, ftp_state->command);
1642  result = 0;
1643  goto end;
1644  }
1645 
1646 end:
1647  if (alp_tctx != NULL)
1648  AppLayerParserThreadCtxFree(alp_tctx);
1650  FLOW_DESTROY(&f);
1651  return result;
1652 }
1653 
1654 /** \test See how it deals with an incomplete request in multiple chunks. */
1655 static int FTPParserTest07(void)
1656 {
1657  int result = 1;
1658  Flow f;
1659  uint8_t ftpbuf1[] = "PO";
1660  uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */
1661  uint8_t ftpbuf2[] = "RT\r\n";
1662  uint32_t ftplen2 = sizeof(ftpbuf2) - 1; /* minus the \0 */
1663  TcpSession ssn;
1665 
1666  memset(&f, 0, sizeof(f));
1667  memset(&ssn, 0, sizeof(ssn));
1668 
1669  FLOW_INITIALIZE(&f);
1670  f.protoctx = (void *)&ssn;
1671  f.proto = IPPROTO_TCP;
1672  f.alproto = ALPROTO_FTP;
1673 
1675 
1676  FLOWLOCK_WRLOCK(&f);
1677  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1678  STREAM_TOSERVER | STREAM_START, ftpbuf1,
1679  ftplen1);
1680  if (r != 0) {
1681  SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1682  result = 0;
1683  FLOWLOCK_UNLOCK(&f);
1684  goto end;
1685  }
1686  FLOWLOCK_UNLOCK(&f);
1687 
1688  FLOWLOCK_WRLOCK(&f);
1689  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1690  STREAM_TOSERVER | STREAM_EOF, ftpbuf2, ftplen2);
1691  if (r != 0) {
1692  SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1693  result = 0;
1694  FLOWLOCK_UNLOCK(&f);
1695  goto end;
1696  }
1697  FLOWLOCK_UNLOCK(&f);
1698 
1699  FtpState *ftp_state = f.alstate;
1700  if (ftp_state == NULL) {
1701  SCLogDebug("no ftp state: ");
1702  result = 0;
1703  goto end;
1704  }
1705 
1706  if (ftp_state->command != FTP_COMMAND_PORT) {
1707  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ",
1708  FTP_COMMAND_PORT, ftp_state->command);
1709  result = 0;
1710  goto end;
1711  }
1712 
1713 end:
1714  if (alp_tctx != NULL)
1715  AppLayerParserThreadCtxFree(alp_tctx);
1717  FLOW_DESTROY(&f);
1718  return result;
1719 }
1720 
1721 /** \test Test case where chunks are smaller than the delim length and the
1722  * last chunk is supposed to match the delim. */
1723 static int FTPParserTest10(void)
1724 {
1725  int result = 1;
1726  Flow f;
1727  uint8_t ftpbuf1[] = "PORT 1,2,3,4,5,6\r\n";
1728  uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */
1729  TcpSession ssn;
1731  int r = 0;
1732  memset(&f, 0, sizeof(f));
1733  memset(&ssn, 0, sizeof(ssn));
1734 
1735  FLOW_INITIALIZE(&f);
1736  f.protoctx = (void *)&ssn;
1737  f.proto = IPPROTO_TCP;
1738  f.alproto = ALPROTO_FTP;
1739 
1741 
1742  uint32_t u;
1743  for (u = 0; u < ftplen1; u++) {
1744  uint8_t flags = 0;
1745 
1746  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
1747  else if (u == (ftplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
1748  else flags = STREAM_TOSERVER;
1749 
1750  FLOWLOCK_WRLOCK(&f);
1751  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, flags,
1752  &ftpbuf1[u], 1);
1753  if (r != 0) {
1754  SCLogDebug("toserver chunk %" PRIu32 " returned %" PRId32 ", expected 0: ", u, r);
1755  result = 0;
1756  FLOWLOCK_UNLOCK(&f);
1757  goto end;
1758  }
1759  FLOWLOCK_UNLOCK(&f);
1760  }
1761 
1762  FtpState *ftp_state = f.alstate;
1763  if (ftp_state == NULL) {
1764  SCLogDebug("no ftp state: ");
1765  result = 0;
1766  goto end;
1767  }
1768 
1769  if (ftp_state->command != FTP_COMMAND_PORT) {
1770  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_PORT, ftp_state->command);
1771  result = 0;
1772  goto end;
1773  }
1774 
1775 end:
1776  if (alp_tctx != NULL)
1777  AppLayerParserThreadCtxFree(alp_tctx);
1779  FLOW_DESTROY(&f);
1780  return result;
1781 }
1782 
1783 /** \test Supply RETR without a filename */
1784 static int FTPParserTest11(void)
1785 {
1786  int result = 1;
1787  Flow f;
1788  uint8_t ftpbuf1[] = "PORT 192,168,1,1,0,80\r\n";
1789  uint8_t ftpbuf2[] = "RETR\r\n";
1790  uint8_t ftpbuf3[] = "227 OK\r\n";
1791  TcpSession ssn;
1792 
1794 
1795  memset(&f, 0, sizeof(f));
1796  memset(&ssn, 0, sizeof(ssn));
1797 
1798  FLOW_INITIALIZE(&f);
1799  f.protoctx = (void *)&ssn;
1800  f.proto = IPPROTO_TCP;
1801  f.alproto = ALPROTO_FTP;
1802 
1804 
1805  FLOWLOCK_WRLOCK(&f);
1806  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1807  STREAM_TOSERVER | STREAM_START, ftpbuf1,
1808  sizeof(ftpbuf1) - 1);
1809  if (r != 0) {
1810  result = 0;
1811  FLOWLOCK_UNLOCK(&f);
1812  goto end;
1813  }
1814  FLOWLOCK_UNLOCK(&f);
1815 
1816  /* Response */
1817  FLOWLOCK_WRLOCK(&f);
1818  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1820  ftpbuf3,
1821  sizeof(ftpbuf3) - 1);
1822  if (r != 0) {
1823  result = 0;
1824  FLOWLOCK_UNLOCK(&f);
1825  goto end;
1826  }
1827  FLOWLOCK_UNLOCK(&f);
1828 
1829  FLOWLOCK_WRLOCK(&f);
1830  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1831  STREAM_TOSERVER, ftpbuf2,
1832  sizeof(ftpbuf2) - 1);
1833  if (r == 0) {
1834  SCLogDebug("parse should've failed");
1835  result = 0;
1836  FLOWLOCK_UNLOCK(&f);
1837  goto end;
1838  }
1839  FLOWLOCK_UNLOCK(&f);
1840 
1841  FtpState *ftp_state = f.alstate;
1842  if (ftp_state == NULL) {
1843  SCLogDebug("no ftp state: ");
1844  result = 0;
1845  goto end;
1846  }
1847 
1848  if (ftp_state->command != FTP_COMMAND_RETR) {
1849  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ",
1850  FTP_COMMAND_RETR, ftp_state->command);
1851  result = 0;
1852  goto end;
1853  }
1854 
1855 end:
1856  if (alp_tctx != NULL)
1857  AppLayerParserThreadCtxFree(alp_tctx);
1859  FLOW_DESTROY(&f);
1860  return result;
1861 }
1862 
1863 /** \test Supply STOR without a filename */
1864 static int FTPParserTest12(void)
1865 {
1866  int result = 1;
1867  Flow f;
1868  uint8_t ftpbuf1[] = "PORT 192,168,1,1,0,80\r\n";
1869  uint8_t ftpbuf2[] = "STOR\r\n";
1870  uint8_t ftpbuf3[] = "227 OK\r\n";
1871  TcpSession ssn;
1872 
1874 
1875  memset(&f, 0, sizeof(f));
1876  memset(&ssn, 0, sizeof(ssn));
1877 
1878  FLOW_INITIALIZE(&f);
1879  f.protoctx = (void *)&ssn;
1880  f.proto = IPPROTO_TCP;
1881  f.alproto = ALPROTO_FTP;
1882 
1884 
1885  FLOWLOCK_WRLOCK(&f);
1886  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1887  STREAM_TOSERVER | STREAM_START, ftpbuf1,
1888  sizeof(ftpbuf1) - 1);
1889  if (r != 0) {
1890  result = 0;
1891  FLOWLOCK_UNLOCK(&f);
1892  goto end;
1893  }
1894  FLOWLOCK_UNLOCK(&f);
1895 
1896  /* Response */
1897  FLOWLOCK_WRLOCK(&f);
1898  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1900  ftpbuf3,
1901  sizeof(ftpbuf3) - 1);
1902  if (r != 0) {
1903  result = 0;
1904  FLOWLOCK_UNLOCK(&f);
1905  goto end;
1906  }
1907  FLOWLOCK_UNLOCK(&f);
1908 
1909  FLOWLOCK_WRLOCK(&f);
1910  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1911  STREAM_TOSERVER, ftpbuf2,
1912  sizeof(ftpbuf2) - 1);
1913  if (r == 0) {
1914  SCLogDebug("parse should've failed");
1915  result = 0;
1916  FLOWLOCK_UNLOCK(&f);
1917  goto end;
1918  }
1919  FLOWLOCK_UNLOCK(&f);
1920 
1921  FtpState *ftp_state = f.alstate;
1922  if (ftp_state == NULL) {
1923  SCLogDebug("no ftp state: ");
1924  result = 0;
1925  goto end;
1926  }
1927 
1928  if (ftp_state->command != FTP_COMMAND_STOR) {
1929  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ",
1930  FTP_COMMAND_STOR, ftp_state->command);
1931  result = 0;
1932  goto end;
1933  }
1934 
1935 end:
1936  if (alp_tctx != NULL)
1937  AppLayerParserThreadCtxFree(alp_tctx);
1939  FLOW_DESTROY(&f);
1940  return result;
1941 }
1942 #endif /* UNITTESTS */
1943 
1945 {
1946 #ifdef UNITTESTS
1947  UtRegisterTest("FTPParserTest01", FTPParserTest01);
1948  UtRegisterTest("FTPParserTest03", FTPParserTest03);
1949  UtRegisterTest("FTPParserTest06", FTPParserTest06);
1950  UtRegisterTest("FTPParserTest07", FTPParserTest07);
1951  UtRegisterTest("FTPParserTest10", FTPParserTest10);
1952  UtRegisterTest("FTPParserTest11", FTPParserTest11);
1953  UtRegisterTest("FTPParserTest12", FTPParserTest12);
1954 #endif /* UNITTESTS */
1955 }
1956 
#define SCMutex
#define STREAMING_BUFFER_CONFIG_INITIALIZER
#define FTP_MPM
Definition: app-layer-ftp.c:71
uint16_t flags
#define SCMemcmp(a, b, c)
Definition: util-memcmp.h:369
FtpLineState line_state[2]
#define SCLogDebug(...)
Definition: util-debug.h:335
uint16_t JsonGetNextLineFromBuffer(const char *buffer, const uint16_t len)
void *(* Malloc)(size_t size)
#define TAILQ_FIRST(head)
Definition: queue.h:339
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:350
struct HtpBodyChunk_ * next
void AppLayerParserRegisterLocalStorageFunc(uint8_t ipproto, AppProto alproto, void *(*LocalStorageAlloc)(void), void(*LocalStorageFree)(void *))
int AppLayerExpectationGetDataId(void)
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, int(*StateGetProgress)(void *alstate, uint8_t direction))
int PmqSetup(PrefilterRuleStore *)
Setup a pmq.
uint8_t proto
Definition: flow.h:344
FileContainer * FileContainerAlloc(void)
allocate a FileContainer
Definition: util-file.c:377
LoggerId
const uint8_t command_length
Definition: app-layer-ftp.h:93
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:243
int logged
#define unlikely(expr)
Definition: util-optimize.h:35
uint64_t detect_flags_ts
int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto)
Given a protocol name, checks if proto detection is enabled in the conf file.
void AppLayerParserRegisterDetectFlagsFuncs(uint8_t ipproto, AppProto alproto, uint64_t(*GetTxDetectFlags)(void *tx, uint8_t dir), void(*SetTxDetectFlags)(void *tx, uint8_t dir, uint64_t))
int16_t file_len
int AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint8_t flag)
void AppLayerParserRegisterParserAcceptableDataDirection(uint8_t ipproto, AppProto alproto, uint8_t direction)
void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, DetectEngineState *(*GetTxDetectState)(void *tx), int(*SetTxDetectState)(void *tx, DetectEngineState *))
uint8_t * file_name
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:107
uint8_t * request
void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher)
Definition: util-mpm.c:256
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
void(* DestroyThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *)
Definition: util-mpm.h:146
void(* DFree)(void *)
uint16_t src
void StreamTcpFreeConfig(char quiet)
Definition: stream-tcp.c:668
const char * command_name
Definition: app-layer-ftp.h:92
#define FLOWLOCK_WRLOCK(fb)
Definition: flow.h:240
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
Definition: util-atomic.h:124
void AppLayerParserRegisterLoggerFuncs(uint8_t ipproto, AppProto alproto, LoggerId(*StateGetTxLogged)(void *, void *), void(*StateSetTxLogged)(void *, void *, LoggerId))
uint64_t FTPMemuseGlobalCounter(void)
#define TRUE
#define SCMutexLock(mut)
MpmThreadCtx * ftp_mpm_thread_ctx
Definition: app-layer-ftp.c:67
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:331
void * protoctx
Definition: flow.h:400
void *(* Calloc)(size_t n, size_t size)
FtpRequestCommand command
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:203
uint64_t detect_flags_tc
void PmqFree(PrefilterRuleStore *)
Cleanup and free a Pmq.
FtpRequestCommand cmd
void * alstate
Definition: flow.h:438
SC_ATOMIC_DECLARE(uint64_t, ftp_memuse)
int AppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name)
check if a parser is enabled in the config Returns enabled always if: were running unittests and when...
#define SC_ATOMIC_INIT(name)
Initialize the previously declared atomic variable and it&#39;s lock.
Definition: util-atomic.h:81
void FTPParserCleanup(void)
Free memory allocated for global SMTP parser state.
int(* Prepare)(struct MpmCtx_ *)
Definition: util-mpm.h:161
uint8_t direction
#define str(s)
#define SCCalloc(nm, a)
Definition: util-mem.h:253
int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, uint8_t direction, AppLayerParserFPtr Parser)
Register app layer parser for the protocol.
struct FTPThreadCtx_ FTPThreadCtx
#define SCMutexUnlock(mut)
uint64_t ftp_config_memcap
struct FtpState_ FtpState
void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id))
#define SCMUTEX_INITIALIZER
void AppLayerParserRegisterGetFilesFunc(uint8_t ipproto, AppProto alproto, FileContainer *(*StateGetFiles)(void *, uint8_t))
#define TAILQ_INIT(head)
Definition: queue.h:370
void AppLayerRegisterExpectationProto(uint8_t proto, AppProto alproto)
Data structures and function prototypes for keeping state for the detection engine.
FtpRequestCommand command
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
#define FLOW_DESTROY(f)
Definition: flow-util.h:121
FTPTransaction * curr_tx
void FTPParserRegisterTests(void)
const uint8_t * input
uint8_t * str
#define STREAM_EOF
Definition: stream.h:30
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
void FileContainerFree(FileContainer *ffc)
Free a FileContainer.
Definition: util-file.c:413
void RegisterFTPParsers(void)
void AppLayerRequestProtocolTLSUpgrade(Flow *f)
request applayer to wrap up this protocol and rerun protocol detection with expectation of TLS...
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:412
void *(* Realloc)(void *ptr, size_t orig_size, size_t size)
void BytesToStringBuffer(const uint8_t *bytes, size_t nbytes, char *outstr, size_t outlen)
Turn byte array into string.
Definition: util-byte.c:85
#define SCEnter(...)
Definition: util-debug.h:337
void StreamTcpInitConfig(char)
To initialize the stream global configuration data.
Definition: stream-tcp.c:364
#define STREAM_TOCLIENT
Definition: stream.h:32
json_t * SCJsonString(const char *val)
Definition: output-json.c:107
uint64_t FTPMemcapGlobalCounter(void)
void AppLayerParserRegisterGetStateProgressCompletionStatus(AppProto alproto, int(*StateGetProgressCompletionStatus)(uint8_t direction))
uint8_t * port_line
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol&#39;s parser thread context.
void(* DestroyCtx)(struct MpmCtx_ *)
Definition: util-mpm.h:145
uint16_t dyn_port
SigIntId * rule_id_array
void DetectEngineStateFree(DetectEngineState *state)
Frees a DetectEngineState object.
#define SCReturnInt(x)
Definition: util-debug.h:341
#define SCRealloc(x, a)
Definition: util-mem.h:238
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:385
json_t * JsonFTPDataAddMetadata(const Flow *f)
uint64_t tx_cnt
#define SCMalloc(a)
Definition: util-mem.h:222
const uint8_t * current_line
#define FILE_USE_DETECT
Definition: util-file.h:49
void FTPAtExitPrintStats(void)
void MpmInitCtx(MpmCtx *mpm_ctx, uint16_t matcher)
Definition: util-mpm.c:261
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:254
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition: util-mpm.h:169
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
uint32_t db_len
#define SCFree(a)
Definition: util-mem.h:322
uint32_t request_length
uint16_t tx_id
uint8_t current_line_lf_seen
uint32_t port_line_len
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
int64_t parent_id
Definition: flow.h:389
#define STREAM_START
Definition: stream.h:29
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:39
uint8_t direction
#define STREAM_TOSERVER
Definition: stream.h:31
int AppLayerExpectationCreate(Flow *f, int direction, Port src, Port dst, AppProto alproto, void *data)
#define SCReturnPtr(x, type)
Definition: util-debug.h:353
int FileOpenFileWithId(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, const uint8_t *name, uint16_t name_len, const uint8_t *data, uint32_t data_len, uint16_t flags)
Open a new File.
Definition: util-file.c:866
int FileCloseFile(FileContainer *ffc, const uint8_t *data, uint32_t data_len, uint16_t flags)
Close a File.
Definition: util-file.c:960
structure for storing potential rule matches
#define APP_LAYER_PARSER_EOF
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:192
uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction)
Definition: util-file.c:217
void * FlowGetStorageById(Flow *f, int id)
Definition: flow-storage.c:39
uint32_t port_line_size
uint16_t file_len
uint16_t length
int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags)
Definition: util-mpm.c:311
struct FtpDataState_ FtpDataState
int AppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction)
Registers a case-insensitive pattern for protocol detection.
FtpRequestCommand
Definition: app-layer-ftp.h:34
DetectEngineState * de_state
uint32_t current_line_len
uint64_t detect_flags_tc
DetectEngineState * de_state
uint32_t(* Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t)
Definition: util-mpm.h:162
uint8_t * db
uint8_t * file_name
void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t(*StateGetTxCnt)(void *alstate))
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void), void(*StateFree)(void *))
uint8_t len
uint64_t detect_flags_ts
AppProto alproto
application level protocol
Definition: flow.h:409
const FtpCommand * command_descriptor
int FileAppendData(FileContainer *ffc, const uint8_t *data, uint32_t data_len)
Store/handle a chunk of file data in the File structure The last file in the FileContainer will be us...
Definition: util-file.c:661
void FlowFreeStorageById(Flow *f, int id)
Definition: flow-storage.c:54
#define likely(expr)
Definition: util-optimize.h:32
uint16_t len
int32_t input_len
const FtpCommand FtpCommands[FTP_COMMAND_MAX+1]
Definition: app-layer-ftp.c:75
PrefilterRuleStore * pmq
Definition: app-layer-ftp.c:68
Flow data structure.
Definition: flow.h:325
uint8_t current_line_delimiter_len
void(* Free)(void *ptr, size_t size)
void PmqReset(PrefilterRuleStore *)
Reset a Pmq for reusage. Meant to be called after a single search.
FileContainer * files
FtpRequestCommand command
Definition: app-layer-ftp.h:91
uint8_t current_line_db
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))
uint64_t flow_id