suricata
app-layer-smtp.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2020 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 Anoop Saldanha <anoopsaldanha@gmail.com>
22  */
23 
24 #include "suricata.h"
25 #include "suricata-common.h"
26 #include "debug.h"
27 #include "decode.h"
28 #include "threads.h"
29 
30 #include "stream-tcp-private.h"
31 #include "stream-tcp-reassemble.h"
32 #include "stream-tcp.h"
33 #include "stream.h"
34 
35 #include "app-layer.h"
36 #include "app-layer-detect-proto.h"
37 #include "app-layer-protos.h"
38 #include "app-layer-parser.h"
39 #include "app-layer-smtp.h"
40 
41 #include "util-mpm.h"
42 #include "util-debug.h"
43 #include "util-byte.h"
44 #include "util-unittest.h"
45 #include "util-unittest-helper.h"
46 #include "util-memcmp.h"
47 #include "flow-util.h"
48 
49 #include "detect-engine.h"
50 #include "detect-engine-state.h"
51 #include "detect-parse.h"
52 
53 #include "decode-events.h"
54 #include "conf.h"
55 
56 #include "util-mem.h"
57 #include "util-misc.h"
58 #include "util-validate.h"
59 
60 /* content-limit default value */
61 #define FILEDATA_CONTENT_LIMIT 100000
62 /* content-inspect-min-size default value */
63 #define FILEDATA_CONTENT_INSPECT_MIN_SIZE 32768
64 /* content-inspect-window default value */
65 #define FILEDATA_CONTENT_INSPECT_WINDOW 4096
66 
67 /* raw extraction default value */
68 #define SMTP_RAW_EXTRACTION_DEFAULT_VALUE 0
69 #define SMTP_MAX_REQUEST_AND_REPLY_LINE_LENGTH 510
70 
71 #define SMTP_COMMAND_BUFFER_STEPS 5
72 
73 /* we are in process of parsing a fresh command. Just a placeholder. If we
74  * are not in STATE_COMMAND_DATA_MODE, we have to be in this mode */
75 #define SMTP_PARSER_STATE_COMMAND_MODE 0x00
76 /* we are in mode of parsing a command's data. Used when we are parsing tls
77  * or accepting the rfc 2822 mail after DATA command */
78 #define SMTP_PARSER_STATE_COMMAND_DATA_MODE 0x01
79 /* Used when we are still in the process of parsing a server command. Used
80  * with multi-line replies and the stream is fragmented before all the lines
81  * for a response is seen */
82 #define SMTP_PARSER_STATE_PARSING_SERVER_RESPONSE 0x02
83 /* Used to indicate that the parser has seen the first reply */
84 #define SMTP_PARSER_STATE_FIRST_REPLY_SEEN 0x04
85 /* Used to indicate that the parser is parsing a multiline reply */
86 #define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY 0x08
87 /* Used to indicate that the server supports pipelining */
88 #define SMTP_PARSER_STATE_PIPELINING_SERVER 0x10
89 
90 /* Various SMTP commands
91  * We currently have var-ified just STARTTLS and DATA, since we need to them
92  * for state transitions. The rest are just indicate as OTHER_CMD. Other
93  * commands would be introduced as and when needed */
94 #define SMTP_COMMAND_STARTTLS 1
95 #define SMTP_COMMAND_DATA 2
96 #define SMTP_COMMAND_BDAT 3
97 /* not an actual command per se, but the mode where we accept the mail after
98  * DATA has it's own reply code for completion, from the server. We give this
99  * stage a pseudo command of it's own, so that we can add this to the command
100  * buffer to match with the reply */
101 #define SMTP_COMMAND_DATA_MODE 4
102 /* All other commands are represented by this var */
103 #define SMTP_COMMAND_OTHER_CMD 5
104 #define SMTP_COMMAND_RSET 6
105 
106 /* Different EHLO extensions. Not used now. */
107 #define SMTP_EHLO_EXTENSION_PIPELINING
108 #define SMTP_EHLO_EXTENSION_SIZE
109 #define SMTP_EHLO_EXTENSION_DSN
110 #define SMTP_EHLO_EXTENSION_STARTTLS
111 #define SMTP_EHLO_EXTENSION_8BITMIME
112 
114  { "INVALID_REPLY", SMTP_DECODER_EVENT_INVALID_REPLY },
115  { "UNABLE_TO_MATCH_REPLY_WITH_REQUEST",
117  { "MAX_COMMAND_LINE_LEN_EXCEEDED",
119  { "MAX_REPLY_LINE_LEN_EXCEEDED",
121  { "INVALID_PIPELINED_SEQUENCE",
123  { "BDAT_CHUNK_LEN_EXCEEDED",
125  { "NO_SERVER_WELCOME_MESSAGE",
127  { "TLS_REJECTED",
129  { "DATA_COMMAND_REJECTED",
131 
132  /* MIME Events */
133  { "MIME_PARSE_FAILED",
135  { "MIME_MALFORMED_MSG",
137  { "MIME_INVALID_BASE64",
139  { "MIME_INVALID_QP",
141  { "MIME_LONG_LINE",
143  { "MIME_LONG_ENC_LINE",
145  { "MIME_LONG_HEADER_NAME",
147  { "MIME_LONG_HEADER_VALUE",
149  { "MIME_LONG_BOUNDARY",
151  { "MIME_LONG_FILENAME",
153 
154  /* Invalid behavior or content */
155  { "DUPLICATE_FIELDS",
157  { "UNPARSABLE_CONTENT",
159 
160  { NULL, -1 },
161 };
162 
163 typedef struct SMTPThreadCtx_ {
167 
168 #define SMTP_MPM mpm_default_matcher
169 
170 static MpmCtx *smtp_mpm_ctx = NULL;
171 
172 /* smtp reply codes. If an entry is made here, please make a simultaneous
173  * entry in smtp_reply_map */
174 enum SMTPCode {
183 
186 
192 
204 };
205 
207  { "211", SMTP_REPLY_211 },
208  { "214", SMTP_REPLY_214 },
209  { "220", SMTP_REPLY_220 },
210  { "221", SMTP_REPLY_221 },
211  { "235", SMTP_REPLY_235 },
212  { "250", SMTP_REPLY_250 },
213  { "251", SMTP_REPLY_251 },
214  { "252", SMTP_REPLY_252 },
215 
216  { "334", SMTP_REPLY_334 },
217  { "354", SMTP_REPLY_354 },
218 
219  { "421", SMTP_REPLY_421 },
220  { "450", SMTP_REPLY_450 },
221  { "451", SMTP_REPLY_451 },
222  { "452", SMTP_REPLY_452 },
223  { "455", SMTP_REPLY_455 },
224 
225  { "500", SMTP_REPLY_500 },
226  { "501", SMTP_REPLY_501 },
227  { "502", SMTP_REPLY_502 },
228  { "503", SMTP_REPLY_503 },
229  { "504", SMTP_REPLY_504 },
230  { "550", SMTP_REPLY_550 },
231  { "551", SMTP_REPLY_551 },
232  { "552", SMTP_REPLY_552 },
233  { "553", SMTP_REPLY_553 },
234  { "554", SMTP_REPLY_554 },
235  { "555", SMTP_REPLY_555 },
236  { NULL, -1 },
237 };
238 
239 /* Create SMTP config structure */
240 SMTPConfig smtp_config = { 0, { 0, 0, 0, 0, 0 }, 0, 0, 0, 0, STREAMING_BUFFER_CONFIG_INITIALIZER};
241 
242 static SMTPString *SMTPStringAlloc(void);
243 
244 /**
245  * \brief Configure SMTP Mime Decoder by parsing out mime section of YAML
246  * config file
247  *
248  * \return none
249  */
250 static void SMTPConfigure(void) {
251 
252  SCEnter();
253  int ret = 0, val;
254  intmax_t imval;
255  uint32_t content_limit = 0;
256  uint32_t content_inspect_min_size = 0;
257  uint32_t content_inspect_window = 0;
258 
259  ConfNode *config = ConfGetNode("app-layer.protocols.smtp.mime");
260  if (config != NULL) {
261 
262  ret = ConfGetChildValueBool(config, "decode-mime", &val);
263  if (ret) {
264  smtp_config.decode_mime = val;
265  }
266 
267  ret = ConfGetChildValueBool(config, "decode-base64", &val);
268  if (ret) {
270  }
271 
272  ret = ConfGetChildValueBool(config, "decode-quoted-printable", &val);
273  if (ret) {
275  }
276 
277  ret = ConfGetChildValueInt(config, "header-value-depth", &imval);
278  if (ret) {
279  smtp_config.mime_config.header_value_depth = (uint32_t) imval;
280  }
281 
282  ret = ConfGetChildValueBool(config, "extract-urls", &val);
283  if (ret) {
285  }
286 
287  ret = ConfGetChildValueBool(config, "body-md5", &val);
288  if (ret) {
290  }
291  }
292 
293  /* Pass mime config data to MimeDec API */
295 
299 
300  ConfNode *t = ConfGetNode("app-layer.protocols.smtp.inspected-tracker");
301  ConfNode *p = NULL;
302 
303  if (t != NULL) {
304  TAILQ_FOREACH(p, &t->head, next) {
305  if (strcasecmp("content-limit", p->name) == 0) {
306  if (ParseSizeStringU32(p->val, &content_limit) < 0) {
308  "parsing content-limit %s failed", p->val);
309  content_limit = FILEDATA_CONTENT_LIMIT;
310  }
311  smtp_config.content_limit = content_limit;
312  }
313 
314  if (strcasecmp("content-inspect-min-size", p->name) == 0) {
315  if (ParseSizeStringU32(p->val, &content_inspect_min_size) < 0) {
317  "parsing content-inspect-min-size %s failed", p->val);
318  content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE;
319  }
320  smtp_config.content_inspect_min_size = content_inspect_min_size;
321  }
322 
323  if (strcasecmp("content-inspect-window", p->name) == 0) {
324  if (ParseSizeStringU32(p->val, &content_inspect_window) < 0) {
326  "parsing content-inspect-window %s failed", p->val);
327  content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW;
328  }
329  smtp_config.content_inspect_window = content_inspect_window;
330  }
331  }
332  }
333 
334  smtp_config.sbcfg.buf_size = content_limit ? content_limit : 256;
335 
336  if (ConfGetBool("app-layer.protocols.smtp.raw-extraction",
337  &smtp_config.raw_extraction) != 1) {
339  }
342  "\"decode-mime\" and \"raw-extraction\" "
343  "options can't be enabled at the same time, "
344  "disabling raw extraction");
346  }
347 
348  SCReturn;
349 }
350 
351 static void SMTPSetEvent(SMTPState *s, uint8_t e)
352 {
353  SCLogDebug("setting event %u", e);
354 
355  if (s->curr_tx != NULL) {
357 // s->events++;
358  return;
359  }
360  SCLogDebug("couldn't set event %u", e);
361 }
362 
363 static SMTPTransaction *SMTPTransactionCreate(void)
364 {
365  SMTPTransaction *tx = SCCalloc(1, sizeof(*tx));
366  if (tx == NULL) {
367  return NULL;
368  }
369 
370  TAILQ_INIT(&tx->rcpt_to_list);
371  tx->mime_state = NULL;
372  return tx;
373 }
374 
375 static void FlagDetectStateNewFile(SMTPTransaction *tx)
376 {
377  if (tx && tx->de_state) {
378  SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set");
380  } else if (tx == NULL) {
381  SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW NOT set, no TX");
382  } else if (tx->de_state == NULL) {
383  SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW NOT set, no TX DESTATE");
384  }
385 }
386 
387 static void SMTPNewFile(SMTPTransaction *tx, File *file)
388 {
389  DEBUG_VALIDATE_BUG_ON(tx == NULL);
390  DEBUG_VALIDATE_BUG_ON(file == NULL);
391 #ifdef UNITTESTS
392  if (RunmodeIsUnittests()) {
393  if (tx == NULL || file == NULL) {
394  return;
395  }
396  }
397 #endif
398  FlagDetectStateNewFile(tx);
399  FileSetTx(file, tx->tx_id);
400 
401  /* set inspect sizes used in file pruning logic.
402  * TODO consider moving this to the file.data code that
403  * would actually have use for this. */
406 }
407 
408 int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len,
409  MimeDecParseState *state)
410 {
411  SCEnter();
412  int ret = MIME_DEC_OK;
413  Flow *flow = (Flow *) state->data;
414  SMTPState *smtp_state = (SMTPState *) flow->alstate;
415  MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data;
416  FileContainer *files = NULL;
417 
418  uint16_t flags = FileFlowToFlags(flow, STREAM_TOSERVER);
419  /* we depend on detection engine for file pruning */
421 
422  /* Find file */
423  if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) {
424 
425  /* Make sure file container allocated */
426  if (smtp_state->files_ts == NULL) {
427  smtp_state->files_ts = FileContainerAlloc();
428  if (smtp_state->files_ts == NULL) {
429  ret = MIME_DEC_ERR_MEM;
430  SCLogError(SC_ERR_MEM_ALLOC, "Could not create file container");
431  SCReturnInt(ret);
432  }
433  }
434  files = smtp_state->files_ts;
435 
436  /* Open file if necessary */
437  if (state->body_begin) {
438 
439  if (SCLogDebugEnabled()) {
440  SCLogDebug("Opening file...%u bytes", len);
441  printf("File - ");
442  for (uint32_t i = 0; i < entity->filename_len; i++) {
443  printf("%c", entity->filename[i]);
444  }
445  printf("\n");
446  }
447 
448  /* Set storage flag if applicable since only the first file in the
449  * flow seems to be processed by the 'filestore' detector */
450  if (files->head != NULL && (files->head->flags & FILE_STORE)) {
451  flags |= FILE_STORE;
452  }
453 
454  uint32_t depth = smtp_config.content_inspect_min_size +
455  (smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp);
456  SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %"PRIu32, depth);
458 
459  if (FileOpenFileWithId(files, &smtp_config.sbcfg, smtp_state->file_track_id++,
460  (uint8_t *) entity->filename, entity->filename_len,
461  (uint8_t *) chunk, len, flags) != 0) {
462  ret = MIME_DEC_ERR_DATA;
463  SCLogDebug("FileOpenFile() failed");
464  }
465  SMTPNewFile(smtp_state->curr_tx, files->tail);
466 
467  /* If close in the same chunk, then pass in empty bytes */
468  if (state->body_end) {
469 
470  SCLogDebug("Closing file...%u bytes", len);
471 
472  if (files->tail->state == FILE_STATE_OPENED) {
473  ret = FileCloseFile(files, (uint8_t *) NULL, 0, flags);
474  if (ret != 0) {
475  SCLogDebug("FileCloseFile() failed: %d", ret);
476  ret = MIME_DEC_ERR_DATA;
477  }
478  } else {
479  SCLogDebug("File already closed");
480  }
481  depth = smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp;
482 
484  SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u",
485  depth);
487  depth);
488  }
489  } else if (state->body_end) {
490  /* Close file */
491  SCLogDebug("Closing file...%u bytes", len);
492 
493  if (files->tail && files->tail->state == FILE_STATE_OPENED) {
494  ret = FileCloseFile(files, (uint8_t *) chunk, len, flags);
495  if (ret != 0) {
496  SCLogDebug("FileCloseFile() failed: %d", ret);
497  ret = MIME_DEC_ERR_DATA;
498  }
499  } else {
500  SCLogDebug("File already closed");
501  }
502  uint32_t depth = smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp;
504  SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u",
505  depth);
507  STREAM_TOSERVER, depth);
508  } else {
509  /* Append data chunk to file */
510  SCLogDebug("Appending file...%u bytes", len);
511 
512  /* 0 is ok, -2 is not stored, -1 is error */
513  ret = FileAppendData(files, (uint8_t *) chunk, len);
514  if (ret == -2) {
515  ret = 0;
516  SCLogDebug("FileAppendData() - file no longer being extracted");
517  } else if (ret < 0) {
518  SCLogDebug("FileAppendData() failed: %d", ret);
519  ret = MIME_DEC_ERR_DATA;
520  }
521 
522  if (files->tail && files->tail->content_inspected == 0 &&
523  files->tail->size >= smtp_config.content_inspect_min_size) {
524  uint32_t depth = smtp_config.content_inspect_min_size +
525  (smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp);
527  SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u",
528  depth);
530  STREAM_TOSERVER, depth);
531 
532  /* after the start of the body inspection, disable the depth logic */
533  } else if (files->tail && files->tail->content_inspected > 0) {
535  STREAM_TOSERVER, 0);
536 
537  /* expand the limit as long as we get file data, as the file data is bigger on the
538  * wire due to base64 */
539  } else {
540  uint32_t depth = smtp_config.content_inspect_min_size +
541  (smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp);
542  SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %"PRIu32,
543  depth);
545  STREAM_TOSERVER, depth);
546  }
547  }
548 
549  if (ret == 0) {
550  SCLogDebug("Successfully processed file data!");
551  }
552  } else {
553  SCLogDebug("Body not a Ctnt_attachment");
554  }
555  SCReturnInt(ret);
556 }
557 
558 /**
559  * \internal
560  * \brief Get the next line from input. It doesn't do any length validation.
561  *
562  * \param state The smtp state.
563  *
564  * \retval 0 On success.
565  * \retval -1 Either when we don't have any new lines to supply anymore or
566  * on failure.
567  */
568 static int SMTPGetLine(SMTPState *state)
569 {
570  SCEnter();
571  void *ptmp;
572 
573  /* we have run out of input */
574  if (state->input_len <= 0)
575  return -1;
576 
577  /* toserver */
578  if (state->direction == 0) {
579  if (state->ts_current_line_lf_seen == 1) {
580  /* we have seen the lf for the previous line. Clear the parser
581  * details to parse new line */
582  state->ts_current_line_lf_seen = 0;
583  if (state->ts_current_line_db == 1) {
584  state->ts_current_line_db = 0;
585  SCFree(state->ts_db);
586  state->ts_db = NULL;
587  state->ts_db_len = 0;
588  state->current_line = NULL;
589  state->current_line_len = 0;
590  }
591  }
592 
593  uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len);
594 
595  if (lf_idx == NULL) {
596  /* fragmented lines. Decoder event for special cases. Not all
597  * fragmented lines should be treated as a possible evasion
598  * attempt. With multi payload smtp chunks we can have valid
599  * cases of fragmentation. But within the same segment chunk
600  * if we see fragmentation then it's definitely something you
601  * should alert about */
602  if (state->ts_current_line_db == 0) {
603  state->ts_db = SCMalloc(state->input_len);
604  if (state->ts_db == NULL) {
605  return -1;
606  }
607  state->ts_current_line_db = 1;
608  memcpy(state->ts_db, state->input, state->input_len);
609  state->ts_db_len = state->input_len;
610  } else {
611  ptmp = SCRealloc(state->ts_db,
612  (state->ts_db_len + state->input_len));
613  if (ptmp == NULL) {
614  SCFree(state->ts_db);
615  state->ts_db = NULL;
616  state->ts_db_len = 0;
617  return -1;
618  }
619  state->ts_db = ptmp;
620 
621  memcpy(state->ts_db + state->ts_db_len,
622  state->input, state->input_len);
623  state->ts_db_len += state->input_len;
624  } /* else */
625  state->input += state->input_len;
626  state->input_len = 0;
627 
628  return -1;
629 
630  } else {
631  state->ts_current_line_lf_seen = 1;
632 
633  if (state->ts_current_line_db == 1) {
634  ptmp = SCRealloc(state->ts_db,
635  (state->ts_db_len + (lf_idx + 1 - state->input)));
636  if (ptmp == NULL) {
637  SCFree(state->ts_db);
638  state->ts_db = NULL;
639  state->ts_db_len = 0;
640  return -1;
641  }
642  state->ts_db = ptmp;
643 
644  memcpy(state->ts_db + state->ts_db_len,
645  state->input, (lf_idx + 1 - state->input));
646  state->ts_db_len += (lf_idx + 1 - state->input);
647 
648  if (state->ts_db_len > 1 &&
649  state->ts_db[state->ts_db_len - 2] == 0x0D) {
650  state->ts_db_len -= 2;
651  state->current_line_delimiter_len = 2;
652  } else {
653  state->ts_db_len -= 1;
654  state->current_line_delimiter_len = 1;
655  }
656 
657  state->current_line = state->ts_db;
658  state->current_line_len = state->ts_db_len;
659 
660  } else {
661  state->current_line = state->input;
662  state->current_line_len = lf_idx - state->input;
663 
664  if (state->input != lf_idx &&
665  *(lf_idx - 1) == 0x0D) {
666  state->current_line_len--;
667  state->current_line_delimiter_len = 2;
668  } else {
669  state->current_line_delimiter_len = 1;
670  }
671  }
672 
673  state->input_len -= (lf_idx - state->input) + 1;
674  state->input = (lf_idx + 1);
675 
676  return 0;
677  }
678 
679  /* toclient */
680  } else {
681  if (state->tc_current_line_lf_seen == 1) {
682  /* we have seen the lf for the previous line. Clear the parser
683  * details to parse new line */
684  state->tc_current_line_lf_seen = 0;
685  if (state->tc_current_line_db == 1) {
686  state->tc_current_line_db = 0;
687  SCFree(state->tc_db);
688  state->tc_db = NULL;
689  state->tc_db_len = 0;
690  state->current_line = NULL;
691  state->current_line_len = 0;
692  }
693  }
694 
695  uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len);
696 
697  if (lf_idx == NULL) {
698  /* fragmented lines. Decoder event for special cases. Not all
699  * fragmented lines should be treated as a possible evasion
700  * attempt. With multi payload smtp chunks we can have valid
701  * cases of fragmentation. But within the same segment chunk
702  * if we see fragmentation then it's definitely something you
703  * should alert about */
704  if (state->tc_current_line_db == 0) {
705  state->tc_db = SCMalloc(state->input_len);
706  if (state->tc_db == NULL) {
707  return -1;
708  }
709  state->tc_current_line_db = 1;
710  memcpy(state->tc_db, state->input, state->input_len);
711  state->tc_db_len = state->input_len;
712  } else {
713  ptmp = SCRealloc(state->tc_db,
714  (state->tc_db_len + state->input_len));
715  if (ptmp == NULL) {
716  SCFree(state->tc_db);
717  state->tc_db = NULL;
718  state->tc_db_len = 0;
719  return -1;
720  }
721  state->tc_db = ptmp;
722 
723  memcpy(state->tc_db + state->tc_db_len,
724  state->input, state->input_len);
725  state->tc_db_len += state->input_len;
726  } /* else */
727  state->input += state->input_len;
728  state->input_len = 0;
729 
730  return -1;
731 
732  } else {
733  state->tc_current_line_lf_seen = 1;
734 
735  if (state->tc_current_line_db == 1) {
736  ptmp = SCRealloc(state->tc_db,
737  (state->tc_db_len + (lf_idx + 1 - state->input)));
738  if (ptmp == NULL) {
739  SCFree(state->tc_db);
740  state->tc_db = NULL;
741  state->tc_db_len = 0;
742  return -1;
743  }
744  state->tc_db = ptmp;
745 
746  memcpy(state->tc_db + state->tc_db_len,
747  state->input, (lf_idx + 1 - state->input));
748  state->tc_db_len += (lf_idx + 1 - state->input);
749 
750  if (state->tc_db_len > 1 &&
751  state->tc_db[state->tc_db_len - 2] == 0x0D) {
752  state->tc_db_len -= 2;
753  state->current_line_delimiter_len = 2;
754  } else {
755  state->tc_db_len -= 1;
756  state->current_line_delimiter_len = 1;
757  }
758 
759  state->current_line = state->tc_db;
760  state->current_line_len = state->tc_db_len;
761 
762  } else {
763  state->current_line = state->input;
764  state->current_line_len = lf_idx - state->input;
765 
766  if (state->input != lf_idx &&
767  *(lf_idx - 1) == 0x0D) {
768  state->current_line_len--;
769  state->current_line_delimiter_len = 2;
770  } else {
771  state->current_line_delimiter_len = 1;
772  }
773  }
774 
775  state->input_len -= (lf_idx - state->input) + 1;
776  state->input = (lf_idx + 1);
777 
778  return 0;
779  } /* else - if (lf_idx == NULL) */
780  }
781 
782 }
783 
784 static int SMTPInsertCommandIntoCommandBuffer(uint8_t command, SMTPState *state, Flow *f)
785 {
786  SCEnter();
787  void *ptmp;
788 
789  if (state->cmds_cnt >= state->cmds_buffer_len) {
790  int increment = SMTP_COMMAND_BUFFER_STEPS;
791  if ((int)(state->cmds_buffer_len + SMTP_COMMAND_BUFFER_STEPS) > (int)USHRT_MAX) {
792  increment = USHRT_MAX - state->cmds_buffer_len;
793  }
794 
795  ptmp = SCRealloc(state->cmds,
796  sizeof(uint8_t) * (state->cmds_buffer_len + increment));
797  if (ptmp == NULL) {
798  SCFree(state->cmds);
799  state->cmds = NULL;
800  SCLogDebug("SCRealloc failure");
801  return -1;
802  }
803  state->cmds = ptmp;
804 
805  state->cmds_buffer_len += increment;
806  }
807  if (state->cmds_cnt >= 1 &&
808  ((state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_STARTTLS) ||
809  (state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_DATA))) {
810  /* decoder event */
812  /* we have to have EHLO, DATA, VRFY, EXPN, TURN, QUIT, NOOP,
813  * STARTTLS as the last command in pipelined mode */
814  }
815 
816  /** \todo decoder event */
817  if ((int)(state->cmds_cnt + 1) > (int)USHRT_MAX) {
818  SCLogDebug("command buffer overflow");
819  return -1;
820  }
821 
822  state->cmds[state->cmds_cnt] = command;
823  state->cmds_cnt++;
824 
825  return 0;
826 }
827 
828 static int SMTPProcessCommandBDAT(SMTPState *state, Flow *f,
829  AppLayerParserState *pstate)
830 {
831  SCEnter();
832 
833  state->bdat_chunk_idx += (state->current_line_len +
835  if (state->bdat_chunk_idx > state->bdat_chunk_len) {
837  /* decoder event */
838  SMTPSetEvent(state, SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED);
839  SCReturnInt(-1);
840  } else if (state->bdat_chunk_idx == state->bdat_chunk_len) {
842  }
843 
844  SCReturnInt(0);
845 }
846 
847 static void SetMimeEvents(SMTPState *state)
848 {
849  if (state->curr_tx->mime_state->msg == NULL) {
850  return;
851  }
852 
853  /* Generate decoder events */
854  MimeDecEntity *msg = state->curr_tx->mime_state->msg;
855  if (msg->anomaly_flags & ANOM_INVALID_BASE64) {
856  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_BASE64);
857  }
858  if (msg->anomaly_flags & ANOM_INVALID_QP) {
859  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_QP);
860  }
861  if (msg->anomaly_flags & ANOM_LONG_LINE) {
862  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_LINE);
863  }
864  if (msg->anomaly_flags & ANOM_LONG_ENC_LINE) {
865  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE);
866  }
867  if (msg->anomaly_flags & ANOM_LONG_HEADER_NAME) {
868  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME);
869  }
870  if (msg->anomaly_flags & ANOM_LONG_HEADER_VALUE) {
871  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE);
872  }
873  if (msg->anomaly_flags & ANOM_MALFORMED_MSG) {
874  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_MALFORMED_MSG);
875  }
876  if (msg->anomaly_flags & ANOM_LONG_BOUNDARY) {
877  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG);
878  }
879  if (msg->anomaly_flags & ANOM_LONG_FILENAME) {
880  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_FILENAME);
881  }
882 }
883 
884 static inline void SMTPTransactionComplete(SMTPState *state)
885 {
886  DEBUG_VALIDATE_BUG_ON(state->curr_tx == NULL);
887  if (state->curr_tx)
888  state->curr_tx->done = 1;
889 }
890 
891 /**
892  * \retval 0 ok
893  * \retval -1 error
894  */
895 static int SMTPProcessCommandDATA(SMTPState *state, Flow *f,
896  AppLayerParserState *pstate)
897 {
898  SCEnter();
899 
901  /* looks like are still waiting for a confirmation from the server */
902  return 0;
903  }
904 
905  if (state->current_line_len == 1 && state->current_line[0] == '.') {
907  /* kinda like a hack. The mail sent in DATA mode, would be
908  * acknowledged with a reply. We insert a dummy command to
909  * the command buffer to be used by the reply handler to match
910  * the reply received */
911  SMTPInsertCommandIntoCommandBuffer(SMTP_COMMAND_DATA_MODE, state, f);
913  /* we use this as the signal that message data is complete. */
914  FileCloseFile(state->files_ts, NULL, 0, 0);
915  } else if (smtp_config.decode_mime &&
916  state->curr_tx->mime_state != NULL) {
917  /* Complete parsing task */
918  int ret = MimeDecParseComplete(state->curr_tx->mime_state);
919  if (ret != MIME_DEC_OK) {
920  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_PARSE_FAILED);
921  SCLogDebug("MimeDecParseComplete() function failed");
922  }
923 
924  /* Generate decoder events */
925  SetMimeEvents(state);
926  }
927  SMTPTransactionComplete(state);
928  SCLogDebug("marked tx as done");
929  } else if (smtp_config.raw_extraction) {
930  // message not over, store the line. This is a substitution of
931  // ProcessDataChunk
932  FileAppendData(state->files_ts, state->current_line,
934  }
935 
936  /* If DATA, then parse out a MIME message */
937  if (state->current_command == SMTP_COMMAND_DATA &&
939 
940  if (smtp_config.decode_mime && state->curr_tx->mime_state != NULL) {
941  int ret = MimeDecParseLine((const uint8_t *) state->current_line,
943  state->curr_tx->mime_state);
944  if (ret != MIME_DEC_OK) {
945  if (ret != MIME_DEC_ERR_STATE) {
946  /* Generate decoder events */
947  SetMimeEvents(state);
948 
949  SCLogDebug("MimeDecParseLine() function returned an error code: %d", ret);
950  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_PARSE_FAILED);
951  }
952  /* keep the parser in its error state so we can log that,
953  * the parser will reject new data */
954  }
955  }
956  }
957 
958  return 0;
959 }
960 
961 static int SMTPProcessCommandSTARTTLS(SMTPState *state, Flow *f,
962  AppLayerParserState *pstate)
963 {
964  return 0;
965 }
966 
967 static inline bool IsReplyToCommand(const SMTPState *state, const uint8_t cmd)
968 {
969  return (state->cmds_idx < state->cmds_buffer_len &&
970  state->cmds[state->cmds_idx] == cmd);
971 }
972 
973 static int SMTPProcessReply(SMTPState *state, Flow *f,
974  AppLayerParserState *pstate,
975  SMTPThreadCtx *td)
976 {
977  SCEnter();
978 
979  /* the reply code has to contain at least 3 bytes, to hold the 3 digit
980  * reply code */
981  if (state->current_line_len < 3) {
982  /* decoder event */
983  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
984  return -1;
985  }
986 
987  if (state->current_line_len >= 4) {
989  if (state->current_line[3] != '-') {
991  }
992  } else {
993  if (state->current_line[3] == '-') {
995  }
996  }
997  } else {
1000  }
1001  }
1002 
1003  /* I don't like this pmq reset here. We'll devise a method later, that
1004  * should make the use of the mpm very efficient */
1005  PmqReset(td->pmq);
1006  int mpm_cnt = mpm_table[SMTP_MPM].Search(smtp_mpm_ctx, td->smtp_mpm_thread_ctx,
1007  td->pmq, state->current_line,
1008  3);
1009  if (mpm_cnt == 0) {
1010  /* set decoder event - reply code invalid */
1011  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
1012  SCLogDebug("invalid reply code %02x %02x %02x",
1013  state->current_line[0], state->current_line[1], state->current_line[2]);
1014  SCReturnInt(-1);
1015  }
1016  enum SMTPCode reply_code = smtp_reply_map[td->pmq->rule_id_array[0]].enum_value;
1017  SCLogDebug("REPLY: reply_code %u / %s", reply_code,
1018  smtp_reply_map[reply_code].enum_name);
1019 
1020  if (state->cmds_idx == state->cmds_cnt) {
1022  /* the first server reply can be a multiline message. Let's
1023  * flag the fact that we have seen the first reply only at the end
1024  * of a multiline reply
1025  */
1028  if (reply_code == SMTP_REPLY_220)
1029  SCReturnInt(0);
1030  else {
1031  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
1032  SCReturnInt(0);
1033  }
1034  } else {
1035  /* decoder event - unable to match reply with request */
1036  SCLogDebug("unable to match reply with request");
1037  SCReturnInt(0);
1038  }
1039  }
1040 
1041  if (state->cmds_cnt == 0) {
1042  /* reply but not a command we have stored, fall through */
1043  } else if (IsReplyToCommand(state, SMTP_COMMAND_STARTTLS)) {
1044  if (reply_code == SMTP_REPLY_220) {
1045  /* we are entering STARRTTLS data mode */
1048  SMTPTransactionComplete(state);
1049  } else {
1050  /* decoder event */
1051  SMTPSetEvent(state, SMTP_DECODER_EVENT_TLS_REJECTED);
1052  }
1053  } else if (IsReplyToCommand(state, SMTP_COMMAND_DATA)) {
1054  if (reply_code == SMTP_REPLY_354) {
1055  /* Next comes the mail for the DATA command in toserver direction */
1057  } else {
1058  /* decoder event */
1059  SMTPSetEvent(state, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED);
1060  }
1061  } else if (IsReplyToCommand(state, SMTP_COMMAND_RSET)) {
1062  if (reply_code == SMTP_REPLY_250) {
1063  SMTPTransactionComplete(state);
1064  }
1065  } else {
1066  /* we don't care for any other command for now */
1067  }
1068 
1069  /* if it is a multi-line reply, we need to move the index only once for all
1070  * the line of the reply. We unset the multiline flag on the last
1071  * line of the multiline reply, following which we increment the index */
1073  state->cmds_idx++;
1074  } else if (state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1075  /* we check if the server is indicating pipelining support */
1076  if (reply_code == SMTP_REPLY_250 && state->current_line_len == 14 &&
1077  SCMemcmpLowercase("pipelining", state->current_line+4, 10) == 0) {
1079  }
1080  }
1081 
1082  /* if we have matched all the buffered commands, reset the cnt and index */
1083  if (state->cmds_idx == state->cmds_cnt) {
1084  state->cmds_cnt = 0;
1085  state->cmds_idx = 0;
1086  }
1087 
1088  return 0;
1089 }
1090 
1091 static int SMTPParseCommandBDAT(SMTPState *state)
1092 {
1093  SCEnter();
1094 
1095  int i = 4;
1096  while (i < state->current_line_len) {
1097  if (state->current_line[i] != ' ') {
1098  break;
1099  }
1100  i++;
1101  }
1102  if (i == 4) {
1103  /* decoder event */
1104  return -1;
1105  }
1106  if (i == state->current_line_len) {
1107  /* decoder event */
1108  return -1;
1109  }
1110  char *endptr = NULL;
1111  state->bdat_chunk_len = strtoul((const char *)state->current_line + i,
1112  (char **)&endptr, 10);
1113  if ((uint8_t *)endptr == state->current_line + i) {
1114  /* decoder event */
1115  return -1;
1116  }
1117 
1118  return 0;
1119 }
1120 
1121 static int SMTPParseCommandWithParam(SMTPState *state, uint8_t prefix_len, uint8_t **target, uint16_t *target_len)
1122 {
1123  int i = prefix_len + 1;
1124  int spc_i = 0;
1125 
1126  while (i < state->current_line_len) {
1127  if (state->current_line[i] != ' ') {
1128  break;
1129  }
1130  i++;
1131  }
1132 
1133  /* rfc1870: with the size extension the mail from can be followed by an option.
1134  We use the space separator to detect it. */
1135  spc_i = i;
1136  while (spc_i < state->current_line_len) {
1137  if (state->current_line[spc_i] == ' ') {
1138  break;
1139  }
1140  spc_i++;
1141  }
1142 
1143  *target = SCMalloc(spc_i - i + 1);
1144  if (*target == NULL)
1145  return -1;
1146  memcpy(*target, state->current_line + i, spc_i - i);
1147  (*target)[spc_i - i] = '\0';
1148  *target_len = spc_i - i;
1149 
1150  return 0;
1151 }
1152 
1153 static int SMTPParseCommandHELO(SMTPState *state)
1154 {
1155  if (state->helo) {
1156  SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1157  return 0;
1158  }
1159  return SMTPParseCommandWithParam(state, 4, &state->helo, &state->helo_len);
1160 }
1161 
1162 static int SMTPParseCommandMAILFROM(SMTPState *state)
1163 {
1164  if (state->curr_tx->mail_from) {
1165  SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1166  return 0;
1167  }
1168  return SMTPParseCommandWithParam(state, 9,
1169  &state->curr_tx->mail_from,
1170  &state->curr_tx->mail_from_len);
1171 }
1172 
1173 static int SMTPParseCommandRCPTTO(SMTPState *state)
1174 {
1175  uint8_t *rcptto;
1176  uint16_t rcptto_len;
1177 
1178  if (SMTPParseCommandWithParam(state, 7, &rcptto, &rcptto_len) == 0) {
1179  SMTPString *rcptto_str = SMTPStringAlloc();
1180  if (rcptto_str) {
1181  rcptto_str->str = rcptto;
1182  rcptto_str->len = rcptto_len;
1183  TAILQ_INSERT_TAIL(&state->curr_tx->rcpt_to_list, rcptto_str, next);
1184  } else {
1185  SCFree(rcptto);
1186  return -1;
1187  }
1188  } else {
1189  return -1;
1190  }
1191  return 0;
1192 }
1193 
1194 /* consider 'rset' and 'quit' to be part of the existing state */
1195 static int NoNewTx(SMTPState *state)
1196 {
1198  if (state->current_line_len >= 4 &&
1199  SCMemcmpLowercase("rset", state->current_line, 4) == 0) {
1200  return 1;
1201  } else if (state->current_line_len >= 4 &&
1202  SCMemcmpLowercase("quit", state->current_line, 4) == 0) {
1203  return 1;
1204  }
1205  }
1206  return 0;
1207 }
1208 
1209 static int SMTPProcessRequest(SMTPState *state, Flow *f,
1210  AppLayerParserState *pstate)
1211 {
1212  SCEnter();
1213  SMTPTransaction *tx = state->curr_tx;
1214 
1215  if (state->curr_tx == NULL || (state->curr_tx->done && !NoNewTx(state))) {
1216  tx = SMTPTransactionCreate();
1217  if (tx == NULL)
1218  return -1;
1219  state->curr_tx = tx;
1220  TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
1221  tx->tx_id = state->tx_cnt++;
1222 
1223  /* keep track of the start of the tx */
1227  }
1228 
1229  state->toserver_data_count += (
1230  state->current_line_len +
1232 
1234  SMTPSetEvent(state, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE);
1235  }
1236 
1237  /* there are 2 commands that can push it into this COMMAND_DATA mode -
1238  * STARTTLS and DATA */
1240  int r = 0;
1241 
1242  if (state->current_line_len >= 8 &&
1243  SCMemcmpLowercase("starttls", state->current_line, 8) == 0) {
1245  } else if (state->current_line_len >= 4 &&
1246  SCMemcmpLowercase("data", state->current_line, 4) == 0) {
1249  const char *msgname = "rawmsg"; /* XXX have a better name */
1250  if (state->files_ts == NULL)
1251  state->files_ts = FileContainerAlloc();
1252  if (state->files_ts == NULL) {
1253  return -1;
1254  }
1255  if (state->tx_cnt > 1 && !state->curr_tx->done) {
1256  // we did not close the previous tx, set error
1257  SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT);
1258  FileCloseFile(state->files_ts, NULL, 0, FILE_TRUNCATED);
1259  tx = SMTPTransactionCreate();
1260  if (tx == NULL)
1261  return -1;
1262  state->curr_tx = tx;
1263  TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
1264  tx->tx_id = state->tx_cnt++;
1265  }
1267  state->file_track_id++,
1268  (uint8_t*) msgname, strlen(msgname), NULL, 0,
1270  SMTPNewFile(state->curr_tx, state->files_ts->tail);
1271  }
1272  } else if (smtp_config.decode_mime) {
1273  if (tx->mime_state) {
1274  /* We have 2 chained mails and did not detect the end
1275  * of first one. So we start a new transaction. */
1277  SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT);
1278  tx = SMTPTransactionCreate();
1279  if (tx == NULL)
1280  return -1;
1281  state->curr_tx = tx;
1282  TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
1283  tx->tx_id = state->tx_cnt++;
1284  }
1286  if (tx->mime_state == NULL) {
1287  SCLogError(SC_ERR_MEM_ALLOC, "MimeDecInitParser() failed to "
1288  "allocate data");
1289  return MIME_DEC_ERR_MEM;
1290  }
1291 
1292  /* Add new MIME message to end of list */
1293  if (tx->msg_head == NULL) {
1294  tx->msg_head = tx->mime_state->msg;
1295  tx->msg_tail = tx->mime_state->msg;
1296  }
1297  else {
1298  tx->msg_tail->next = tx->mime_state->msg;
1299  tx->msg_tail = tx->mime_state->msg;
1300  }
1301  }
1302  /* Enter immediately data mode without waiting for server reply */
1305  }
1306  } else if (state->current_line_len >= 4 &&
1307  SCMemcmpLowercase("bdat", state->current_line, 4) == 0) {
1308  r = SMTPParseCommandBDAT(state);
1309  if (r == -1) {
1310  SCReturnInt(-1);
1311  }
1314  } else if (state->current_line_len >= 4 &&
1315  ((SCMemcmpLowercase("helo", state->current_line, 4) == 0) ||
1316  SCMemcmpLowercase("ehlo", state->current_line, 4) == 0)) {
1317  r = SMTPParseCommandHELO(state);
1318  if (r == -1) {
1319  SCReturnInt(-1);
1320  }
1322  } else if (state->current_line_len >= 9 &&
1323  SCMemcmpLowercase("mail from", state->current_line, 9) == 0) {
1324  r = SMTPParseCommandMAILFROM(state);
1325  if (r == -1) {
1326  SCReturnInt(-1);
1327  }
1329  } else if (state->current_line_len >= 7 &&
1330  SCMemcmpLowercase("rcpt to", state->current_line, 7) == 0) {
1331  r = SMTPParseCommandRCPTTO(state);
1332  if (r == -1) {
1333  SCReturnInt(-1);
1334  }
1336  } else if (state->current_line_len >= 4 &&
1337  SCMemcmpLowercase("rset", state->current_line, 4) == 0) {
1338  // Resets chunk index in case of connection reuse
1339  state->bdat_chunk_idx = 0;
1341  } else {
1343  }
1344 
1345  /* Every command is inserted into a command buffer, to be matched
1346  * against reply(ies) sent by the server */
1347  if (SMTPInsertCommandIntoCommandBuffer(state->current_command,
1348  state, f) == -1) {
1349  SCReturnInt(-1);
1350  }
1351 
1352  SCReturnInt(r);
1353  }
1354 
1355  switch (state->current_command) {
1356  case SMTP_COMMAND_STARTTLS:
1357  return SMTPProcessCommandSTARTTLS(state, f, pstate);
1358 
1359  case SMTP_COMMAND_DATA:
1360  return SMTPProcessCommandDATA(state, f, pstate);
1361 
1362  case SMTP_COMMAND_BDAT:
1363  return SMTPProcessCommandBDAT(state, f, pstate);
1364 
1365  default:
1366  /* we have nothing to do with any other command at this instant.
1367  * Just let it go through */
1368  SCReturnInt(0);
1369  }
1370 }
1371 
1372 static AppLayerResult SMTPParse(int direction, Flow *f, SMTPState *state,
1373  AppLayerParserState *pstate, const uint8_t *input,
1374  uint32_t input_len,
1375  SMTPThreadCtx *thread_data)
1376 {
1377  SCEnter();
1378 
1379  if (input == NULL &&
1380  ((direction == 0 && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) ||
1381  (direction == 1 && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC)))) {
1383  } else if (input == NULL || input_len == 0) {
1385  }
1386 
1387  state->input = input;
1388  state->input_len = input_len;
1389  state->direction = direction;
1390 
1391  /* toserver */
1392  if (direction == 0) {
1393  while (SMTPGetLine(state) >= 0) {
1394  if (SMTPProcessRequest(state, f, pstate) == -1)
1396  }
1397 
1398  /* toclient */
1399  } else {
1400  while (SMTPGetLine(state) >= 0) {
1401  if (SMTPProcessReply(state, f, pstate, thread_data) == -1)
1403  }
1404  }
1405 
1407 }
1408 
1409 static AppLayerResult SMTPParseClientRecord(Flow *f, void *alstate,
1410  AppLayerParserState *pstate,
1411  const uint8_t *input, uint32_t input_len,
1412  void *local_data, const uint8_t flags)
1413 {
1414  SCEnter();
1415 
1416  /* first arg 0 is toserver */
1417  return SMTPParse(0, f, alstate, pstate, input, input_len, local_data);
1418 }
1419 
1420 static AppLayerResult SMTPParseServerRecord(Flow *f, void *alstate,
1421  AppLayerParserState *pstate,
1422  const uint8_t *input, uint32_t input_len,
1423  void *local_data, const uint8_t flags)
1424 {
1425  SCEnter();
1426 
1427  /* first arg 1 is toclient */
1428  return SMTPParse(1, f, alstate, pstate, input, input_len, local_data);
1429 }
1430 
1431 /**
1432  * \internal
1433  * \brief Function to allocate SMTP state memory.
1434  */
1435 void *SMTPStateAlloc(void *orig_state, AppProto proto_orig)
1436 {
1437  SMTPState *smtp_state = SCMalloc(sizeof(SMTPState));
1438  if (unlikely(smtp_state == NULL))
1439  return NULL;
1440  memset(smtp_state, 0, sizeof(SMTPState));
1441 
1442  smtp_state->cmds = SCMalloc(sizeof(uint8_t) *
1444  if (smtp_state->cmds == NULL) {
1445  SCFree(smtp_state);
1446  return NULL;
1447  }
1449 
1450  TAILQ_INIT(&smtp_state->tx_list);
1451 
1452  return smtp_state;
1453 }
1454 
1455 static SMTPString *SMTPStringAlloc(void)
1456 {
1457  SMTPString *smtp_string = SCMalloc(sizeof(SMTPString));
1458  if (unlikely(smtp_string == NULL))
1459  return NULL;
1460  memset(smtp_string, 0, sizeof(SMTPString));
1461 
1462  return smtp_string;
1463 }
1464 
1465 
1466 static void SMTPStringFree(SMTPString *str)
1467 {
1468  if (str->str) {
1469  SCFree(str->str);
1470  }
1471  SCFree(str);
1472 }
1473 
1474 static void *SMTPLocalStorageAlloc(void)
1475 {
1476  /* needed by the mpm */
1477  SMTPThreadCtx *td = SCCalloc(1, sizeof(*td));
1478  if (td == NULL) {
1479  exit(EXIT_FAILURE);
1480  }
1481 
1482  td->pmq = SCCalloc(1, sizeof(*td->pmq));
1483  if (td->pmq == NULL) {
1484  exit(EXIT_FAILURE);
1485  }
1486  PmqSetup(td->pmq);
1487 
1488  td->smtp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx));
1489  if (unlikely(td->smtp_mpm_thread_ctx == NULL)) {
1490  exit(EXIT_FAILURE);
1491  }
1493  return td;
1494 }
1495 
1496 static void SMTPLocalStorageFree(void *ptr)
1497 {
1498  SMTPThreadCtx *td = ptr;
1499  if (td != NULL) {
1500  if (td->pmq != NULL) {
1501  PmqFree(td->pmq);
1502  SCFree(td->pmq);
1503  }
1504 
1505  if (td->smtp_mpm_thread_ctx != NULL) {
1508  }
1509 
1510  SCFree(td);
1511  }
1512 
1513  return;
1514 }
1515 
1516 static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state)
1517 {
1518  if (tx->mime_state != NULL) {
1520  }
1521  /* Free list of MIME message recursively */
1523 
1524  if (tx->decoder_events != NULL)
1526 
1527  if (tx->de_state != NULL)
1529 
1530  if (tx->mail_from)
1531  SCFree(tx->mail_from);
1532 
1533  SMTPString *str = NULL;
1534  while ((str = TAILQ_FIRST(&tx->rcpt_to_list))) {
1535  TAILQ_REMOVE(&tx->rcpt_to_list, str, next);
1536  SMTPStringFree(str);
1537  }
1538 #if 0
1539  if (tx->decoder_events->cnt <= smtp_state->events)
1540  smtp_state->events -= tx->decoder_events->cnt;
1541  else
1542  smtp_state->events = 0;
1543 #endif
1544  SCFree(tx);
1545 }
1546 
1547 /**
1548  * \internal
1549  * \brief Function to free SMTP state memory.
1550  */
1551 static void SMTPStateFree(void *p)
1552 {
1553  SMTPState *smtp_state = (SMTPState *)p;
1554 
1555  if (smtp_state->cmds != NULL) {
1556  SCFree(smtp_state->cmds);
1557  }
1558  if (smtp_state->ts_current_line_db) {
1559  SCFree(smtp_state->ts_db);
1560  }
1561  if (smtp_state->tc_current_line_db) {
1562  SCFree(smtp_state->tc_db);
1563  }
1564 
1565  if (smtp_state->helo) {
1566  SCFree(smtp_state->helo);
1567  }
1568 
1569  FileContainerFree(smtp_state->files_ts);
1570 
1571  SMTPTransaction *tx = NULL;
1572  while ((tx = TAILQ_FIRST(&smtp_state->tx_list))) {
1573  TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1574  SMTPTransactionFree(tx, smtp_state);
1575  }
1576 
1577  SCFree(smtp_state);
1578 
1579  return;
1580 }
1581 
1582 static void SMTPSetMpmState(void)
1583 {
1584  smtp_mpm_ctx = SCMalloc(sizeof(MpmCtx));
1585  if (unlikely(smtp_mpm_ctx == NULL)) {
1586  exit(EXIT_FAILURE);
1587  }
1588  memset(smtp_mpm_ctx, 0, sizeof(MpmCtx));
1589  MpmInitCtx(smtp_mpm_ctx, SMTP_MPM);
1590 
1591  uint32_t i = 0;
1592  for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) {
1593  SCEnumCharMap *map = &smtp_reply_map[i];
1594  /* The third argument is 3, because reply code is always 3 bytes. */
1595  MpmAddPatternCI(smtp_mpm_ctx, (uint8_t *)map->enum_name, 3,
1596  0 /* defunct */, 0 /* defunct */,
1597  i /* pattern id */, i /* rule id */ , 0 /* no flags */);
1598  }
1599 
1600  mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx);
1601 
1602 }
1603 
1604 static void SMTPFreeMpmState(void)
1605 {
1606  if (smtp_mpm_ctx != NULL) {
1607  mpm_table[SMTP_MPM].DestroyCtx(smtp_mpm_ctx);
1608  SCFree(smtp_mpm_ctx);
1609  smtp_mpm_ctx = NULL;
1610  }
1611 }
1612 
1613 static int SMTPStateGetEventInfo(const char *event_name,
1614  int *event_id, AppLayerEventType *event_type)
1615 {
1616  *event_id = SCMapEnumNameToValue(event_name, smtp_decoder_event_table);
1617  if (*event_id == -1) {
1618  SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
1619  "smtp's enum map table.", event_name);
1620  /* yes this is fatal */
1621  return -1;
1622  }
1623 
1624  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
1625 
1626  return 0;
1627 }
1628 
1629 static int SMTPStateGetEventInfoById(int event_id, const char **event_name,
1630  AppLayerEventType *event_type)
1631 {
1632  *event_name = SCMapEnumValueToName(event_id, smtp_decoder_event_table);
1633  if (*event_name == NULL) {
1634  SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%d\" not present in "
1635  "smtp's enum map table.", event_id);
1636  /* yes this is fatal */
1637  return -1;
1638  }
1639 
1640  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
1641 
1642  return 0;
1643 }
1644 
1645 static int SMTPRegisterPatternsForProtocolDetection(void)
1646 {
1648  "EHLO", 4, 0, STREAM_TOSERVER) < 0)
1649  {
1650  return -1;
1651  }
1653  "HELO", 4, 0, STREAM_TOSERVER) < 0)
1654  {
1655  return -1;
1656  }
1658  "QUIT", 4, 0, STREAM_TOSERVER) < 0)
1659  {
1660  return -1;
1661  }
1662 
1663  return 0;
1664 }
1665 
1666 static void SMTPStateTransactionFree (void *state, uint64_t tx_id)
1667 {
1668  SMTPState *smtp_state = state;
1669  SMTPTransaction *tx = NULL;
1670  TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
1671  if (tx_id < tx->tx_id)
1672  break;
1673  else if (tx_id > tx->tx_id)
1674  continue;
1675 
1676  if (tx == smtp_state->curr_tx)
1677  smtp_state->curr_tx = NULL;
1678  TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1679  SMTPTransactionFree(tx, state);
1680  break;
1681  }
1682 
1683 
1684 }
1685 
1686 /** \retval cnt highest tx id */
1687 static uint64_t SMTPStateGetTxCnt(void *state)
1688 {
1689  uint64_t cnt = 0;
1690  SMTPState *smtp_state = state;
1691  if (smtp_state) {
1692  cnt = smtp_state->tx_cnt;
1693  }
1694  SCLogDebug("returning %"PRIu64, cnt);
1695  return cnt;
1696 }
1697 
1698 static void *SMTPStateGetTx(void *state, uint64_t id)
1699 {
1700  SMTPState *smtp_state = state;
1701  if (smtp_state) {
1702  SMTPTransaction *tx = NULL;
1703 
1704  if (smtp_state->curr_tx == NULL)
1705  return NULL;
1706  if (smtp_state->curr_tx->tx_id == id)
1707  return smtp_state->curr_tx;
1708 
1709  TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
1710  if (tx->tx_id == id)
1711  return tx;
1712  }
1713  }
1714  return NULL;
1715 
1716 }
1717 
1718 static int SMTPStateGetAlstateProgressCompletionStatus(uint8_t direction) {
1719  return 1;
1720 }
1721 
1722 static int SMTPStateGetAlstateProgress(void *vtx, uint8_t direction)
1723 {
1724  SMTPTransaction *tx = vtx;
1725  return tx->done;
1726 }
1727 
1728 static FileContainer *SMTPStateGetFiles(void *state, uint8_t direction)
1729 {
1730  if (state == NULL)
1731  return NULL;
1732 
1733  SMTPState *smtp_state = (SMTPState *)state;
1734 
1735  if (direction & STREAM_TOCLIENT) {
1736  SCReturnPtr(NULL, "FileContainer");
1737  } else {
1738  SCLogDebug("smtp_state->files_ts %p", smtp_state->files_ts);
1739  SCReturnPtr(smtp_state->files_ts, "FileContainer");
1740  }
1741 }
1742 
1743 static void SMTPStateTruncate(void *state, uint8_t direction)
1744 {
1745  FileContainer *fc = SMTPStateGetFiles(state, direction);
1746  if (fc != NULL) {
1747  SCLogDebug("truncating stream, closing files in %s direction (container %p)",
1748  direction & STREAM_TOCLIENT ? "STREAM_TOCLIENT" : "STREAM_TOSERVER", fc);
1750  }
1751 }
1752 
1753 static AppLayerDecoderEvents *SMTPGetEvents(void *tx)
1754 {
1755  SCLogDebug("get SMTP events for TX %p", tx);
1756 
1757  return ((SMTPTransaction *)tx)->decoder_events;
1758 }
1759 
1760 static DetectEngineState *SMTPGetTxDetectState(void *vtx)
1761 {
1762  SMTPTransaction *tx = (SMTPTransaction *)vtx;
1763  return tx->de_state;
1764 }
1765 
1766 static int SMTPSetTxDetectState(void *vtx, DetectEngineState *s)
1767 {
1768  SMTPTransaction *tx = (SMTPTransaction *)vtx;
1769  tx->de_state = s;
1770  return 0;
1771 }
1772 
1773 static AppLayerTxData *SMTPGetTxData(void *vtx)
1774 {
1775  SMTPTransaction *tx = (SMTPTransaction *)vtx;
1776  return &tx->tx_data;
1777 }
1778 
1779 /**
1780  * \brief Register the SMTP Protocol parser.
1781  */
1783 {
1784  const char *proto_name = "smtp";
1785 
1786  if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
1788  if (SMTPRegisterPatternsForProtocolDetection() < 0 )
1789  return;
1790  } else {
1791  SCLogInfo("Protocol detection and parser disabled for %s protocol.",
1792  proto_name);
1793  return;
1794  }
1795 
1796  if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
1797  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree);
1798 
1800  SMTPParseClientRecord);
1802  SMTPParseServerRecord);
1803 
1804  AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo);
1805  AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfoById);
1806  AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetEvents);
1808  SMTPGetTxDetectState, SMTPSetTxDetectState);
1809 
1810  AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc,
1811  SMTPLocalStorageFree);
1812 
1813  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTransactionFree);
1814  AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetFiles);
1815  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress);
1816  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt);
1817  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx);
1818  AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxData);
1820  SMTPStateGetAlstateProgressCompletionStatus);
1821  AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTruncate);
1822  } else {
1823  SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
1824  "still on.", proto_name);
1825  }
1826 
1827  SMTPSetMpmState();
1828 
1829  SMTPConfigure();
1830 
1831 #ifdef UNITTESTS
1833 #endif
1834  return;
1835 }
1836 
1837 /**
1838  * \brief Free memory allocated for global SMTP parser state.
1839  */
1841 {
1842  SMTPFreeMpmState();
1843 }
1844 
1845 /***************************************Unittests******************************/
1846 
1847 #ifdef UNITTESTS
1848 
1849 static void SMTPTestInitConfig(void)
1850 {
1852 
1856 
1858 }
1859 
1860 /*
1861  * \test Test STARTTLS.
1862  */
1863 static int SMTPParserTest01(void)
1864 {
1865  int result = 0;
1866  Flow f;
1867  int r = 0;
1868 
1869  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
1870  uint8_t welcome_reply[] = {
1871  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
1872  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1873  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
1874  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
1875  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
1876  0x0d, 0x0a
1877  };
1878  uint32_t welcome_reply_len = sizeof(welcome_reply);
1879 
1880  /* EHLO [192.168.0.158]<CR><LF> */
1881  uint8_t request1[] = {
1882  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39,
1883  0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e,
1884  0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a
1885  };
1886  uint32_t request1_len = sizeof(request1);
1887  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
1888  * 250-SIZE 35882577<CR><LF>
1889  * 250-8BITMIME<CR><LF>
1890  * 250-STARTTLS<CR><LF>
1891  * 250 ENHANCEDSTATUSCODES<CR><LF>
1892  */
1893  uint8_t reply1[] = {
1894  0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67,
1895  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1896  0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75,
1897  0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
1898  0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e,
1899  0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e,
1900  0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30,
1901  0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35,
1902  0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a,
1903  0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54,
1904  0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35,
1905  0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54,
1906  0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20,
1907  0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44,
1908  0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f,
1909  0x44, 0x45, 0x53, 0x0d, 0x0a
1910  };
1911  uint32_t reply1_len = sizeof(reply1);
1912 
1913  /* STARTTLS<CR><LF> */
1914  uint8_t request2[] = {
1915  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
1916  0x0d, 0x0a
1917  };
1918  uint32_t request2_len = sizeof(request2);
1919  /* 220 2.0.0 Ready to start TLS<CR><LF> */
1920  uint8_t reply2[] = {
1921  0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1922  0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20,
1923  0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74,
1924  0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a
1925  };
1926  uint32_t reply2_len = sizeof(reply2);
1927 
1928  TcpSession ssn;
1930 
1931  memset(&f, 0, sizeof(f));
1932  memset(&ssn, 0, sizeof(ssn));
1933 
1934  FLOW_INITIALIZE(&f);
1935  f.protoctx = (void *)&ssn;
1936  f.proto = IPPROTO_TCP;
1937  f.alproto = ALPROTO_SMTP;
1938 
1940  SMTPTestInitConfig();
1941 
1942  FLOWLOCK_WRLOCK(&f);
1943  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1944  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
1945  if (r != 0) {
1946  printf("smtp check returned %" PRId32 ", expected 0: ", r);
1947  FLOWLOCK_UNLOCK(&f);
1948  goto end;
1949  }
1950  FLOWLOCK_UNLOCK(&f);
1951  SMTPState *smtp_state = f.alstate;
1952  if (smtp_state == NULL) {
1953  printf("no smtp state: ");
1954  goto end;
1955  }
1956  if (smtp_state->input_len != 0 ||
1957  smtp_state->cmds_cnt != 0 ||
1958  smtp_state->cmds_idx != 0 ||
1960  printf("smtp parser in inconsistent state\n");
1961  goto end;
1962  }
1963 
1964  FLOWLOCK_WRLOCK(&f);
1965  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1966  STREAM_TOSERVER, request1, request1_len);
1967  if (r != 0) {
1968  printf("smtp check returned %" PRId32 ", expected 0: ", r);
1969  FLOWLOCK_UNLOCK(&f);
1970  goto end;
1971  }
1972  FLOWLOCK_UNLOCK(&f);
1973  if (smtp_state->input_len != 0 ||
1974  smtp_state->cmds_cnt != 1 ||
1975  smtp_state->cmds_idx != 0 ||
1976  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1978  printf("smtp parser in inconsistent state\n");
1979  goto end;
1980  }
1981 
1982  FLOWLOCK_WRLOCK(&f);
1983  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1984  STREAM_TOCLIENT, reply1, reply1_len);
1985  if (r != 0) {
1986  printf("smtp check returned %" PRId32 ", expected 0: ", r);
1987  FLOWLOCK_UNLOCK(&f);
1988  goto end;
1989  }
1990  FLOWLOCK_UNLOCK(&f);
1991  if (smtp_state->input_len != 0 ||
1992  smtp_state->cmds_cnt != 0 ||
1993  smtp_state->cmds_idx != 0 ||
1995  printf("smtp parser in inconsistent state\n");
1996  goto end;
1997  }
1998 
1999  FLOWLOCK_WRLOCK(&f);
2000  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2001  STREAM_TOSERVER, request2, request2_len);
2002  if (r != 0) {
2003  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2004  FLOWLOCK_UNLOCK(&f);
2005  goto end;
2006  }
2007  FLOWLOCK_UNLOCK(&f);
2008  if (smtp_state->input_len != 0 ||
2009  smtp_state->cmds_cnt != 1 ||
2010  smtp_state->cmds_idx != 0 ||
2011  smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
2013  printf("smtp parser in inconsistent state\n");
2014  goto end;
2015  }
2016 
2017  FLOWLOCK_WRLOCK(&f);
2018  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2019  STREAM_TOCLIENT, reply2, reply2_len);
2020  if (r != 0) {
2021  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2022  FLOWLOCK_UNLOCK(&f);
2023  goto end;
2024  }
2025  FLOWLOCK_UNLOCK(&f);
2026  if (smtp_state->input_len != 0 ||
2027  smtp_state->cmds_cnt != 0 ||
2028  smtp_state->cmds_idx != 0 ||
2031  printf("smtp parser in inconsistent state\n");
2032  goto end;
2033  }
2034 
2035  if (!FlowChangeProto(&f)) {
2036  goto end;
2037  }
2038 
2039  result = 1;
2040 end:
2041  if (alp_tctx != NULL)
2044  FLOW_DESTROY(&f);
2045  return result;
2046 }
2047 
2048 /**
2049  * \test Test multiple DATA commands(full mail transactions).
2050  */
2051 static int SMTPParserTest02(void)
2052 {
2053  int result = 0;
2054  Flow f;
2055  int r = 0;
2056 
2057  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
2058  uint8_t welcome_reply[] = {
2059  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
2060  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
2061  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
2062  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
2063  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
2064  0x0d, 0x0a
2065  };
2066  uint32_t welcome_reply_len = sizeof(welcome_reply);
2067 
2068  /* EHLO boo.com<CR><LF> */
2069  uint8_t request1[] = {
2070  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2071  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2072  };
2073  uint32_t request1_len = sizeof(request1);
2074  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
2075  * 250-SIZE 35882577<CR><LF>
2076  * 250-8BITMIME<CR><LF>
2077  * 250-STARTTLS<CR><LF>
2078  * 250 ENHANCEDSTATUSCODES<CR><LF>
2079  */
2080  uint8_t reply1[] = {
2081  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2082  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2083  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2084  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2085  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2086  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2087  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2088  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2089  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2090  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2091  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2092  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2093  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2094  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2095  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2096  };
2097  uint32_t reply1_len = sizeof(reply1);
2098 
2099  /* MAIL FROM:asdff@asdf.com<CR><LF> */
2100  uint8_t request2[] = {
2101  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2102  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
2103  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2104  0x0d, 0x0a
2105  };
2106  uint32_t request2_len = sizeof(request2);
2107  /* 250 2.1.0 Ok<CR><LF> */
2108  uint8_t reply2[] = {
2109  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2110  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2111  };
2112  uint32_t reply2_len = sizeof(reply2);
2113 
2114  /* RCPT TO:bimbs@gmail.com<CR><LF> */
2115  uint8_t request3[] = {
2116  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2117  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2118  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2119  0x0a
2120  };
2121  uint32_t request3_len = sizeof(request3);
2122  /* 250 2.1.5 Ok<CR><LF> */
2123  uint8_t reply3[] = {
2124  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2125  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2126  };
2127  uint32_t reply3_len = sizeof(reply3);
2128 
2129  /* DATA<CR><LF> */
2130  uint8_t request4[] = {
2131  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2132  };
2133  uint32_t request4_len = sizeof(request4);
2134  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2135  uint8_t reply4[] = {
2136  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2137  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2138  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2139  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2140  0x4c, 0x46, 0x3e, 0x0d, 0x0a
2141  };
2142  uint32_t reply4_len = sizeof(reply4);
2143 
2144  /* FROM:asdff@asdf.com<CR><LF> */
2145  uint8_t request5_1[] = {
2146  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2147  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2148  0x63, 0x6f, 0x6d, 0x0d, 0x0a
2149  };
2150  uint32_t request5_1_len = sizeof(request5_1);
2151  /* TO:bimbs@gmail.com<CR><LF> */
2152  uint8_t request5_2[] = {
2153  0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2154  0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2155  0x6f, 0x6d, 0x0d, 0x0a
2156  };
2157  uint32_t request5_2_len = sizeof(request5_2);
2158  /* <CR><LF> */
2159  uint8_t request5_3[] = {
2160  0x0d, 0x0a
2161  };
2162  uint32_t request5_3_len = sizeof(request5_3);
2163  /* this is test mail1<CR><LF> */
2164  uint8_t request5_4[] = {
2165  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2166  0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2167  0x6c, 0x31, 0x0d, 0x0a
2168  };
2169  uint32_t request5_4_len = sizeof(request5_4);
2170  /* .<CR><LF> */
2171  uint8_t request5_5[] = {
2172  0x2e, 0x0d, 0x0a
2173  };
2174  uint32_t request5_5_len = sizeof(request5_5);
2175  /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
2176  uint8_t reply5[] = {
2177  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2178  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2179  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2180  0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
2181  0x46, 0x32, 0x0d, 0x0a
2182  };
2183  uint32_t reply5_len = sizeof(reply5);
2184 
2185  /* MAIL FROM:asdfg@asdf.com<CR><LF> */
2186  uint8_t request6[] = {
2187  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2188  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40,
2189  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2190  0x0d, 0x0a
2191  };
2192  uint32_t request6_len = sizeof(request6);
2193  /* 250 2.1.0 Ok<CR><LF> */
2194  uint8_t reply6[] = {
2195  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2196  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2197  };
2198  uint32_t reply6_len = sizeof(reply6);
2199 
2200  /* RCPT TO:bimbs@gmail.com<CR><LF> */
2201  uint8_t request7[] = {
2202  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2203  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2204  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2205  0x0a
2206  };
2207  uint32_t request7_len = sizeof(request7);
2208  /* 250 2.1.5 Ok<CR><LF> */
2209  uint8_t reply7[] = {
2210  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2211  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2212  };
2213  uint32_t reply7_len = sizeof(reply7);
2214 
2215  /* DATA<CR><LF> */
2216  uint8_t request8[] = {
2217  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2218  };
2219  uint32_t request8_len = sizeof(request8);
2220  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2221  uint8_t reply8[] = {
2222  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2223  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2224  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2225  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2226  0x4c, 0x46, 0x3e, 0x0d, 0x0a
2227  };
2228  uint32_t reply8_len = sizeof(reply8);
2229 
2230  /* FROM:asdfg@gmail.com<CR><LF> */
2231  uint8_t request9_1[] = {
2232  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2233  0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
2234  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2235  };
2236  uint32_t request9_1_len = sizeof(request9_1);
2237  /* TO:bimbs@gmail.com<CR><LF> */
2238  uint8_t request9_2[] = {
2239  0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2240  0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2241  0x6f, 0x6d, 0x0d, 0x0a
2242  };
2243  uint32_t request9_2_len = sizeof(request9_2);
2244  /* <CR><LF> */
2245  uint8_t request9_3[] = {
2246  0x0d, 0x0a
2247  };
2248  uint32_t request9_3_len = sizeof(request9_3);
2249  /* this is test mail2<CR><LF> */
2250  uint8_t request9_4[] = {
2251  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2252  0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2253  0x6c, 0x32, 0x0d, 0x0a
2254  };
2255  uint32_t request9_4_len = sizeof(request9_4);
2256  /* .<CR><LF> */
2257  uint8_t request9_5[] = {
2258  0x2e, 0x0d, 0x0a
2259  };
2260  uint32_t request9_5_len = sizeof(request9_5);
2261  /* 250 2.0.0 Ok: queued as 28CFF20BF2<CR><LF> */
2262  uint8_t reply9[] = {
2263  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2264  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2265  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2266  0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42,
2267  0x46, 0x32, 0x0d, 0x0a
2268  };
2269  uint32_t reply9_len = sizeof(reply9);
2270 
2271  /* QUIT<CR><LF> */
2272  uint8_t request10[] = {
2273  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
2274  };
2275  uint32_t request10_len = sizeof(request10);
2276  /* 221 2.0.0 Bye<CR><LF> */
2277  uint8_t reply10[] = {
2278  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2279  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
2280  };
2281  uint32_t reply10_len = sizeof(reply10);
2282 
2283  TcpSession ssn;
2285 
2286  memset(&f, 0, sizeof(f));
2287  memset(&ssn, 0, sizeof(ssn));
2288 
2289  FLOW_INITIALIZE(&f);
2290  f.protoctx = (void *)&ssn;
2291  f.proto = IPPROTO_TCP;
2292  f.alproto = ALPROTO_SMTP;
2293 
2295  SMTPTestInitConfig();
2296 
2297  FLOWLOCK_WRLOCK(&f);
2298  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2299  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2300  if (r != 0) {
2301  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2302  FLOWLOCK_UNLOCK(&f);
2303  goto end;
2304  }
2305  FLOWLOCK_UNLOCK(&f);
2306  SMTPState *smtp_state = f.alstate;
2307  if (smtp_state == NULL) {
2308  printf("no smtp state: ");
2309  goto end;
2310  }
2311  if (smtp_state->input_len != 0 ||
2312  smtp_state->cmds_cnt != 0 ||
2313  smtp_state->cmds_idx != 0 ||
2315  printf("smtp parser in inconsistent state\n");
2316  goto end;
2317  }
2318 
2319  FLOWLOCK_WRLOCK(&f);
2320  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2321  STREAM_TOSERVER, request1, request1_len);
2322  if (r != 0) {
2323  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2324  FLOWLOCK_UNLOCK(&f);
2325  goto end;
2326  }
2327  FLOWLOCK_UNLOCK(&f);
2328  if (smtp_state->input_len != 0 ||
2329  smtp_state->cmds_cnt != 1 ||
2330  smtp_state->cmds_idx != 0 ||
2331  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2333  printf("smtp parser in inconsistent state\n");
2334  goto end;
2335  }
2336 
2337  FLOWLOCK_WRLOCK(&f);
2338  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2339  STREAM_TOCLIENT, reply1, reply1_len);
2340  if (r != 0) {
2341  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2342  FLOWLOCK_UNLOCK(&f);
2343  goto end;
2344  }
2345  FLOWLOCK_UNLOCK(&f);
2346  if (smtp_state->input_len != 0 ||
2347  smtp_state->cmds_cnt != 0 ||
2348  smtp_state->cmds_idx != 0 ||
2350  printf("smtp parser in inconsistent state\n");
2351  goto end;
2352  }
2353 
2354  FLOWLOCK_WRLOCK(&f);
2355  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2356  STREAM_TOSERVER, request2, request2_len);
2357  if (r != 0) {
2358  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2359  FLOWLOCK_UNLOCK(&f);
2360  goto end;
2361  }
2362  FLOWLOCK_UNLOCK(&f);
2363  if (smtp_state->input_len != 0 ||
2364  smtp_state->cmds_cnt != 1 ||
2365  smtp_state->cmds_idx != 0 ||
2366  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2368  printf("smtp parser in inconsistent state\n");
2369  goto end;
2370  }
2371 
2372  FLOWLOCK_WRLOCK(&f);
2373  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2374  STREAM_TOCLIENT, reply2, reply2_len);
2375  if (r != 0) {
2376  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2377  FLOWLOCK_UNLOCK(&f);
2378  goto end;
2379  }
2380  FLOWLOCK_UNLOCK(&f);
2381  if (smtp_state->input_len != 0 ||
2382  smtp_state->cmds_cnt != 0 ||
2383  smtp_state->cmds_idx != 0 ||
2385  printf("smtp parser in inconsistent state\n");
2386  goto end;
2387  }
2388 
2389  FLOWLOCK_WRLOCK(&f);
2390  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2391  STREAM_TOSERVER, request3, request3_len);
2392  if (r != 0) {
2393  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2394  FLOWLOCK_UNLOCK(&f);
2395  goto end;
2396  }
2397  FLOWLOCK_UNLOCK(&f);
2398  if (smtp_state->input_len != 0 ||
2399  smtp_state->cmds_cnt != 1 ||
2400  smtp_state->cmds_idx != 0 ||
2401  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2403  printf("smtp parser in inconsistent state\n");
2404  goto end;
2405  }
2406 
2407  FLOWLOCK_WRLOCK(&f);
2408  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2409  STREAM_TOCLIENT, reply3, reply3_len);
2410  if (r != 0) {
2411  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2412  FLOWLOCK_UNLOCK(&f);
2413  goto end;
2414  }
2415  FLOWLOCK_UNLOCK(&f);
2416  if (smtp_state->input_len != 0 ||
2417  smtp_state->cmds_cnt != 0 ||
2418  smtp_state->cmds_idx != 0 ||
2420  printf("smtp parser in inconsistent state\n");
2421  goto end;
2422  }
2423 
2424  FLOWLOCK_WRLOCK(&f);
2425  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2426  STREAM_TOSERVER, request4, request4_len);
2427  if (r != 0) {
2428  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2429  FLOWLOCK_UNLOCK(&f);
2430  goto end;
2431  }
2432  FLOWLOCK_UNLOCK(&f);
2433  if (smtp_state->input_len != 0 ||
2434  smtp_state->cmds_cnt != 1 ||
2435  smtp_state->cmds_idx != 0 ||
2436  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2438  printf("smtp parser in inconsistent state\n");
2439  goto end;
2440  }
2441 
2442  FLOWLOCK_WRLOCK(&f);
2443  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2444  STREAM_TOCLIENT, reply4, reply4_len);
2445  if (r != 0) {
2446  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2447  FLOWLOCK_UNLOCK(&f);
2448  goto end;
2449  }
2450  FLOWLOCK_UNLOCK(&f);
2451  if (smtp_state->input_len != 0 ||
2452  smtp_state->cmds_cnt != 0 ||
2453  smtp_state->cmds_idx != 0 ||
2456  printf("smtp parser in inconsistent state\n");
2457  goto end;
2458  }
2459 
2460  FLOWLOCK_WRLOCK(&f);
2461  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2462  STREAM_TOSERVER, request5_1, request5_1_len);
2463  if (r != 0) {
2464  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2465  FLOWLOCK_UNLOCK(&f);
2466  goto end;
2467  }
2468  FLOWLOCK_UNLOCK(&f);
2469  if (smtp_state->input_len != 0 ||
2470  smtp_state->cmds_cnt != 0 ||
2471  smtp_state->cmds_idx != 0 ||
2474 
2475  printf("smtp parser in inconsistent state\n");
2476  goto end;
2477  }
2478 
2479  FLOWLOCK_WRLOCK(&f);
2480  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2481  STREAM_TOSERVER, request5_2, request5_2_len);
2482  if (r != 0) {
2483  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2484  FLOWLOCK_UNLOCK(&f);
2485  goto end;
2486  }
2487  FLOWLOCK_UNLOCK(&f);
2488  if (smtp_state->input_len != 0 ||
2489  smtp_state->cmds_cnt != 0 ||
2490  smtp_state->cmds_idx != 0 ||
2493 
2494  printf("smtp parser in inconsistent state\n");
2495  goto end;
2496  }
2497 
2498  FLOWLOCK_WRLOCK(&f);
2499  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2500  STREAM_TOSERVER, request5_3, request5_3_len);
2501  if (r != 0) {
2502  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2503  FLOWLOCK_UNLOCK(&f);
2504  goto end;
2505  }
2506  FLOWLOCK_UNLOCK(&f);
2507  if (smtp_state->input_len != 0 ||
2508  smtp_state->cmds_cnt != 0 ||
2509  smtp_state->cmds_idx != 0 ||
2512 
2513  printf("smtp parser in inconsistent state\n");
2514  goto end;
2515  }
2516 
2517  FLOWLOCK_WRLOCK(&f);
2518  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2519  STREAM_TOSERVER, request5_4, request5_4_len);
2520  if (r != 0) {
2521  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2522  FLOWLOCK_UNLOCK(&f);
2523  goto end;
2524  }
2525  FLOWLOCK_UNLOCK(&f);
2526  if (smtp_state->input_len != 0 ||
2527  smtp_state->cmds_cnt != 0 ||
2528  smtp_state->cmds_idx != 0 ||
2531 
2532  printf("smtp parser in inconsistent state\n");
2533  goto end;
2534  }
2535 
2536  FLOWLOCK_WRLOCK(&f);
2537  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2538  STREAM_TOSERVER, request5_5, request5_5_len);
2539  if (r != 0) {
2540  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2541  FLOWLOCK_UNLOCK(&f);
2542  goto end;
2543  }
2544  FLOWLOCK_UNLOCK(&f);
2545  if (smtp_state->input_len != 0 ||
2546  smtp_state->cmds_cnt != 1 ||
2547  smtp_state->cmds_idx != 0 ||
2548  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2550  printf("smtp parser in inconsistent state\n");
2551  goto end;
2552  }
2553 
2554  FLOWLOCK_WRLOCK(&f);
2555  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2556  STREAM_TOCLIENT, reply5, reply5_len);
2557  if (r != 0) {
2558  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2559  FLOWLOCK_UNLOCK(&f);
2560  goto end;
2561  }
2562  FLOWLOCK_UNLOCK(&f);
2563  if (smtp_state->input_len != 0 ||
2564  smtp_state->cmds_cnt != 0 ||
2565  smtp_state->cmds_idx != 0 ||
2567  printf("smtp parser in inconsistent state\n");
2568  goto end;
2569  }
2570 
2571  FLOWLOCK_WRLOCK(&f);
2572  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2573  STREAM_TOSERVER, request6, request6_len);
2574  if (r != 0) {
2575  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2576  FLOWLOCK_UNLOCK(&f);
2577  goto end;
2578  }
2579  FLOWLOCK_UNLOCK(&f);
2580  if (smtp_state->input_len != 0 ||
2581  smtp_state->cmds_cnt != 1 ||
2582  smtp_state->cmds_idx != 0 ||
2583  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2585  printf("smtp parser in inconsistent state\n");
2586  goto end;
2587  }
2588 
2589  FLOWLOCK_WRLOCK(&f);
2590  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2591  STREAM_TOCLIENT, reply6, reply6_len);
2592  if (r != 0) {
2593  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2594  FLOWLOCK_UNLOCK(&f);
2595  goto end;
2596  }
2597  FLOWLOCK_UNLOCK(&f);
2598  if (smtp_state->input_len != 0 ||
2599  smtp_state->cmds_cnt != 0 ||
2600  smtp_state->cmds_idx != 0 ||
2602  printf("smtp parser in inconsistent state\n");
2603  goto end;
2604  }
2605 
2606  FLOWLOCK_WRLOCK(&f);
2607  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2608  STREAM_TOSERVER, request7, request7_len);
2609  if (r != 0) {
2610  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2611  FLOWLOCK_UNLOCK(&f);
2612  goto end;
2613  }
2614  FLOWLOCK_UNLOCK(&f);
2615  if (smtp_state->input_len != 0 ||
2616  smtp_state->cmds_cnt != 1 ||
2617  smtp_state->cmds_idx != 0 ||
2618  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2620  printf("smtp parser in inconsistent state\n");
2621  goto end;
2622  }
2623 
2624  FLOWLOCK_WRLOCK(&f);
2625  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2626  STREAM_TOCLIENT, reply7, reply7_len);
2627  if (r != 0) {
2628  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2629  FLOWLOCK_UNLOCK(&f);
2630  goto end;
2631  }
2632  FLOWLOCK_UNLOCK(&f);
2633  if (smtp_state->input_len != 0 ||
2634  smtp_state->cmds_cnt != 0 ||
2635  smtp_state->cmds_idx != 0 ||
2637  printf("smtp parser in inconsistent state\n");
2638  goto end;
2639  }
2640 
2641  FLOWLOCK_WRLOCK(&f);
2642  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2643  STREAM_TOSERVER, request8, request8_len);
2644  if (r != 0) {
2645  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2646  FLOWLOCK_UNLOCK(&f);
2647  goto end;
2648  }
2649  FLOWLOCK_UNLOCK(&f);
2650  if (smtp_state->input_len != 0 ||
2651  smtp_state->cmds_cnt != 1 ||
2652  smtp_state->cmds_idx != 0 ||
2653  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2655  printf("smtp parser in inconsistent state\n");
2656  goto end;
2657  }
2658 
2659  FLOWLOCK_WRLOCK(&f);
2660  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2661  STREAM_TOCLIENT, reply8, reply8_len);
2662  if (r != 0) {
2663  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2664  FLOWLOCK_UNLOCK(&f);
2665  goto end;
2666  }
2667  FLOWLOCK_UNLOCK(&f);
2668  if (smtp_state->input_len != 0 ||
2669  smtp_state->cmds_cnt != 0 ||
2670  smtp_state->cmds_idx != 0 ||
2673  printf("smtp parser in inconsistent state\n");
2674  goto end;
2675  }
2676 
2677  FLOWLOCK_WRLOCK(&f);
2678  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2679  STREAM_TOSERVER, request9_1, request9_1_len);
2680  if (r != 0) {
2681  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2682  FLOWLOCK_UNLOCK(&f);
2683  goto end;
2684  }
2685  FLOWLOCK_UNLOCK(&f);
2686  if (smtp_state->input_len != 0 ||
2687  smtp_state->cmds_cnt != 0 ||
2688  smtp_state->cmds_idx != 0 ||
2691 
2692  printf("smtp parser in inconsistent state\n");
2693  goto end;
2694  }
2695 
2696  FLOWLOCK_WRLOCK(&f);
2697  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2698  STREAM_TOSERVER, request9_2, request9_2_len);
2699  if (r != 0) {
2700  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2701  FLOWLOCK_UNLOCK(&f);
2702  goto end;
2703  }
2704  FLOWLOCK_UNLOCK(&f);
2705  if (smtp_state->input_len != 0 ||
2706  smtp_state->cmds_cnt != 0 ||
2707  smtp_state->cmds_idx != 0 ||
2710 
2711  printf("smtp parser in inconsistent state\n");
2712  goto end;
2713  }
2714 
2715  FLOWLOCK_WRLOCK(&f);
2716  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2717  STREAM_TOSERVER, request9_3, request9_3_len);
2718  if (r != 0) {
2719  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2720  FLOWLOCK_UNLOCK(&f);
2721  goto end;
2722  }
2723  FLOWLOCK_UNLOCK(&f);
2724  if (smtp_state->input_len != 0 ||
2725  smtp_state->cmds_cnt != 0 ||
2726  smtp_state->cmds_idx != 0 ||
2729 
2730  printf("smtp parser in inconsistent state\n");
2731  goto end;
2732  }
2733 
2734  FLOWLOCK_WRLOCK(&f);
2735  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2736  STREAM_TOSERVER, request9_4, request9_4_len);
2737  if (r != 0) {
2738  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2739  FLOWLOCK_UNLOCK(&f);
2740  goto end;
2741  }
2742  FLOWLOCK_UNLOCK(&f);
2743  if (smtp_state->input_len != 0 ||
2744  smtp_state->cmds_cnt != 0 ||
2745  smtp_state->cmds_idx != 0 ||
2748 
2749  printf("smtp parser in inconsistent state\n");
2750  goto end;
2751  }
2752 
2753  FLOWLOCK_WRLOCK(&f);
2754  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2755  STREAM_TOSERVER, request9_5, request9_5_len);
2756  if (r != 0) {
2757  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2758  FLOWLOCK_UNLOCK(&f);
2759  goto end;
2760  }
2761  FLOWLOCK_UNLOCK(&f);
2762  if (smtp_state->input_len != 0 ||
2763  smtp_state->cmds_cnt != 1 ||
2764  smtp_state->cmds_idx != 0 ||
2765  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2767  printf("smtp parser in inconsistent state\n");
2768  goto end;
2769  }
2770 
2771  FLOWLOCK_WRLOCK(&f);
2772  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2773  STREAM_TOCLIENT, reply9, reply9_len);
2774  if (r != 0) {
2775  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2776  FLOWLOCK_UNLOCK(&f);
2777  goto end;
2778  }
2779  FLOWLOCK_UNLOCK(&f);
2780  if (smtp_state->input_len != 0 ||
2781  smtp_state->cmds_cnt != 0 ||
2782  smtp_state->cmds_idx != 0 ||
2784  printf("smtp parser in inconsistent state\n");
2785  goto end;
2786  }
2787 
2788  FLOWLOCK_WRLOCK(&f);
2789  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2790  STREAM_TOSERVER, request10, request10_len);
2791  if (r != 0) {
2792  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2793  FLOWLOCK_UNLOCK(&f);
2794  goto end;
2795  }
2796  FLOWLOCK_UNLOCK(&f);
2797  if (smtp_state->input_len != 0 ||
2798  smtp_state->cmds_cnt != 1 ||
2799  smtp_state->cmds_idx != 0 ||
2800  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2802  printf("smtp parser in inconsistent state\n");
2803  goto end;
2804  }
2805 
2806  FLOWLOCK_WRLOCK(&f);
2807  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2808  STREAM_TOCLIENT, reply10, reply10_len);
2809  if (r != 0) {
2810  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2811  FLOWLOCK_UNLOCK(&f);
2812  goto end;
2813  }
2814  FLOWLOCK_UNLOCK(&f);
2815  if (smtp_state->input_len != 0 ||
2816  smtp_state->cmds_cnt != 0 ||
2817  smtp_state->cmds_idx != 0 ||
2819  printf("smtp parser in inconsistent state\n");
2820  goto end;
2821  }
2822 
2823  result = 1;
2824 end:
2825  if (alp_tctx != NULL)
2828  FLOW_DESTROY(&f);
2829  return result;
2830 }
2831 
2832 /**
2833  * \test Testing parsing pipelined commands.
2834  */
2835 static int SMTPParserTest03(void)
2836 {
2837  int result = 0;
2838  Flow f;
2839  int r = 0;
2840 
2841  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2842  uint8_t welcome_reply[] = {
2843  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2844  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2845  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2846  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2847  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2848  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2849  };
2850  uint32_t welcome_reply_len = sizeof(welcome_reply);
2851 
2852  /* EHLO boo.com<CR><LF> */
2853  uint8_t request1[] = {
2854  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2855  0x2e, 0x63, 0x6f, 0x6d, 0x0a
2856  };
2857  uint32_t request1_len = sizeof(request1);
2858  /* 250-poona_slack_vm1.localdomain<CR><LF>
2859  * 250-PIPELINING<CR><LF>
2860  * 250-SIZE 10240000<CR><LF>
2861  * 250-VRFY<CR><LF>
2862  * 250-ETRN<CR><LF>
2863  * 250-ENHANCEDSTATUSCODES<CR><LF>
2864  * 250-8BITMIME<CR><LF>
2865  * 250 DSN<CR><LF>
2866  */
2867  uint8_t reply1[] = {
2868  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2869  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2870  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2871  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2872  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
2873  0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
2874  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2875  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2876  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2877  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2878  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2879  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2880  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2881  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2882  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2883  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2884  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2885  };
2886  uint32_t reply1_len = sizeof(reply1);
2887 
2888  /* MAIL FROM:pbsf@asdfs.com<CR><LF>
2889  * RCPT TO:pbsf@asdfs.com<CR><LF>
2890  * DATA<CR><LF>
2891  * Immediate data
2892  */
2893  uint8_t request2[] = {
2894  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2895  0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2896  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2897  0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
2898  0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2899  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2900  0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
2901  0x49, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74,
2902  0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0d, 0x0a,
2903  };
2904  uint32_t request2_len = sizeof(request2);
2905  /* 250 2.1.0 Ok<CR><LF>
2906  * 250 2.1.5 Ok<CR><LF>
2907  * 354 End data with <CR><LF>.<CR><LF>|<CR><LF>|
2908  */
2909  uint8_t reply2[] = {
2910  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2911  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35,
2912  0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20,
2913  0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20,
2914  0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61,
2915  0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43,
2916  0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c,
2917  0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d,
2918  0x0a
2919  };
2920  uint32_t reply2_len = sizeof(reply2);
2921 
2922  TcpSession ssn;
2924 
2925  memset(&f, 0, sizeof(f));
2926  memset(&ssn, 0, sizeof(ssn));
2927 
2928  FLOW_INITIALIZE(&f);
2929  f.protoctx = (void *)&ssn;
2930  f.proto = IPPROTO_TCP;
2931  f.alproto = ALPROTO_SMTP;
2932 
2934  SMTPTestInitConfig();
2935 
2936  FLOWLOCK_WRLOCK(&f);
2937  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2938  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2939  if (r != 0) {
2940  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2941  FLOWLOCK_UNLOCK(&f);
2942  goto end;
2943  }
2944  FLOWLOCK_UNLOCK(&f);
2945  SMTPState *smtp_state = f.alstate;
2946  if (smtp_state == NULL) {
2947  printf("no smtp state: ");
2948  goto end;
2949  }
2950  if (smtp_state->input_len != 0 ||
2951  smtp_state->cmds_cnt != 0 ||
2952  smtp_state->cmds_idx != 0 ||
2954  printf("smtp parser in inconsistent state\n");
2955  goto end;
2956  }
2957 
2958  FLOWLOCK_WRLOCK(&f);
2959  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2960  STREAM_TOSERVER, request1, request1_len);
2961  if (r != 0) {
2962  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2963  FLOWLOCK_UNLOCK(&f);
2964  goto end;
2965  }
2966  FLOWLOCK_UNLOCK(&f);
2967  if (smtp_state->input_len != 0 ||
2968  smtp_state->cmds_cnt != 1 ||
2969  smtp_state->cmds_idx != 0 ||
2970  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2972  printf("smtp parser in inconsistent state\n");
2973  goto end;
2974  }
2975 
2976  FLOWLOCK_WRLOCK(&f);
2977  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2978  STREAM_TOCLIENT, reply1, reply1_len);
2979  if (r != 0) {
2980  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2981  FLOWLOCK_UNLOCK(&f);
2982  goto end;
2983  }
2984  FLOWLOCK_UNLOCK(&f);
2985  if (smtp_state->input_len != 0 ||
2986  smtp_state->cmds_cnt != 0 ||
2987  smtp_state->cmds_idx != 0 ||
2990  printf("smtp parser in inconsistent state\n");
2991  goto end;
2992  }
2993 
2994  FLOWLOCK_WRLOCK(&f);
2995  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2996  STREAM_TOSERVER, request2, request2_len);
2997  if (r != 0) {
2998  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2999  FLOWLOCK_UNLOCK(&f);
3000  goto end;
3001  }
3002  FLOWLOCK_UNLOCK(&f);
3003  if (smtp_state->input_len != 0 ||
3004  smtp_state->cmds_cnt != 3 ||
3005  smtp_state->cmds_idx != 0 ||
3006  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3007  smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD ||
3008  smtp_state->cmds[2] != SMTP_COMMAND_DATA ||
3012  printf("smtp parser in inconsistent state\n");
3013  goto end;
3014  }
3015 
3016  FLOWLOCK_WRLOCK(&f);
3017  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3018  STREAM_TOCLIENT, reply2, reply2_len);
3019  if (r != 0) {
3020  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3021  FLOWLOCK_UNLOCK(&f);
3022  goto end;
3023  }
3024  FLOWLOCK_UNLOCK(&f);
3025  if (smtp_state->input_len != 0 ||
3026  smtp_state->cmds_cnt != 0 ||
3027  smtp_state->cmds_idx != 0 ||
3031  printf("smtp parser in inconsistent state\n");
3032  goto end;
3033  }
3034 
3035  result = 1;
3036 end:
3037  if (alp_tctx != NULL)
3040  FLOW_DESTROY(&f);
3041  return result;
3042 }
3043 
3044 /*
3045  * \test Test smtp with just <LF> delimiter instead of <CR><LF>.
3046  */
3047 static int SMTPParserTest04(void)
3048 {
3049  int result = 0;
3050  Flow f;
3051  int r = 0;
3052 
3053  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
3054  uint8_t welcome_reply[] = {
3055  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3056  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3057  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3058  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3059  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3060  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3061  };
3062  uint32_t welcome_reply_len = sizeof(welcome_reply);
3063 
3064  /* EHLO boo.com<CR><LF> */
3065  uint8_t request1[] = {
3066  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3067  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3068  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3069  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3070  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3071  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3072  };
3073  uint32_t request1_len = sizeof(request1);
3074 
3075  TcpSession ssn;
3077 
3078  memset(&f, 0, sizeof(f));
3079  memset(&ssn, 0, sizeof(ssn));
3080 
3081  FLOW_INITIALIZE(&f);
3082  f.protoctx = (void *)&ssn;
3083  f.proto = IPPROTO_TCP;
3084  f.alproto = ALPROTO_SMTP;
3085 
3087  SMTPTestInitConfig();
3088 
3089  FLOWLOCK_WRLOCK(&f);
3090  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3091  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3092  if (r != 0) {
3093  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3094  FLOWLOCK_UNLOCK(&f);
3095  goto end;
3096  }
3097  FLOWLOCK_UNLOCK(&f);
3098  SMTPState *smtp_state = f.alstate;
3099  if (smtp_state == NULL) {
3100  printf("no smtp state: ");
3101  goto end;
3102  }
3103  if (smtp_state->input_len != 0 ||
3104  smtp_state->cmds_cnt != 0 ||
3105  smtp_state->cmds_idx != 0 ||
3107  printf("smtp parser in inconsistent state\n");
3108  goto end;
3109  }
3110 
3111  FLOWLOCK_WRLOCK(&f);
3112  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3113  STREAM_TOSERVER, request1, request1_len);
3114  if (r != 0) {
3115  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3116  FLOWLOCK_UNLOCK(&f);
3117  goto end;
3118  }
3119  FLOWLOCK_UNLOCK(&f);
3120  if (smtp_state->input_len != 0 ||
3121  smtp_state->cmds_cnt != 1 ||
3122  smtp_state->cmds_idx != 0 ||
3123  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3125  printf("smtp parser in inconsistent state\n");
3126  goto end;
3127  }
3128 
3129  result = 1;
3130 end:
3131  if (alp_tctx != NULL)
3134  FLOW_DESTROY(&f);
3135  return result;
3136 }
3137 
3138 /*
3139  * \test Test STARTTLS fail.
3140  */
3141 static int SMTPParserTest05(void)
3142 {
3143  int result = 0;
3144  Flow f;
3145  int r = 0;
3146 
3147  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
3148  uint8_t welcome_reply[] = {
3149  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3150  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3151  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3152  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3153  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3154  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3155  };
3156  uint32_t welcome_reply_len = sizeof(welcome_reply);
3157 
3158  /* EHLO boo.com<CR><LF> */
3159  uint8_t request1[] = {
3160  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3161  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
3162  };
3163  uint32_t request1_len = sizeof(request1);
3164  /* 250-poona_slack_vm1.localdomain<CR><LF>
3165  * 250-PIPELINING<CR><LF>
3166  * 250-SIZE 10240000<CR><LF>
3167  * 250-VRFY<CR><LF>
3168  * 250-ETRN<CR><LF>
3169  * 250-ENHANCEDSTATUSCODES<CR><LF>
3170  * 250-8BITMIME<CR><LF>
3171  * 250 DSN<CR><LF>
3172  */
3173  uint8_t reply1[] = {
3174  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
3175  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3176  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3177  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
3178  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
3179  0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
3180  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
3181  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
3182  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3183  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
3184  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
3185  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
3186  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
3187  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
3188  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
3189  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
3190  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
3191  };
3192  uint32_t reply1_len = sizeof(reply1);
3193 
3194  /* STARTTLS<CR><LF> */
3195  uint8_t request2[] = {
3196  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
3197  0x0d, 0x0a
3198  };
3199  uint32_t request2_len = sizeof(request2);
3200  /* 502 5.5.2 Error: command not recognized<CR><LF> */
3201  uint8_t reply2[] = {
3202  0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e,
3203  0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a,
3204  0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
3205  0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63,
3206  0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d,
3207  0x0a
3208  };
3209  uint32_t reply2_len = sizeof(reply2);
3210 
3211  /* QUIT<CR><LF> */
3212  uint8_t request3[] = {
3213  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
3214 
3215  };
3216  uint32_t request3_len = sizeof(request3);
3217  /* 221 2.0.0 Bye<CR><LF> */
3218  uint8_t reply3[] = {
3219  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
3220  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
3221  };
3222  uint32_t reply3_len = sizeof(reply3);
3223 
3224  TcpSession ssn;
3226 
3227  memset(&f, 0, sizeof(f));
3228  memset(&ssn, 0, sizeof(ssn));
3229 
3230  FLOW_INITIALIZE(&f);
3231  f.protoctx = (void *)&ssn;
3232  f.proto = IPPROTO_TCP;
3233  f.alproto = ALPROTO_SMTP;
3234 
3236  SMTPTestInitConfig();
3237 
3238  FLOWLOCK_WRLOCK(&f);
3239  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3240  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3241  if (r != 0) {
3242  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3243  FLOWLOCK_UNLOCK(&f);
3244  goto end;
3245  }
3246  FLOWLOCK_UNLOCK(&f);
3247  SMTPState *smtp_state = f.alstate;
3248  if (smtp_state == NULL) {
3249  printf("no smtp state: ");
3250  goto end;
3251  }
3252  if (smtp_state->input_len != 0 ||
3253  smtp_state->cmds_cnt != 0 ||
3254  smtp_state->cmds_idx != 0 ||
3256  printf("smtp parser in inconsistent state\n");
3257  goto end;
3258  }
3259 
3260  FLOWLOCK_WRLOCK(&f);
3261  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3262  STREAM_TOSERVER, request1, request1_len);
3263  if (r != 0) {
3264  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3265  FLOWLOCK_UNLOCK(&f);
3266  goto end;
3267  }
3268  FLOWLOCK_UNLOCK(&f);
3269  if (smtp_state->input_len != 0 ||
3270  smtp_state->cmds_cnt != 1 ||
3271  smtp_state->cmds_idx != 0 ||
3272  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3274  printf("smtp parser in inconsistent state\n");
3275  goto end;
3276  }
3277 
3278  FLOWLOCK_WRLOCK(&f);
3279  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3280  STREAM_TOCLIENT, reply1, reply1_len);
3281  if (r != 0) {
3282  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3283  FLOWLOCK_UNLOCK(&f);
3284  goto end;
3285  }
3286  FLOWLOCK_UNLOCK(&f);
3287  if (smtp_state->input_len != 0 ||
3288  smtp_state->cmds_cnt != 0 ||
3289  smtp_state->cmds_idx != 0 ||
3292  printf("smtp parser in inconsistent state\n");
3293  goto end;
3294  }
3295 
3296  FLOWLOCK_WRLOCK(&f);
3297  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3298  STREAM_TOSERVER, request2, request2_len);
3299  if (r != 0) {
3300  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3301  FLOWLOCK_UNLOCK(&f);
3302  goto end;
3303  }
3304  FLOWLOCK_UNLOCK(&f);
3305  if (smtp_state->input_len != 0 ||
3306  smtp_state->cmds_cnt != 1 ||
3307  smtp_state->cmds_idx != 0 ||
3308  smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
3311  printf("smtp parser in inconsistent state\n");
3312  goto end;
3313  }
3314 
3315  FLOWLOCK_WRLOCK(&f);
3316  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3317  STREAM_TOCLIENT, reply2, reply2_len);
3318  if (r != 0) {
3319  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3320  FLOWLOCK_UNLOCK(&f);
3321  goto end;
3322  }
3323  FLOWLOCK_UNLOCK(&f);
3324  if (smtp_state->input_len != 0 ||
3325  smtp_state->cmds_cnt != 0 ||
3326  smtp_state->cmds_idx != 0 ||
3329  printf("smtp parser in inconsistent state\n");
3330  goto end;
3331  }
3332 
3333  if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
3335  (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
3336  (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
3337  goto end;
3338  }
3339 
3340  FLOWLOCK_WRLOCK(&f);
3341  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3342  STREAM_TOSERVER, request3, request3_len);
3343  if (r != 0) {
3344  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3345  FLOWLOCK_UNLOCK(&f);
3346  goto end;
3347  }
3348  FLOWLOCK_UNLOCK(&f);
3349  if (smtp_state->input_len != 0 ||
3350  smtp_state->cmds_cnt != 1 ||
3351  smtp_state->cmds_idx != 0 ||
3352  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3355  printf("smtp parser in inconsistent state\n");
3356  goto end;
3357  }
3358 
3359  FLOWLOCK_WRLOCK(&f);
3360  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3361  STREAM_TOCLIENT, reply3, reply3_len);
3362  if (r != 0) {
3363  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3364  FLOWLOCK_UNLOCK(&f);
3365  goto end;
3366  }
3367  FLOWLOCK_UNLOCK(&f);
3368  if (smtp_state->input_len != 0 ||
3369  smtp_state->cmds_cnt != 0 ||
3370  smtp_state->cmds_idx != 0 ||
3373  printf("smtp parser in inconsistent state\n");
3374  goto end;
3375  }
3376 
3377  result = 1;
3378 end:
3379  if (alp_tctx != NULL)
3382  FLOW_DESTROY(&f);
3383  return result;
3384 }
3385 
3386 /**
3387  * \test Test multiple DATA commands(full mail transactions).
3388  */
3389 static int SMTPParserTest06(void)
3390 {
3391  int result = 0;
3392  Flow f;
3393  int r = 0;
3394 
3395  uint8_t welcome_reply[] = {
3396  0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30,
3397  0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3398  0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3399  0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3400  0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e,
3401  0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69,
3402  0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f,
3403  0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c,
3404  0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b,
3405  0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20,
3406  0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f,
3407  0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63,
3408  0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20,
3409  0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
3410  0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69,
3411  0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f,
3412  0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73,
3413  0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e,
3414  0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f,
3415  0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68,
3416  0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72,
3417  0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73,
3418  0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e,
3419  0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f,
3420  0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74,
3421  0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c,
3422  0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
3423  0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20,
3424  0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70,
3425  0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63,
3426  0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
3427  0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
3428  0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f,
3429  0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61,
3430  0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69,
3431  0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62,
3432  0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35,
3433  0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d,
3434  0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a
3435  };
3436  uint32_t welcome_reply_len = sizeof(welcome_reply);
3437 
3438  uint8_t request1[] = {
3439  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43,
3440  0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63,
3441  0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69,
3442  0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d,
3443  0x0a
3444  };
3445  uint32_t request1_len = sizeof(request1);
3446 
3447  uint8_t reply1[] = {
3448  0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30,
3449  0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3450  0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3451  0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3452  0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31,
3453  0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c,
3454  0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31,
3455  0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39,
3456  0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53,
3457  0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39,
3458  0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35,
3459  0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69,
3460  0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3461  0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49,
3462  0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3463  0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47,
3464  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3465  0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3466  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3467  0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3468  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b,
3469  0x0d, 0x0a
3470  };
3471  uint32_t reply1_len = sizeof(reply1);
3472 
3473  /* MAIL FROM:asdff@asdf.com<CR><LF> */
3474  uint8_t request2[] = {
3475  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3476  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
3477  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
3478  0x0d, 0x0a
3479  };
3480  uint32_t request2_len = sizeof(request2);
3481  /* 250 2.1.0 Ok<CR><LF> */
3482  uint8_t reply2[] = {
3483  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3484  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3485  };
3486  uint32_t reply2_len = sizeof(reply2);
3487 
3488  /* RCPT TO:bimbs@gmail.com<CR><LF> */
3489  uint8_t request3[] = {
3490  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
3491  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
3492  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3493  0x0a
3494  };
3495  uint32_t request3_len = sizeof(request3);
3496  /* 250 2.1.5 Ok<CR><LF> */
3497  uint8_t reply3[] = {
3498  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3499  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3500  };
3501  uint32_t reply3_len = sizeof(reply3);
3502 
3503  /* BDAT 51<CR><LF> */
3504  uint8_t request4[] = {
3505  0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d,
3506  0x0a,
3507  };
3508  uint32_t request4_len = sizeof(request4);
3509 
3510  uint8_t request5[] = {
3511  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3512  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3513  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3514  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a,
3515  };
3516  uint32_t request5_len = sizeof(request5);
3517 
3518  uint8_t request6[] = {
3519  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3520  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3521  0x66, 0x0d, 0x0a,
3522  };
3523  uint32_t request6_len = sizeof(request6);
3524 
3525  TcpSession ssn;
3527 
3528  memset(&f, 0, sizeof(f));
3529  memset(&ssn, 0, sizeof(ssn));
3530 
3531  FLOW_INITIALIZE(&f);
3532  f.protoctx = (void *)&ssn;
3533  f.proto = IPPROTO_TCP;
3534  f.alproto = ALPROTO_SMTP;
3535 
3537  SMTPTestInitConfig();
3538 
3539  FLOWLOCK_WRLOCK(&f);
3540  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3541  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3542  if (r != 0) {
3543  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3544  FLOWLOCK_UNLOCK(&f);
3545  goto end;
3546  }
3547  FLOWLOCK_UNLOCK(&f);
3548  SMTPState *smtp_state = f.alstate;
3549  if (smtp_state == NULL) {
3550  printf("no smtp state: ");
3551  goto end;
3552  }
3553  if (smtp_state->input_len != 0 ||
3554  smtp_state->cmds_cnt != 0 ||
3555  smtp_state->cmds_idx != 0 ||
3557  printf("smtp parser in inconsistent state\n");
3558  goto end;
3559  }
3560 
3561  FLOWLOCK_WRLOCK(&f);
3562  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3563  STREAM_TOSERVER, request1, request1_len);
3564  if (r != 0) {
3565  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3566  FLOWLOCK_UNLOCK(&f);
3567  goto end;
3568  }
3569  FLOWLOCK_UNLOCK(&f);
3570  if (smtp_state->input_len != 0 ||
3571  smtp_state->cmds_cnt != 1 ||
3572  smtp_state->cmds_idx != 0 ||
3573  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3575  printf("smtp parser in inconsistent state\n");
3576  goto end;
3577  }
3578 
3579  FLOWLOCK_WRLOCK(&f);
3580  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3581  STREAM_TOCLIENT, reply1, reply1_len);
3582  if (r != 0) {
3583  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3584  FLOWLOCK_UNLOCK(&f);
3585  goto end;
3586  }
3587  FLOWLOCK_UNLOCK(&f);
3588  if (smtp_state->input_len != 0 ||
3589  smtp_state->cmds_cnt != 0 ||
3590  smtp_state->cmds_idx != 0 ||
3592  printf("smtp parser in inconsistent state\n");
3593  goto end;
3594  }
3595 
3596  FLOWLOCK_WRLOCK(&f);
3597  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3598  STREAM_TOSERVER, request2, request2_len);
3599  if (r != 0) {
3600  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3601  FLOWLOCK_UNLOCK(&f);
3602  goto end;
3603  }
3604  FLOWLOCK_UNLOCK(&f);
3605  if (smtp_state->input_len != 0 ||
3606  smtp_state->cmds_cnt != 1 ||
3607  smtp_state->cmds_idx != 0 ||
3608  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3610  printf("smtp parser in inconsistent state\n");
3611  goto end;
3612  }
3613 
3614  FLOWLOCK_WRLOCK(&f);
3615  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3616  STREAM_TOCLIENT, reply2, reply2_len);
3617  if (r != 0) {
3618  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3619  FLOWLOCK_UNLOCK(&f);
3620  goto end;
3621  }
3622  FLOWLOCK_UNLOCK(&f);
3623  if (smtp_state->input_len != 0 ||
3624  smtp_state->cmds_cnt != 0 ||
3625  smtp_state->cmds_idx != 0 ||
3627  printf("smtp parser in inconsistent state\n");
3628  goto end;
3629  }
3630 
3631  FLOWLOCK_WRLOCK(&f);
3632  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3633  STREAM_TOSERVER, request3, request3_len);
3634  if (r != 0) {
3635  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3636  FLOWLOCK_UNLOCK(&f);
3637  goto end;
3638  }
3639  FLOWLOCK_UNLOCK(&f);
3640  if (smtp_state->input_len != 0 ||
3641  smtp_state->cmds_cnt != 1 ||
3642  smtp_state->cmds_idx != 0 ||
3643  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3645  printf("smtp parser in inconsistent state\n");
3646  goto end;
3647  }
3648 
3649  FLOWLOCK_WRLOCK(&f);
3650  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3651  STREAM_TOCLIENT, reply3, reply3_len);
3652  if (r != 0) {
3653  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3654  FLOWLOCK_UNLOCK(&f);
3655  goto end;
3656  }
3657  FLOWLOCK_UNLOCK(&f);
3658  if (smtp_state->input_len != 0 ||
3659  smtp_state->cmds_cnt != 0 ||
3660  smtp_state->cmds_idx != 0 ||
3662  printf("smtp parser in inconsistent state\n");
3663  goto end;
3664  }
3665 
3666  FLOWLOCK_WRLOCK(&f);
3667  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3668  STREAM_TOSERVER, request4, request4_len);
3669  if (r != 0) {
3670  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3671  FLOWLOCK_UNLOCK(&f);
3672  goto end;
3673  }
3674  FLOWLOCK_UNLOCK(&f);
3675  if (smtp_state->input_len != 0 ||
3676  smtp_state->cmds_cnt != 1 ||
3677  smtp_state->cmds_idx != 0 ||
3678  smtp_state->cmds[0] != SMTP_COMMAND_BDAT ||
3681  smtp_state->bdat_chunk_len != 51 ||
3682  smtp_state->bdat_chunk_idx != 0) {
3683  printf("smtp parser in inconsistent state\n");
3684  goto end;
3685  }
3686 
3687  FLOWLOCK_WRLOCK(&f);
3688  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3689  STREAM_TOSERVER, request5, request5_len);
3690  if (r != 0) {
3691  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3692  FLOWLOCK_UNLOCK(&f);
3693  goto end;
3694  }
3695  FLOWLOCK_UNLOCK(&f);
3696  if (smtp_state->input_len != 0 ||
3697  smtp_state->cmds_cnt != 1 ||
3698  smtp_state->cmds_idx != 0 ||
3701  smtp_state->bdat_chunk_len != 51 ||
3702  smtp_state->bdat_chunk_idx != 32) {
3703  printf("smtp parser in inconsistent state\n");
3704  goto end;
3705  }
3706 
3707  FLOWLOCK_WRLOCK(&f);
3708  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3709  STREAM_TOSERVER, request6, request6_len);
3710  if (r != 0) {
3711  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3712  FLOWLOCK_UNLOCK(&f);
3713  goto end;
3714  }
3715  FLOWLOCK_UNLOCK(&f);
3716  if (smtp_state->input_len != 0 ||
3717  smtp_state->cmds_cnt != 1 ||
3718  smtp_state->cmds_idx != 0 ||
3720  smtp_state->bdat_chunk_len != 51 ||
3721  smtp_state->bdat_chunk_idx != 51) {
3722  printf("smtp parser in inconsistent state\n");
3723  goto end;
3724  }
3725 
3726  result = 1;
3727 end:
3728  if (alp_tctx != NULL)
3731  FLOW_DESTROY(&f);
3732  return result;
3733 }
3734 
3735 /*
3736  * \test Test retrieving lines when frag'ed.
3737  */
3738 static int SMTPParserTest07(void)
3739 {
3740  int result = 0;
3741  Flow f;
3742  int r = 0;
3743 
3744  const char *request1_str = "EHLO boo.com";
3745  /* EHLO boo.com<CR> */
3746  uint8_t request1_1[] = {
3747  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3748  0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3749  };
3750  int32_t request1_1_len = sizeof(request1_1);
3751 
3752  /* <LF> */
3753  uint8_t request1_2[] = {
3754  0x0a
3755  };
3756  int32_t request1_2_len = sizeof(request1_2);
3757 
3758  /* EHLO boo.com<CR><LF> */
3759  uint8_t request2[] = {
3760  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3761  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3762  };
3763  int32_t request2_len = sizeof(request2);
3764 
3765  TcpSession ssn;
3767 
3768  memset(&f, 0, sizeof(f));
3769  memset(&ssn, 0, sizeof(ssn));
3770 
3771  FLOW_INITIALIZE(&f);
3772  f.protoctx = (void *)&ssn;
3773  f.proto = IPPROTO_TCP;
3774  f.alproto = ALPROTO_SMTP;
3775 
3777  SMTPTestInitConfig();
3778 
3779  FLOWLOCK_WRLOCK(&f);
3780  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3781  STREAM_TOSERVER, request1_1, request1_1_len);
3782  if (r != 0) {
3783  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3784  FLOWLOCK_UNLOCK(&f);
3785  goto end;
3786  }
3787  FLOWLOCK_UNLOCK(&f);
3788  SMTPState *smtp_state = f.alstate;
3789  if (smtp_state == NULL) {
3790  printf("no smtp state: ");
3791  goto end;
3792  }
3793  if (smtp_state->current_line != NULL ||
3794  smtp_state->current_line_len != 0 ||
3795  smtp_state->ts_current_line_db != 1 ||
3796  smtp_state->ts_db == NULL ||
3797  smtp_state->ts_db_len != request1_1_len ||
3798  memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3799  printf("smtp parser in inconsistent state\n");
3800  goto end;
3801  }
3802 
3803  FLOWLOCK_WRLOCK(&f);
3804  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3805  STREAM_TOSERVER, request1_2, request1_2_len);
3806  if (r != 0) {
3807  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3808  FLOWLOCK_UNLOCK(&f);
3809  goto end;
3810  }
3811  FLOWLOCK_UNLOCK(&f);
3812  if (smtp_state->ts_current_line_db != 1 ||
3813  smtp_state->ts_db == NULL ||
3814  smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3815  memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3816  smtp_state->current_line != smtp_state->ts_db ||
3817  smtp_state->current_line_len != smtp_state->ts_db_len) {
3818  printf("smtp parser in inconsistent state\n");
3819  goto end;
3820  }
3821 
3822  FLOWLOCK_WRLOCK(&f);
3823  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3824  STREAM_TOSERVER, request2, request2_len);
3825  if (r != 0) {
3826  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3827  FLOWLOCK_UNLOCK(&f);
3828  goto end;
3829  }
3830  FLOWLOCK_UNLOCK(&f);
3831  if (smtp_state->ts_current_line_db != 0 ||
3832  smtp_state->ts_db != NULL ||
3833  smtp_state->ts_db_len != 0 ||
3834  smtp_state->current_line == NULL ||
3835  smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
3836  memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3837  printf("smtp parser in inconsistent state\n");
3838  goto end;
3839  }
3840 
3841  result = 1;
3842 end:
3843  if (alp_tctx != NULL)
3846  FLOW_DESTROY(&f);
3847  return result;
3848 }
3849 
3850 /*
3851  * \test Test retrieving lines when frag'ed.
3852  */
3853 static int SMTPParserTest08(void)
3854 {
3855  int result = 0;
3856  Flow f;
3857  int r = 0;
3858 
3859  const char *request1_str = "EHLO boo.com";
3860  /* EHLO boo.com */
3861  uint8_t request1_1[] = {
3862  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3863  0x2e, 0x63, 0x6f, 0x6d,
3864  };
3865  int32_t request1_1_len = sizeof(request1_1);
3866 
3867  /* <CR><LF> */
3868  uint8_t request1_2[] = {
3869  0x0d, 0x0a
3870  };
3871  int32_t request1_2_len = sizeof(request1_2);
3872 
3873  /* EHLO boo.com<CR><LF> */
3874  uint8_t request2[] = {
3875  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3876  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3877  };
3878  int32_t request2_len = sizeof(request2);
3879 
3880  TcpSession ssn;
3882 
3883  memset(&f, 0, sizeof(f));
3884  memset(&ssn, 0, sizeof(ssn));
3885 
3886  FLOW_INITIALIZE(&f);
3887  f.protoctx = (void *)&ssn;
3888  f.proto = IPPROTO_TCP;
3889  f.alproto = ALPROTO_SMTP;
3890 
3892  SMTPTestInitConfig();
3893 
3894  FLOWLOCK_WRLOCK(&f);
3895  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3896  STREAM_TOSERVER, request1_1, request1_1_len);
3897  if (r != 0) {
3898  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3899  FLOWLOCK_UNLOCK(&f);
3900  goto end;
3901  }
3902  FLOWLOCK_UNLOCK(&f);
3903  SMTPState *smtp_state = f.alstate;
3904  if (smtp_state == NULL) {
3905  printf("no smtp state: ");
3906  goto end;
3907  }
3908  if (smtp_state->current_line != NULL ||
3909  smtp_state->current_line_len != 0 ||
3910  smtp_state->ts_current_line_db != 1 ||
3911  smtp_state->ts_db == NULL ||
3912  smtp_state->ts_db_len != request1_1_len ||
3913  memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3914  printf("smtp parser in inconsistent state\n");
3915  goto end;
3916  }
3917 
3918  FLOWLOCK_WRLOCK(&f);
3919  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3920  STREAM_TOSERVER, request1_2, request1_2_len);
3921  if (r != 0) {
3922  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3923  FLOWLOCK_UNLOCK(&f);
3924  goto end;
3925  }
3926  FLOWLOCK_UNLOCK(&f);
3927  if (smtp_state->ts_current_line_db != 1 ||
3928  smtp_state->ts_db == NULL ||
3929  smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3930  memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3931  smtp_state->current_line != smtp_state->ts_db ||
3932  smtp_state->current_line_len != smtp_state->ts_db_len) {
3933  printf("smtp parser in inconsistent state\n");
3934  goto end;
3935  }
3936 
3937  FLOWLOCK_WRLOCK(&f);
3938  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3939  STREAM_TOSERVER, request2, request2_len);
3940  if (r != 0) {
3941  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3942  FLOWLOCK_UNLOCK(&f);
3943  goto end;
3944  }
3945  FLOWLOCK_UNLOCK(&f);
3946  if (smtp_state->ts_current_line_db != 0 ||
3947  smtp_state->ts_db != NULL ||
3948  smtp_state->ts_db_len != 0 ||
3949  smtp_state->current_line == NULL ||
3950  smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
3951  memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3952  printf("smtp parser in inconsistent state\n");
3953  goto end;
3954  }
3955 
3956  result = 1;
3957 end:
3958  if (alp_tctx != NULL)
3961  FLOW_DESTROY(&f);
3962  return result;
3963 }
3964 
3965 /*
3966  * \test Test retrieving lines when frag'ed.
3967  */
3968 static int SMTPParserTest09(void)
3969 {
3970  int result = 0;
3971  Flow f;
3972  int r = 0;
3973 
3974  const char *request1_str = "EHLO boo.com";
3975  /* EHLO boo. */
3976  uint8_t request1_1[] = {
3977  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3978  0x2e,
3979  };
3980  int32_t request1_1_len = sizeof(request1_1);
3981 
3982  /* com<CR><LF> */
3983  uint8_t request1_2[] = {
3984  0x63, 0x6f, 0x6d, 0x0d, 0x0a
3985  };
3986  int32_t request1_2_len = sizeof(request1_2);
3987 
3988  /* EHLO boo.com<CR><LF> */
3989  uint8_t request2[] = {
3990  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3991  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3992  };
3993  int32_t request2_len = sizeof(request2);
3994 
3995  TcpSession ssn;
3997 
3998  memset(&f, 0, sizeof(f));
3999  memset(&ssn, 0, sizeof(ssn));
4000 
4001  FLOW_INITIALIZE(&f);
4002  f.protoctx = (void *)&ssn;
4003  f.proto = IPPROTO_TCP;
4004  f.alproto = ALPROTO_SMTP;
4005 
4007  SMTPTestInitConfig();
4008 
4009  FLOWLOCK_WRLOCK(&f);
4010  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4011  STREAM_TOSERVER, request1_1, request1_1_len);
4012  if (r != 0) {
4013  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4014  FLOWLOCK_UNLOCK(&f);
4015  goto end;
4016  }
4017  FLOWLOCK_UNLOCK(&f);
4018  SMTPState *smtp_state = f.alstate;
4019  if (smtp_state == NULL) {
4020  printf("no smtp state: ");
4021  goto end;
4022  }
4023  if (smtp_state->current_line != NULL ||
4024  smtp_state->current_line_len != 0 ||
4025  smtp_state->ts_current_line_db != 1 ||
4026  smtp_state->ts_db == NULL ||
4027  smtp_state->ts_db_len != request1_1_len ||
4028  memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
4029  printf("smtp parser in inconsistent state\n");
4030  goto end;
4031  }
4032 
4033  FLOWLOCK_WRLOCK(&f);
4034  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4035  STREAM_TOSERVER, request1_2, request1_2_len);
4036  if (r != 0) {
4037  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4038  FLOWLOCK_UNLOCK(&f);
4039  goto end;
4040  }
4041  FLOWLOCK_UNLOCK(&f);
4042  if (smtp_state->ts_current_line_db != 1 ||
4043  smtp_state->ts_db == NULL ||
4044  smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
4045  memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
4046  smtp_state->current_line != smtp_state->ts_db ||
4047  smtp_state->current_line_len != smtp_state->ts_db_len) {
4048  printf("smtp parser in inconsistent state\n");
4049  goto end;
4050  }
4051 
4052  FLOWLOCK_WRLOCK(&f);
4053  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4054  STREAM_TOSERVER, request2, request2_len);
4055  if (r != 0) {
4056  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4057  FLOWLOCK_UNLOCK(&f);
4058  goto end;
4059  }
4060  FLOWLOCK_UNLOCK(&f);
4061  if (smtp_state->ts_current_line_db != 0 ||
4062  smtp_state->ts_db != NULL ||
4063  smtp_state->ts_db_len != 0 ||
4064  smtp_state->current_line == NULL ||
4065  smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
4066  memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
4067  printf("smtp parser in inconsistent state\n");
4068  goto end;
4069  }
4070 
4071  result = 1;
4072 end:
4073  if (alp_tctx != NULL)
4076  FLOW_DESTROY(&f);
4077  return result;
4078 }
4079 
4080 /*
4081  * \test Test retrieving lines when frag'ed.
4082  */
4083 static int SMTPParserTest10(void)
4084 {
4085  int result = 0;
4086  Flow f;
4087  int r = 0;
4088 
4089  const char *request1_str = "";
4090  /* EHLO boo. */
4091  uint8_t request1_1[] = {
4092  0x0d,
4093  };
4094  int32_t request1_1_len = sizeof(request1_1);
4095 
4096  /* com<CR><LF> */
4097  uint8_t request1_2[] = {
4098  0x0a,
4099  };
4100  int32_t request1_2_len = sizeof(request1_2);
4101 
4102  const char *request2_str = "EHLO boo.com";
4103  /* EHLO boo.com<CR><LF> */
4104  uint8_t request2[] = {
4105  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4106  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4107  };
4108  int32_t request2_len = sizeof(request2);
4109 
4110  TcpSession ssn;
4112 
4113  memset(&f, 0, sizeof(f));
4114  memset(&ssn, 0, sizeof(ssn));
4115 
4116  FLOW_INITIALIZE(&f);
4117  f.protoctx = (void *)&ssn;
4118  f.proto = IPPROTO_TCP;
4119  f.alproto = ALPROTO_SMTP;
4120 
4122  SMTPTestInitConfig();
4123 
4124  FLOWLOCK_WRLOCK(&f);
4125  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4126  STREAM_TOSERVER, request1_1, request1_1_len);
4127  if (r != 0) {
4128  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4129  FLOWLOCK_UNLOCK(&f);
4130  goto end;
4131  }
4132  FLOWLOCK_UNLOCK(&f);
4133  SMTPState *smtp_state = f.alstate;
4134  if (smtp_state == NULL) {
4135  printf("no smtp state: ");
4136  goto end;
4137  }
4138  if (smtp_state->current_line != NULL ||
4139  smtp_state->current_line_len != 0 ||
4140  smtp_state->ts_current_line_db != 1 ||
4141  smtp_state->ts_db == NULL ||
4142  smtp_state->ts_db_len != request1_1_len ||
4143  memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
4144  printf("smtp parser in inconsistent state\n");
4145  goto end;
4146  }
4147 
4148  FLOWLOCK_WRLOCK(&f);
4149  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4150  STREAM_TOSERVER, request1_2, request1_2_len);
4151  if (r != 0) {
4152  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4153  FLOWLOCK_UNLOCK(&f);
4154  goto end;
4155  }
4156  FLOWLOCK_UNLOCK(&f);
4157  if (smtp_state->ts_current_line_db != 1 ||
4158  smtp_state->ts_db == NULL ||
4159  smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
4160  memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
4161  smtp_state->current_line != smtp_state->ts_db ||
4162  smtp_state->current_line_len != smtp_state->ts_db_len) {
4163  printf("smtp parser in inconsistent state\n");
4164  goto end;
4165  }
4166 
4167  FLOWLOCK_WRLOCK(&f);
4168  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4169  STREAM_TOSERVER, request2, request2_len);
4170  if (r != 0) {
4171  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4172  FLOWLOCK_UNLOCK(&f);
4173  goto end;
4174  }
4175  FLOWLOCK_UNLOCK(&f);
4176  if (smtp_state->ts_current_line_db != 0 ||
4177  smtp_state->ts_db != NULL ||
4178  smtp_state->ts_db_len != 0 ||
4179  smtp_state->current_line == NULL ||
4180  smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
4181  memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
4182  printf("smtp parser in inconsistent state\n");
4183  goto end;
4184  }
4185 
4186  result = 1;
4187 end:
4188  if (alp_tctx != NULL)
4191  FLOW_DESTROY(&f);
4192  return result;
4193 }
4194 
4195 /*
4196  * \test Test retrieving lines when frag'ed.
4197  */
4198 static int SMTPParserTest11(void)
4199 {
4200  int result = 0;
4201  Flow f;
4202  int r = 0;
4203 
4204  const char *request1_str = "";
4205  /* EHLO boo. */
4206  uint8_t request1[] = {
4207  0x0a,
4208  };
4209  int32_t request1_len = sizeof(request1);
4210 
4211  const char *request2_str = "EHLO boo.com";
4212  /* EHLO boo.com<CR><LF> */
4213  uint8_t request2[] = {
4214  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4215  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4216  };
4217  int32_t request2_len = sizeof(request2);
4218 
4219  TcpSession ssn;
4221 
4222  memset(&f, 0, sizeof(f));
4223  memset(&ssn, 0, sizeof(ssn));
4224 
4225  FLOW_INITIALIZE(&f);
4226  f.protoctx = (void *)&ssn;
4227  f.proto = IPPROTO_TCP;
4228  f.alproto = ALPROTO_SMTP;
4229 
4231  SMTPTestInitConfig();
4232 
4233  FLOWLOCK_WRLOCK(&f);
4234  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4235  STREAM_TOSERVER, request1, request1_len);
4236  if (r != 0) {
4237  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4238  FLOWLOCK_UNLOCK(&f);
4239  goto end;
4240  }
4241  FLOWLOCK_UNLOCK(&f);
4242  SMTPState *smtp_state = f.alstate;
4243  if (smtp_state == NULL) {
4244  printf("no smtp state: ");
4245  goto end;
4246  }
4247  if (smtp_state->current_line == NULL ||
4248  smtp_state->current_line_len != 0 ||
4249  smtp_state->ts_current_line_db == 1 ||
4250  smtp_state->ts_db != NULL ||
4251  smtp_state->ts_db_len != 0 ||
4252  memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
4253  printf("smtp parser in inconsistent state\n");
4254  goto end;
4255  }
4256 
4257  FLOWLOCK_WRLOCK(&f);
4258  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4259  STREAM_TOSERVER, request2, request2_len);
4260  if (r != 0) {
4261  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4262  FLOWLOCK_UNLOCK(&f);
4263  goto end;
4264  }
4265  FLOWLOCK_UNLOCK(&f);
4266  if (smtp_state->ts_current_line_db != 0 ||
4267  smtp_state->ts_db != NULL ||
4268  smtp_state->ts_db_len != 0 ||
4269  smtp_state->current_line == NULL ||
4270  smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
4271  memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
4272  printf("smtp parser in inconsistent state\n");
4273  goto end;
4274  }
4275 
4276  result = 1;
4277 end:
4278  if (alp_tctx != NULL)
4281  FLOW_DESTROY(&f);
4282  return result;
4283 }
4284 
4285 static int SMTPParserTest12(void)
4286 {
4287  int result = 0;
4288  Signature *s = NULL;
4289  ThreadVars th_v;
4290  Packet *p = NULL;
4291  Flow f;
4292  TcpSession ssn;
4293  DetectEngineThreadCtx *det_ctx = NULL;
4294  DetectEngineCtx *de_ctx = NULL;
4295  SMTPState *smtp_state = NULL;
4296  int r = 0;
4297 
4298  /* EHLO boo.com<CR><LF> */
4299  uint8_t request1[] = {
4300  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4301  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4302  };
4303  int32_t request1_len = sizeof(request1);
4304 
4305  /* 388<CR><LF>
4306  */
4307  uint8_t reply1[] = {
4308  0x31, 0x38, 0x38, 0x0d, 0x0a,
4309  };
4310  uint32_t reply1_len = sizeof(reply1);
4311 
4313 
4314  memset(&th_v, 0, sizeof(th_v));
4315  memset(&f, 0, sizeof(f));
4316  memset(&ssn, 0, sizeof(ssn));
4317 
4318  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
4319 
4320  FLOW_INITIALIZE(&f);
4321  f.protoctx = (void *)&ssn;
4322  f.proto = IPPROTO_TCP;
4323  f.alproto = ALPROTO_SMTP;
4324  p->flow = &f;
4328  f.alproto = ALPROTO_SMTP;
4329 
4331  SMTPTestInitConfig();
4332 
4334  if (de_ctx == NULL)
4335  goto end;
4336 
4337  de_ctx->flags |= DE_QUIET;
4338 
4339  s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any "
4340  "(msg:\"SMTP event handling\"; "
4341  "app-layer-event: smtp.invalid_reply; "
4342  "sid:1;)");
4343  if (s == NULL)
4344  goto end;
4345 
4347  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4348 
4349  FLOWLOCK_WRLOCK(&f);
4350  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4351  STREAM_TOSERVER | STREAM_START, request1,
4352  request1_len);
4353  if (r != 0) {
4354  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4355  FLOWLOCK_UNLOCK(&f);
4356  goto end;
4357  }
4358  FLOWLOCK_UNLOCK(&f);
4359 
4360  smtp_state = f.alstate;
4361  if (smtp_state == NULL) {
4362  printf("no smtp state: ");
4363  goto end;
4364  }
4365 
4366  /* do detect */
4367  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4368 
4369  if (PacketAlertCheck(p, 1)) {
4370  printf("sid 1 matched. It shouldn't match: ");
4371  goto end;
4372  }
4373 
4374  FLOWLOCK_WRLOCK(&f);
4375  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4376  STREAM_TOCLIENT | STREAM_TOCLIENT, reply1,
4377  reply1_len);
4378  if (r == 0) {
4379  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4380  FLOWLOCK_UNLOCK(&f);
4381  goto end;
4382  }
4383  FLOWLOCK_UNLOCK(&f);
4384 
4385  /* do detect */
4386  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4387 
4388  if (!PacketAlertCheck(p, 1)) {
4389  printf("sid 1 didn't match. Should have matched: ");
4390  goto end;
4391  }
4392 
4393  result = 1;
4394 
4395 end:
4398 
4399  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4401 
4402  if (alp_tctx != NULL)
4405  FLOW_DESTROY(&f);
4406  UTHFreePackets(&p, 1);
4407  return result;
4408 }
4409 
4410 static int SMTPParserTest13(void)
4411 {
4412  int result = 0;
4413  Signature *s = NULL;
4414  ThreadVars th_v;
4415  Packet *p = NULL;
4416  Flow f;
4417  TcpSession ssn;
4418  DetectEngineThreadCtx *det_ctx = NULL;
4419  DetectEngineCtx *de_ctx = NULL;
4420  SMTPState *smtp_state = NULL;
4421  int r = 0;
4422 
4423  /* EHLO boo.com<CR><LF> */
4424  uint8_t request1[] = {
4425  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4426  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4427  };
4428  int32_t request1_len = sizeof(request1);
4429 
4430  /* 250<CR><LF>
4431  */
4432  uint8_t reply1[] = {
4433  0x32, 0x35, 0x30, 0x0d, 0x0a,
4434  };
4435  uint32_t reply1_len = sizeof(reply1);
4436 
4437  /* MAIL FROM:pbsf@asdfs.com<CR><LF>
4438  * RCPT TO:pbsf@asdfs.com<CR><LF>
4439  * DATA<CR><LF>
4440  * STARTTLS<CR><LF>
4441  */
4442  uint8_t request2[] = {
4443  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
4444  0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
4445  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
4446  0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
4447  0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
4448  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
4449  0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
4450  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
4451  0x0d, 0x0a
4452  };
4453  uint32_t request2_len = sizeof(request2);
4454 
4456 
4457  memset(&th_v, 0, sizeof(th_v));
4458  memset(&f, 0, sizeof(f));
4459  memset(&ssn, 0, sizeof(ssn));
4460 
4461  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
4462 
4463  FLOW_INITIALIZE(&f);
4464  f.protoctx = (void *)&ssn;
4465  f.proto = IPPROTO_TCP;
4466  f.alproto = ALPROTO_SMTP;
4467  p->flow = &f;
4471  f.alproto = ALPROTO_SMTP;
4472 
4474  SMTPTestInitConfig();
4475 
4477  if (de_ctx == NULL)
4478  goto end;
4479 
4480  de_ctx->flags |= DE_QUIET;
4481 
4482  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
4483  "(msg:\"SMTP event handling\"; "
4484  "app-layer-event: "
4485  "smtp.invalid_pipelined_sequence; "
4486  "sid:1;)");
4487  if (s == NULL)
4488  goto end;
4489 
4491  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4492 
4493  FLOWLOCK_WRLOCK(&f);
4494  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4495  STREAM_TOSERVER | STREAM_START, request1,
4496  request1_len);
4497  if (r != 0) {
4498  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4499  FLOWLOCK_UNLOCK(&f);
4500  goto end;
4501  }
4502  FLOWLOCK_UNLOCK(&f);
4503 
4504  smtp_state = f.alstate;
4505  if (smtp_state == NULL) {
4506  printf("no smtp state: ");
4507  goto end;
4508  }
4509 
4510  /* do detect */
4511  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4512 
4513  if (PacketAlertCheck(p, 1)) {
4514  printf("sid 1 matched. It shouldn't match: ");
4515  goto end;
4516  }
4517 
4518  FLOWLOCK_WRLOCK(&f);
4519  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4520  STREAM_TOCLIENT, reply1, reply1_len);
4521  if (r != 0) {
4522  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4523  FLOWLOCK_UNLOCK(&f);
4524  goto end;
4525  }
4526  FLOWLOCK_UNLOCK(&f);
4527 
4528  /* do detect */
4529  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4530 
4531  if (PacketAlertCheck(p, 1)) {
4532  printf("sid 1 matched. It shouldn't match: ");
4533  goto end;
4534  }
4535 
4536  FLOWLOCK_WRLOCK(&f);
4537  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4538  STREAM_TOSERVER, request2, request2_len);
4539  if (r != 0) {
4540  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4541  FLOWLOCK_UNLOCK(&f);
4542  goto end;
4543  }
4544  FLOWLOCK_UNLOCK(&f);
4545 
4546  /* do detect */
4547  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4548 
4549  if (!PacketAlertCheck(p, 1)) {
4550  printf("sid 1 didn't match. Should have matched: ");
4551  goto end;
4552  }
4553 
4554  result = 1;
4555 
4556 end:
4559 
4560  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4562 
4563  if (alp_tctx != NULL)
4566  FLOW_DESTROY(&f);
4567  UTHFreePackets(&p, 1);
4568  return result;
4569 }
4570 
4571 /**
4572  * \test Test DATA command w/MIME message.
4573  */
4574 static int SMTPParserTest14(void)
4575 {
4576  int result = 0;
4577  Flow f;
4578  int r = 0;
4579 
4580  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
4581  static uint8_t welcome_reply[] = {
4582  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
4583  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
4584  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
4585  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
4586  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
4587  0x0d, 0x0a
4588  };
4589  static uint32_t welcome_reply_len = sizeof(welcome_reply);
4590 
4591  /* EHLO boo.com<CR><LF> */
4592  static uint8_t request1[] = {
4593  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4594  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
4595  };
4596  static uint32_t request1_len = sizeof(request1);
4597  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
4598  * 250-SIZE 35882577<CR><LF>
4599  * 250-8BITMIME<CR><LF>
4600  * 250-STARTTLS<CR><LF>
4601  * 250 ENHANCEDSTATUSCODES<CR><LF>
4602  */
4603  static uint8_t reply1[] = {
4604  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
4605  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
4606  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
4607  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
4608  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
4609  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
4610  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
4611  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
4612  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
4613  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
4614  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
4615  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
4616  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
4617  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
4618  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
4619  };
4620  static uint32_t reply1_len = sizeof(reply1);
4621 
4622  /* MAIL FROM:asdff@asdf.com<CR><LF> */
4623  static uint8_t request2[] = {
4624  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
4625  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
4626  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
4627  0x0d, 0x0a
4628  };
4629  static uint32_t request2_len = sizeof(request2);
4630  /* 250 2.1.0 Ok<CR><LF> */
4631  static uint8_t reply2[] = {
4632  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4633  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4634  };
4635  static uint32_t reply2_len = sizeof(reply2);
4636 
4637  /* RCPT TO:bimbs@gmail.com<CR><LF> */
4638  static uint8_t request3[] = {
4639  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
4640  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
4641  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
4642  0x0a
4643  };
4644  static uint32_t request3_len = sizeof(request3);
4645  /* 250 2.1.5 Ok<CR><LF> */
4646  static uint8_t reply3[] = {
4647  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4648  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4649  };
4650  static uint32_t reply3_len = sizeof(reply3);
4651 
4652  /* DATA<CR><LF> */
4653  static uint8_t request4[] = {
4654  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
4655  };
4656  static uint32_t request4_len = sizeof(request4);
4657  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
4658  static uint8_t reply4[] = {
4659  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
4660  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
4661  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
4662  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
4663  0x4c, 0x46, 0x3e, 0x0d, 0x0a
4664  };
4665  static uint32_t reply4_len = sizeof(reply4);
4666 
4667  /* MIME_MSG */
4668  static uint64_t filesize = 133;
4669  static uint8_t request4_msg[] = {
4670  0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
4671  0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
4672  0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4673  0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
4674  0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
4675  0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
4676  0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
4677  0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4678  0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
4679  0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
4680  0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
4681  0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
4682  0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
4683  0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
4684  0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
4685  0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
4686  0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
4687  0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
4688  0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
4689  0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
4690  0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
4691  0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
4692  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4693  0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
4694  0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
4695  0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
4696  0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
4697  0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
4698  0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
4699  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4700  0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
4701  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4702  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4703  0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
4704  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4705  0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4706  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4707  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4708  0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
4709  0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
4710  0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
4711  0x41, 0x3D, 0x3D, 0x0D,0x0A };
4712  static uint32_t request4_msg_len = sizeof(request4_msg);
4713 
4714  /* DATA COMPLETED */
4715  static uint8_t request4_end[] = {
4716  0x0d, 0x0a, 0x2e, 0x0d, 0x0a
4717  };
4718  static uint32_t request4_end_len = sizeof(request4_end);
4719  /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
4720  static uint8_t reply4_end[] = {
4721  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4722  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
4723  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
4724  0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
4725  0x46, 0x32, 0x0d, 0x0a
4726  };
4727  static uint32_t reply4_end_len = sizeof(reply4_end);
4728 
4729  /* QUIT<CR><LF> */
4730  static uint8_t request5[] = {
4731  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
4732  };
4733  static uint32_t request5_len = sizeof(request5);
4734  /* 221 2.0.0 Bye<CR><LF> */
4735  static uint8_t reply5[] = {
4736  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4737  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
4738  };
4739  static uint32_t reply5_len = sizeof(reply5);
4740 
4741  TcpSession ssn;
4743 
4744  memset(&f, 0, sizeof(f));
4745  memset(&ssn, 0, sizeof(ssn));
4746 
4747  FLOW_INITIALIZE(&f);
4748  f.protoctx = (void *)&ssn;
4749  f.proto = IPPROTO_TCP;
4750  f.alproto = ALPROTO_SMTP;
4751 
4753  SMTPTestInitConfig();
4754 
4755  FLOWLOCK_WRLOCK(&f);
4756  /* Welcome reply */
4757  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4758  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
4759  if (r != 0) {
4760  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4761  FLOWLOCK_UNLOCK(&f);
4762  goto end;
4763  }
4764  FLOWLOCK_UNLOCK(&f);
4765  SMTPState *smtp_state = f.alstate;
4766  if (smtp_state == NULL) {
4767  printf("no smtp state: ");
4768  goto end;
4769  }
4770  if (smtp_state->input_len != 0 ||
4771  smtp_state->cmds_cnt != 0 ||
4772  smtp_state->cmds_idx != 0 ||
4774  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4775  goto end;
4776  }
4777 
4778  FLOWLOCK_WRLOCK(&f);
4779  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4780  STREAM_TOSERVER, request1, request1_len);
4781  if (r != 0) {
4782  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4783  FLOWLOCK_UNLOCK(&f);
4784  goto end;
4785  }
4786  FLOWLOCK_UNLOCK(&f);
4787  if (smtp_state->input_len != 0 ||
4788  smtp_state->cmds_cnt != 1 ||
4789  smtp_state->cmds_idx != 0 ||
4790  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4792  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4793  goto end;
4794  }
4795 
4796  FLOWLOCK_WRLOCK(&f);
4797  /* EHLO Reply */
4798  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4799  STREAM_TOCLIENT, reply1, reply1_len);
4800  if (r != 0) {
4801  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4802  FLOWLOCK_UNLOCK(&f);
4803  goto end;
4804  }
4805 
4806  if ((smtp_state->helo_len != 7) || strncmp("boo.com", (char *)smtp_state->helo, 7)) {
4807  printf("incorrect parsing of HELO field '%s' (%d)\n", smtp_state->helo, smtp_state->helo_len);
4808  FLOWLOCK_UNLOCK(&f);
4809  goto end;
4810  }
4811 
4812  FLOWLOCK_UNLOCK(&f);
4813  if (smtp_state->input_len != 0 ||
4814  smtp_state->cmds_cnt != 0 ||
4815  smtp_state->cmds_idx != 0 ||
4817  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4818  goto end;
4819  }
4820 
4821  FLOWLOCK_WRLOCK(&f);
4822  /* MAIL FROM Request */
4823  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4824  STREAM_TOSERVER, request2, request2_len);
4825  if (r != 0) {
4826  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4827  FLOWLOCK_UNLOCK(&f);
4828  goto end;
4829  }
4830  FLOWLOCK_UNLOCK(&f);
4831  if (smtp_state->input_len != 0 ||
4832  smtp_state->cmds_cnt != 1 ||
4833  smtp_state->cmds_idx != 0 ||
4834  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4836  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4837  goto end;
4838  }
4839 
4840  FLOWLOCK_WRLOCK(&f);
4841  /* MAIL FROM Reply */
4842  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4843  STREAM_TOCLIENT, reply2, reply2_len);
4844  if (r != 0) {
4845  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4846  FLOWLOCK_UNLOCK(&f);
4847  goto end;
4848  }
4849 
4850  if ((smtp_state->curr_tx->mail_from_len != 14) ||
4851  strncmp("asdff@asdf.com", (char *)smtp_state->curr_tx->mail_from, 14)) {
4852  printf("incorrect parsing of MAIL FROM field '%s' (%d)\n",
4853  smtp_state->curr_tx->mail_from,
4854  smtp_state->curr_tx->mail_from_len);
4855  FLOWLOCK_UNLOCK(&f);
4856  goto end;
4857  }
4858 
4859  FLOWLOCK_UNLOCK(&f);
4860  if (smtp_state->input_len != 0 ||
4861  smtp_state->cmds_cnt != 0 ||
4862  smtp_state->cmds_idx != 0 ||
4864  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4865  goto end;
4866  }
4867 
4868  FLOWLOCK_WRLOCK(&f);
4869  /* RCPT TO Request */
4870  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4871  STREAM_TOSERVER, request3, request3_len);
4872  if (r != 0) {
4873  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4874  FLOWLOCK_UNLOCK(&f);
4875  goto end;
4876  }
4877  FLOWLOCK_UNLOCK(&f);
4878  if (smtp_state->input_len != 0 ||
4879  smtp_state->cmds_cnt != 1 ||
4880  smtp_state->cmds_idx != 0 ||
4881  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4883  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4884  goto end;
4885  }
4886 
4887  FLOWLOCK_WRLOCK(&f);
4888  /* RCPT TO Reply */
4889  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4890  STREAM_TOCLIENT, reply3, reply3_len);
4891  if (r != 0) {
4892  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4893  FLOWLOCK_UNLOCK(&f);
4894  goto end;
4895  }
4896  FLOWLOCK_UNLOCK(&f);
4897  if (smtp_state->input_len != 0 ||
4898  smtp_state->cmds_cnt != 0 ||
4899  smtp_state->cmds_idx != 0 ||
4901  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4902  goto end;
4903  }
4904 
4905  /* Enable mime decoding */
4910 
4911  FLOWLOCK_WRLOCK(&f);
4912  /* DATA request */
4913  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4914  STREAM_TOSERVER, request4, request4_len);
4915  if (r != 0) {
4916  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4917  FLOWLOCK_UNLOCK(&f);
4918  goto end;
4919  }
4920  FLOWLOCK_UNLOCK(&f);
4921 
4922  if (smtp_state->input_len != 0 ||
4923  smtp_state->cmds_cnt != 1 ||
4924  smtp_state->cmds_idx != 0 ||
4925  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
4927  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4928  goto end;
4929  }
4930 
4931  FLOWLOCK_WRLOCK(&f);
4932  /* Data reply */
4933  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4934  STREAM_TOCLIENT, reply4, reply4_len);
4935  if (r != 0) {
4936  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4937  FLOWLOCK_UNLOCK(&f);
4938  goto end;
4939  }
4940  FLOWLOCK_UNLOCK(&f);
4941  if (smtp_state->input_len != 0 ||
4942  smtp_state->cmds_cnt != 0 ||
4943  smtp_state->cmds_idx != 0 ||
4946  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4947  goto end;
4948  }
4949 
4950  FLOWLOCK_WRLOCK(&f);
4951  /* DATA message */
4952  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4953  STREAM_TOSERVER, request4_msg, request4_msg_len);
4954  if (r != 0) {
4955  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4956  FLOWLOCK_UNLOCK(&f);
4957  goto end;
4958  }
4959  FLOWLOCK_UNLOCK(&f);
4960 
4961  if (smtp_state->input_len != 0 ||
4962  smtp_state->cmds_cnt != 0 ||
4963  smtp_state->cmds_idx != 0 ||
4964  smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */
4967  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4968  goto end;
4969  }
4970 
4971  FLOWLOCK_WRLOCK(&f);
4972  /* DATA . request */
4973  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4974  STREAM_TOSERVER, request4_end, request4_end_len);
4975  if (r != 0) {
4976  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4977  FLOWLOCK_UNLOCK(&f);
4978  goto end;
4979  }
4980  FLOWLOCK_UNLOCK(&f);
4981 
4982  if (smtp_state->input_len != 0 ||
4983  smtp_state->cmds_cnt != 1 ||
4984  smtp_state->cmds_idx != 0 ||
4985  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
4986  smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */
4988  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4989  goto end;
4990  }
4991 
4992  SMTPState *state = (SMTPState *) f.alstate;
4993  FileContainer *files = state->files_ts;
4994  if (files != NULL && files->head != NULL) {
4995  File *file = files->head;
4996 
4997  if(strncmp((const char *)file->name, "test.exe", 8) != 0){
4998  printf("smtp-mime file name is incorrect");
4999  goto end;
5000  }
5001  if (FileTrackedSize(file) != filesize){
5002  printf("smtp-mime file size %"PRIu64" is incorrect", FileDataSize(file));
5003  goto end;
5004  }
5005  static uint8_t org_binary[] = {
5006  0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00,
5007  0x4C, 0x01, 0x01, 0x00, 0x6A, 0x2A, 0x58, 0xC3,
5008  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5009  0x04, 0x00, 0x03, 0x01, 0x0B, 0x01, 0x08, 0x00,
5010  0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
5011  0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
5012  0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
5013  0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00,
5014  0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00,
5015  0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
5016  0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00,
5017  0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5018  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5019  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5020  0x00, 0x00, 0x00, 0x00, 0x5C, 0x5C, 0x36, 0x36,
5021  0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36,
5022  0x5C, 0x7A, 0x00, 0x00, 0x38,};
5023 
5025  org_binary, sizeof(org_binary)) != 1)
5026  {
5027  printf("smtp-mime file data incorrect\n");
5028  goto end;
5029  }
5030  }
5031 
5032  FLOWLOCK_WRLOCK(&f);
5033  /* DATA . reply */
5034  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
5035  STREAM_TOCLIENT, reply4_end, reply4_end_len);
5036  if (r != 0) {
5037  printf("smtp check returned %" PRId32 ", expected 0: ", r);
5038  FLOWLOCK_UNLOCK(&f);
5039  goto end;
5040  }
5041  FLOWLOCK_UNLOCK(&f);
5042  if (smtp_state->input_len != 0 ||
5043  smtp_state->cmds_cnt != 0 ||
5044  smtp_state->cmds_idx != 0 ||
5046  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
5047  goto end;
5048  }
5049 
5050  FLOWLOCK_WRLOCK(&f);
5051  /* QUIT Request */
5052  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
5053  STREAM_TOSERVER, request5, request5_len);
5054  if (r != 0) {
5055  printf("smtp check returned %" PRId32 ", expected 0: ", r);
5056  FLOWLOCK_UNLOCK(&f);
5057  goto end;
5058  }
5059  FLOWLOCK_UNLOCK(&f);
5060  if (smtp_state->input_len != 0 ||
5061  smtp_state->cmds_cnt != 1 ||
5062  smtp_state->cmds_idx != 0 ||
5063  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
5065  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
5066  goto end;
5067  }
5068 
5069  FLOWLOCK_WRLOCK(&f);
5070  /* QUIT Reply */
5071  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
5072  STREAM_TOCLIENT, reply5, reply5_len);
5073  if (r != 0) {
5074  printf("smtp check returned %" PRId32 ", expected 0: ", r);
5075  FLOWLOCK_UNLOCK(&f);
5076  goto end;
5077  }
5078  FLOWLOCK_UNLOCK(&f);
5079  if (smtp_state->input_len != 0 ||
5080  smtp_state->cmds_cnt != 0 ||
5081  smtp_state->cmds_idx != 0 ||
5083  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
5084  goto end;
5085  }
5086 
5087  result = 1;
5088 end:
5089  if (alp_tctx != NULL)
5092  FLOW_DESTROY(&f);
5093  return result;
5094 }
5095 
5096 static int SMTPProcessDataChunkTest01(void){
5097  Flow f;
5098  FLOW_INITIALIZE(&f);
5100  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5101  int ret;
5102  ret = SMTPProcessDataChunk(NULL, 0, state);
5103 
5104  return ret == 0;
5105 }
5106 
5107 
5108 static int SMTPProcessDataChunkTest02(void){
5109  char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
5110  0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
5111  0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
5112  0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
5113  0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
5114  0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
5115  0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
5116  0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
5117  0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
5118  0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
5119  0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
5120  0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
5121  0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
5122  0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
5123  0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
5124  0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
5125  0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
5126  0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
5127  0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
5128  0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
5129  0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
5130  0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
5131  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
5132  0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
5133  0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
5134  0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
5135  0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
5136  0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
5137  0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
5138  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
5139  0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
5140  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
5141  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
5142  0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
5143  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
5144  0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
5145  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
5146  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
5147  0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
5148  0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
5149  0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
5150  0x41, 0x3D, 0x3D, 0x0D, 0x0A,};
5151 
5152  Flow f;
5153  TcpSession ssn;
5154  memset(&ssn, 0, sizeof(ssn));
5155  FLOW_INITIALIZE(&f);
5156  f.protoctx = &ssn;
5158  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5159  ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
5160  state->body_begin = 1;
5161  int ret;
5162  ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
5163 
5164  return ret == 0;
5165 }
5166 
5167 
5168 
5169 static int SMTPProcessDataChunkTest03(void){
5170  char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, };
5171  char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, };
5172  char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5173  char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, };
5174  char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, };
5175  char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, };
5176  char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, };
5177  char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5178  char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, };
5179  char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, };
5180  char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, };
5181  char mimemsg12[] = {0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F, };
5182 
5183  TcpSession ssn;
5184  memset(&ssn, 0, sizeof(ssn));
5185  Flow f;
5186  FLOW_INITIALIZE(&f);
5187  f.protoctx = &ssn;
5189  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5190  ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
5191  int ret;
5192 
5193  state->body_begin = 1;
5194  ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
5195  if(ret) goto end;
5196  state->body_begin = 0;
5197  ret = SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state);
5198  if(ret) goto end;
5199  ret = SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state);
5200  if(ret) goto end;
5201  ret = SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state);
5202  if(ret) goto end;
5203  ret = SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state);
5204  if(ret) goto end;
5205  ret = SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state);
5206  if(ret) goto end;
5207  ret = SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state);
5208  if(ret) goto end;
5209  ret = SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state);
5210  if(ret) goto end;
5211  ret = SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state);
5212  if(ret) goto end;
5213  ret = SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state);
5214  if(ret) goto end;
5215  ret = SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state);
5216  if(ret) goto end;
5217  state->body_end = 1;
5218  ret = SMTPProcessDataChunk((uint8_t *)mimemsg12, sizeof(mimemsg12), state);
5219  if(ret) goto end;
5220 
5221  end:
5222  return ret == 0;
5223 }
5224 
5225 
5226 static int SMTPProcessDataChunkTest04(void){
5227  char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, };
5228  char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, };
5229  char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5230  char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, };
5231  char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, };
5232  char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, };
5233  char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, };
5234  char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5235  char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, };
5236  char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, };
5237  char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, };
5238 
5239  TcpSession ssn;
5240  memset(&ssn, 0, sizeof(ssn));
5241  Flow f;
5242  FLOW_INITIALIZE(&f);
5243  f.protoctx = &ssn;
5245  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5246  ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
5247  int ret = MIME_DEC_OK;
5248 
5249  state->body_begin = 1;
5250  if(SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state) != 0) goto end;
5251  if(SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state) != 0) goto end;
5252  if(SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state) != 0) goto end;
5253  if(SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state) != 0) goto end;
5254  if(SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state) != 0) goto end;
5255  if(SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state) != 0) goto end;
5256  if(SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state) != 0) goto end;
5257  state->body_begin = 0;
5258  state->body_end = 1;
5259  if(SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state) != 0) goto end;
5260  state->body_end = 0;
5261  if(SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state) != 0) goto end;
5262  if(SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state) != 0) goto end;
5263  if(SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state) != 0) goto end;
5264 
5265  end:
5266  return ret == 0;
5267 }
5268 
5269 static int SMTPProcessDataChunkTest05(void){
5270  char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
5271  0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
5272  0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
5273  0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
5274  0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
5275  0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
5276  0x41, 0x3D, 0x3D, 0x0D, 0x0A,};
5277 
5278  TcpSession ssn;
5279  memset(&ssn, 0, sizeof(ssn));
5280  Flow f;
5281  int ret;
5282  FLOW_INITIALIZE(&f);
5283  f.protoctx = &ssn;
5285  FAIL_IF(f.alstate == NULL);
5286  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5287  ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
5288  FAIL_IF(state == NULL);
5289  state->body_begin = 1;
5290  ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
5291  FAIL_IF(ret != 0);
5292  state->body_begin = 0;
5293  SMTPState *smtp_state = (SMTPState *)((Flow *)state->data)->alstate;
5294  FileContainer *files = smtp_state->files_ts;
5295  FAIL_IF(files == NULL);
5296  File *file = files->head;
5297  FAIL_IF(file == NULL);
5298  ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
5299  FAIL_IF(ret != 0);
5300  FAIL_IF((uint32_t)FileDataSize(file) != 106);
5301  SMTPStateFree(smtp_state);
5302  FLOW_DESTROY(&f);
5303  PASS;
5304 }
5305 
5306 #endif /* UNITTESTS */
5307 
5309 {
5310 #ifdef UNITTESTS
5311  UtRegisterTest("SMTPParserTest01", SMTPParserTest01);
5312  UtRegisterTest("SMTPParserTest02", SMTPParserTest02);
5313  UtRegisterTest("SMTPParserTest03", SMTPParserTest03);
5314  UtRegisterTest("SMTPParserTest04", SMTPParserTest04);
5315  UtRegisterTest("SMTPParserTest05", SMTPParserTest05);
5316  UtRegisterTest("SMTPParserTest06", SMTPParserTest06);
5317  UtRegisterTest("SMTPParserTest07", SMTPParserTest07);
5318  UtRegisterTest("SMTPParserTest08", SMTPParserTest08);
5319  UtRegisterTest("SMTPParserTest09", SMTPParserTest09);
5320  UtRegisterTest("SMTPParserTest10", SMTPParserTest10);
5321  UtRegisterTest("SMTPParserTest11", SMTPParserTest11);
5322  UtRegisterTest("SMTPParserTest12", SMTPParserTest12);
5323  UtRegisterTest("SMTPParserTest13", SMTPParserTest13);
5324  UtRegisterTest("SMTPParserTest14", SMTPParserTest14);
5325  UtRegisterTest("SMTPProcessDataChunkTest01", SMTPProcessDataChunkTest01);
5326  UtRegisterTest("SMTPProcessDataChunkTest02", SMTPProcessDataChunkTest02);
5327  UtRegisterTest("SMTPProcessDataChunkTest03", SMTPProcessDataChunkTest03);
5328  UtRegisterTest("SMTPProcessDataChunkTest04", SMTPProcessDataChunkTest04);
5329  UtRegisterTest("SMTPProcessDataChunkTest05", SMTPProcessDataChunkTest05);
5330 #endif /* UNITTESTS */
5331 
5332  return;
5333 }
MpmInitThreadCtx
void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher)
Definition: util-mpm.c:249
PARSE_ERROR
#define PARSE_ERROR
Definition: util-decode-mime.h:76
util-byte.h
MimeDecEntity::ctnt_flags
uint32_t ctnt_flags
Definition: util-decode-mime.h:138
SMTPConfig::content_limit
uint32_t content_limit
Definition: app-layer-smtp.h:98
ConfGetChildValueInt
int ConfGetChildValueInt(const ConfNode *base, const char *name, intmax_t *val)
Definition: conf.c:468
SMTPState_
Definition: app-layer-smtp.h:107
FILE_TRUNCATED
#define FILE_TRUNCATED
Definition: util-file.h:36
SMTPState_::ts_db_len
int32_t ts_db_len
Definition: app-layer-smtp.h:137
MimeDecParseComplete
int MimeDecParseComplete(MimeDecParseState *state)
Called to indicate that the last message line has been processed and the parsing operation is complet...
Definition: util-decode-mime.c:2525
AppLayerParserRegisterGetStateProgressFunc
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, int(*StateGetProgress)(void *alstate, uint8_t direction))
Definition: app-layer-parser.c:475
FileContainer_
Definition: util-file.h:100
len
uint8_t len
Definition: app-layer-dnp3.h:2
MIME_DEC_OK
@ MIME_DEC_OK
Definition: util-decode-mime.h:82
MIME_DEC_ERR_MEM
@ MIME_DEC_ERR_MEM
Definition: util-decode-mime.h:85
detect-engine.h
SMTP_DECODER_EVENT_TLS_REJECTED
@ SMTP_DECODER_EVENT_TLS_REJECTED
Definition: app-layer-smtp.h:41
SMTPCode
SMTPCode
Definition: app-layer-smtp.c:174
DetectEngineStateDirection_::flags
uint8_t flags
Definition: detect-engine-state.h:88
AppLayerProtoDetectPMRegisterPatternCI
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.
Definition: app-layer-detect-proto.c:1800
SMTPState_::cmds_cnt
uint16_t cmds_cnt
Definition: app-layer-smtp.h:158
StreamingBufferConfig_::buf_size
uint32_t buf_size
Definition: util-streaming-buffer.h:70
PKT_HAS_FLOW
#define PKT_HAS_FLOW
Definition: decode.h:1109
AppLayerParserRegisterLocalStorageFunc
void AppLayerParserRegisterLocalStorageFunc(uint8_t ipproto, AppProto alproto, void *(*LocalStorageAlloc)(void), void(*LocalStorageFree)(void *))
Definition: app-layer-parser.c:411
SMTP_PARSER_STATE_FIRST_REPLY_SEEN
#define SMTP_PARSER_STATE_FIRST_REPLY_SEEN
Definition: app-layer-smtp.c:84
TAILQ_INIT
#define TAILQ_INIT(head)
Definition: queue.h:370
ANOM_LONG_BOUNDARY
#define ANOM_LONG_BOUNDARY
Definition: util-decode-mime.h:61
flow-util.h
MimeDecConfig::header_value_depth
uint32_t header_value_depth
Definition: util-decode-mime.h:99
SMTPTransaction_::msg_tail
MimeDecEntity * msg_tail
Definition: app-layer-smtp.h:78
SMTP_COMMAND_DATA
#define SMTP_COMMAND_DATA
Definition: app-layer-smtp.c:95
FileContainerAlloc
FileContainer * FileContainerAlloc(void)
allocate a FileContainer
Definition: util-file.c:423
DetectEngineState_
Definition: detect-engine-state.h:92
MpmThreadCtx_
Definition: util-mpm.h:46
ConfNode_::val
char * val
Definition: conf.h:34
ConfGetBool
int ConfGetBool(const char *name, int *val)
Retrieve a configuration value as an boolen.
Definition: conf.c:516
stream-tcp.h
SMTPState_::bdat_chunk_idx
uint32_t bdat_chunk_idx
Definition: app-layer-smtp.h:149
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
SMTPState_::current_line_len
int32_t current_line_len
Definition: app-layer-smtp.h:123
SMTPState_::current_line
const uint8_t * current_line
Definition: app-layer-smtp.h:121
PrefilterRuleStore_
structure for storing potential rule matches
Definition: util-prefilter.h:32
SMTPState_::current_line_delimiter_len
uint8_t current_line_delimiter_len
Definition: app-layer-smtp.h:124
MimeDecParseState::data
void * data
Definition: util-decode-mime.h:209
MimeDecParseLine
int MimeDecParseLine(const uint8_t *line, const uint32_t len, const uint8_t delim_len, MimeDecParseState *state)
Parse a line of a MIME message and update the parser state.
Definition: util-decode-mime.c:2587
MimeDecEntity::filename
uint8_t * filename
Definition: util-decode-mime.h:141
SMTPTransaction_::mime_state
MimeDecParseState * mime_state
Definition: app-layer-smtp.h:80
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
SMTPConfig
Definition: app-layer-smtp.h:94
SMTPState_::tc_current_line_db
uint8_t tc_current_line_db
Definition: app-layer-smtp.h:130
SMTPTransaction_::msg_head
MimeDecEntity * msg_head
Definition: app-layer-smtp.h:76
SMTP_REPLY_421
@ SMTP_REPLY_421
Definition: app-layer-smtp.c:187
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
MpmInitCtx
void MpmInitCtx(MpmCtx *mpm_ctx, uint16_t matcher)
Definition: util-mpm.c:254
Flow_::proto
uint8_t proto
Definition: flow.h:365
SMTPState_::tc_db
uint8_t * tc_db
Definition: app-layer-smtp.h:128
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:73
SMTPState_::input_len
int32_t input_len
Definition: app-layer-smtp.h:116
AppLayerParserConfParserEnabled
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
Definition: app-layer-parser.c:301
PacketAlertCheck
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
Definition: detect-engine-alert.c:138
SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED
@ SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED
Definition: app-layer-smtp.h:36
AppLayerParserTriggerRawStreamReassembly
void AppLayerParserTriggerRawStreamReassembly(Flow *f, int direction)
Definition: app-layer-parser.c:1434
StreamTcpReassemblySetMinInspectDepth
void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
Definition: stream-tcp-reassemble.c:1950
STREAMING_BUFFER_CONFIG_INITIALIZER
#define STREAMING_BUFFER_CONFIG_INITIALIZER
Definition: util-streaming-buffer.h:77
Packet_::flags
uint32_t flags
Definition: decode.h:449
ConfGetNode
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:175
threads.h
FILE_STATE_OPENED
@ FILE_STATE_OPENED
Definition: util-file.h:54
ANOM_LONG_LINE
#define ANOM_LONG_LINE
Definition: util-decode-mime.h:58
Flow_
Flow data structure.
Definition: flow.h:347
MimeDecStack::top
MimeDecStackNode * top
Definition: util-decode-mime.h:168
SMTP_REPLY_503
@ SMTP_REPLY_503
Definition: app-layer-smtp.c:196
AppLayerEventType
enum AppLayerEventType_ AppLayerEventType
SMTP_DECODER_EVENT_INVALID_REPLY
@ SMTP_DECODER_EVENT_INVALID_REPLY
Definition: app-layer-smtp.h:34
AppLayerParserRegisterGetEventsFunc
void AppLayerParserRegisterGetEventsFunc(uint8_t ipproto, AppProto alproto, AppLayerDecoderEvents *(*StateGetEvents)(void *))
Definition: app-layer-parser.c:436
MimeDecEntity::filename_len
uint32_t filename_len
Definition: util-decode-mime.h:140
AppLayerParserRegisterTruncateFunc
void AppLayerParserRegisterTruncateFunc(uint8_t ipproto, AppProto alproto, void(*Truncate)(void *, uint8_t))
Definition: app-layer-parser.c:465
SMTP_REPLY_553
@ SMTP_REPLY_553
Definition: app-layer-smtp.c:201
SMTP_REPLY_500
@ SMTP_REPLY_500
Definition: app-layer-smtp.c:193
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:767
FILE_STORE
#define FILE_STORE
Definition: util-file.h:46
SMTPState_::toserver_last_data_stamp
uint64_t toserver_last_data_stamp
Definition: app-layer-smtp.h:112
SMTPThreadCtx
struct SMTPThreadCtx_ SMTPThreadCtx
AppLayerParserRegisterTxFreeFunc
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))
Definition: app-layer-parser.c:486
FileSetTx
int FileSetTx(File *ff, uint64_t txid)
Set the TX id for a file.
Definition: util-file.c:566
FLOW_NOPAYLOAD_INSPECTION
#define FLOW_NOPAYLOAD_INSPECTION
Definition: flow.h:62
SCEnumCharMap_::enum_value
int enum_value
Definition: util-enum.h:29
SMTPState_::tx_cnt
uint64_t tx_cnt
Definition: app-layer-smtp.h:110
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:350
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2093
DetectEngineState_::dir_state
DetectEngineStateDirection dir_state[2]
Definition: detect-engine-state.h:93
AppLayerParserThreadCtxFree
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
Definition: app-layer-parser.c:278
SMTPState_::cmds_idx
uint16_t cmds_idx
Definition: app-layer-smtp.h:161
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:219
FileContainer_::tail
File * tail
Definition: util-file.h:102
AppLayerDecoderEventsFreeEvents
void AppLayerDecoderEventsFreeEvents(AppLayerDecoderEvents **events)
Definition: app-layer-events.c:148
DE_QUIET
#define DE_QUIET
Definition: detect.h:294
SMTP_REPLY_552
@ SMTP_REPLY_552
Definition: app-layer-smtp.c:200
stream-tcp-reassemble.h
AppLayerParserRegisterDetectStateFuncs
void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, DetectEngineState *(*GetTxDetectState)(void *tx), int(*SetTxDetectState)(void *tx, DetectEngineState *))
Definition: app-layer-parser.c:562
UTHBuildPacket
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
Definition: util-unittest-helper.c:337
SMTP_REPLY_550
@ SMTP_REPLY_550
Definition: app-layer-smtp.c:198
FILEDATA_CONTENT_LIMIT
#define FILEDATA_CONTENT_LIMIT
Definition: app-layer-smtp.c:61
SMTP_REPLY_334
@ SMTP_REPLY_334
Definition: app-layer-smtp.c:184
MimeDecSetConfig
void MimeDecSetConfig(MimeDecConfig *config)
Set global config policy.
Definition: util-decode-mime.c:133
TAILQ_INSERT_TAIL
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:385
MimeDecInitParser
MimeDecParseState * MimeDecInitParser(void *data, int(*DataChunkProcessorFunc)(const uint8_t *chunk, uint32_t len, MimeDecParseState *state))
Init the parser by allocating memory for the state and top-level entity.
Definition: util-decode-mime.c:2431
SigCleanSignatures
void SigCleanSignatures(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:39
SMTPState_::ts_current_line_lf_seen
uint8_t ts_current_line_lf_seen
Definition: app-layer-smtp.h:140
SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE
@ SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE
Definition: app-layer-smtp.h:38
SMTPThreadCtx_
Definition: app-layer-smtp.c:163
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:445
APP_LAYER_PARSER_EOF_TS
#define APP_LAYER_PARSER_EOF_TS
Definition: app-layer-parser.h:41
SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY
#define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY
Definition: app-layer-smtp.c:86
Flow_::protoctx
void * protoctx
Definition: flow.h:441
FileAppendData
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:722
SMTP_REPLY_251
@ SMTP_REPLY_251
Definition: app-layer-smtp.c:181
SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST
@ SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST
Definition: app-layer-smtp.h:35
SMTPState_::direction
uint8_t direction
Definition: app-layer-smtp.h:117
AppLayerDecoderEvents_
Data structure to store app layer decoder events.
Definition: app-layer-events.h:34
SMTPState_::tc_db_len
int32_t tc_db_len
Definition: app-layer-smtp.h:129
util-unittest.h
APP_LAYER_EVENT_TYPE_TRANSACTION
@ APP_LAYER_EVENT_TYPE_TRANSACTION
Definition: app-layer-events.h:57
smtp_decoder_event_table
SCEnumCharMap smtp_decoder_event_table[]
Definition: app-layer-smtp.c:113
SMTPConfig::content_inspect_min_size
uint32_t content_inspect_min_size
Definition: app-layer-smtp.h:99
util-unittest-helper.h
SMTP_REPLY_502
@ SMTP_REPLY_502
Definition: app-layer-smtp.c:195
TcpSession_::flags
uint16_t flags
Definition: stream-tcp-private.h:269
FLOWLOCK_UNLOCK
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:264
STREAM_START
#define STREAM_START
Definition: stream.h:29
File_::sb
StreamingBuffer * sb
Definition: util-file.h:67
SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME
@ SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME
Definition: app-layer-smtp.h:51
util-memcmp.h
MimeDecParseState::body_begin
int body_begin
Definition: util-decode-mime.h:206
SC_ERR_SIZE_PARSE
@ SC_ERR_SIZE_PARSE
Definition: util-error.h:230
ANOM_MALFORMED_MSG
#define ANOM_MALFORMED_MSG
Definition: util-decode-mime.h:60
SMTP_DECODER_EVENT_MIME_PARSE_FAILED
@ SMTP_DECODER_EVENT_MIME_PARSE_FAILED
Definition: app-layer-smtp.h:45
app-layer-detect-proto.h
SMTP_DECODER_EVENT_MIME_LONG_LINE
@ SMTP_DECODER_EVENT_MIME_LONG_LINE
Definition: app-layer-smtp.h:49
FLOW_INITIALIZE
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:39
SMTP_REPLY_504
@ SMTP_REPLY_504
Definition: app-layer-smtp.c:197
AppLayerParserStateIssetFlag
int AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint8_t flag)
Definition: app-layer-parser.c:1648
SMTP_COMMAND_DATA_MODE
#define SMTP_COMMAND_DATA_MODE
Definition: app-layer-smtp.c:101
SMTP_COMMAND_STARTTLS
#define SMTP_COMMAND_STARTTLS
Definition: app-layer-smtp.c:94
TAILQ_REMOVE
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:412
decode.h
util-debug.h
SMTP_MPM
#define SMTP_MPM
Definition: app-layer-smtp.c:168
TAILQ_FIRST
#define TAILQ_FIRST(head)
Definition: queue.h:339
AppLayerParserState_
Definition: app-layer-parser.c:154
SC_ERR_CONF_YAML_ERROR
@ SC_ERR_CONF_YAML_ERROR
Definition: util-error.h:274
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
MimeDecConfig::body_md5
int body_md5
Definition: util-decode-mime.h:98
SMTP_REPLY_235
@ SMTP_REPLY_235
Definition: app-layer-smtp.c:179
SMTP_REPLY_551
@ SMTP_REPLY_551
Definition: app-layer-smtp.c:199
SMTP_DECODER_EVENT_MIME_INVALID_BASE64
@ SMTP_DECODER_EVENT_MIME_INVALID_BASE64
Definition: app-layer-smtp.h:47
FileFlowToFlags
uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction)
Definition: util-file.c:231
DetectEngineThreadCtx_
Definition: detect.h:1010
FLOWFILE_NO_STORE_TS
#define FLOWFILE_NO_STORE_TS
Definition: flow.h:120
SMTP_COMMAND_RSET
#define SMTP_COMMAND_RSET
Definition: app-layer-smtp.c:104
SMTPState_::helo
uint8_t * helo
Definition: app-layer-smtp.h:165
SMTPConfig::decode_mime
int decode_mime
Definition: app-layer-smtp.h:96
ALPROTO_SMTP
@ ALPROTO_SMTP
Definition: app-layer-protos.h:32
STREAM_TOSERVER
#define STREAM_TOSERVER
Definition: stream.h:31
SMTPTransaction_::done
int done
Definition: app-layer-smtp.h:74
alp_tctx
AppLayerParserThreadCtx * alp_tctx
Definition: fuzz_applayerparserparse.c:19
FLOWLOCK_WRLOCK
#define FLOWLOCK_WRLOCK(fb)
Definition: flow.h:261
MimeDecParseState::stack
MimeDecStack * stack
Definition: util-decode-mime.h:189
AppLayerParserRegisterGetFilesFunc
void AppLayerParserRegisterGetFilesFunc(uint8_t ipproto, AppProto alproto, FileContainer *(*StateGetFiles)(void *, uint8_t))
Definition: app-layer-parser.c:425
SCEnter
#define SCEnter(...)
Definition: util-debug.h:300
SMTPTransaction_::tx_data
AppLayerTxData tx_data
Definition: app-layer-smtp.h:72
SMTPState_::parser_state
uint8_t parser_state
Definition: app-layer-smtp.h:143
FileContainer_::head
File * head
Definition: util-file.h:101
SMTP_REPLY_455
@ SMTP_REPLY_455
Definition: app-layer-smtp.c:191
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
SMTPTransaction_::mail_from
uint8_t * mail_from
Definition: app-layer-smtp.h:86
SMTPState_::input
const uint8_t * input
Definition: app-layer-smtp.h:115
FileTrackedSize
uint64_t FileTrackedSize(const File *file)
get the size of the file
Definition: util-file.c:308
AppLayerParserRegisterStateFuncs
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void *, AppProto), void(*StateFree)(void *))
Definition: app-layer-parser.c:398
FILEDATA_CONTENT_INSPECT_MIN_SIZE
#define FILEDATA_CONTENT_INSPECT_MIN_SIZE
Definition: app-layer-smtp.c:63
SMTPState_::curr_tx
SMTPTransaction * curr_tx
Definition: app-layer-smtp.h:108
SMTP_COMMAND_BDAT
#define SMTP_COMMAND_BDAT
Definition: app-layer-smtp.c:96
SMTP_REPLY_211
@ SMTP_REPLY_211
Definition: app-layer-smtp.c:175
SMTP_REPLY_220
@ SMTP_REPLY_220
Definition: app-layer-smtp.c:177
app-layer-parser.h
TRUE
#define TRUE
Definition: suricata-common.h:33
AppLayerDecoderEvents_::cnt
uint8_t cnt
Definition: app-layer-events.h:38
smtp_config
SMTPConfig smtp_config
Definition: app-layer-smtp.c:240
SigMatchSignatures
void SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests