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 SMTPStateGetAlstateProgress(void *vtx, uint8_t direction)
1719 {
1720  SMTPTransaction *tx = vtx;
1721  return tx->done;
1722 }
1723 
1724 static FileContainer *SMTPStateGetFiles(void *state, uint8_t direction)
1725 {
1726  if (state == NULL)
1727  return NULL;
1728 
1729  SMTPState *smtp_state = (SMTPState *)state;
1730 
1731  if (direction & STREAM_TOCLIENT) {
1732  SCReturnPtr(NULL, "FileContainer");
1733  } else {
1734  SCLogDebug("smtp_state->files_ts %p", smtp_state->files_ts);
1735  SCReturnPtr(smtp_state->files_ts, "FileContainer");
1736  }
1737 }
1738 
1739 static void SMTPStateTruncate(void *state, uint8_t direction)
1740 {
1741  FileContainer *fc = SMTPStateGetFiles(state, direction);
1742  if (fc != NULL) {
1743  SCLogDebug("truncating stream, closing files in %s direction (container %p)",
1744  direction & STREAM_TOCLIENT ? "STREAM_TOCLIENT" : "STREAM_TOSERVER", fc);
1746  }
1747 }
1748 
1749 static AppLayerDecoderEvents *SMTPGetEvents(void *tx)
1750 {
1751  SCLogDebug("get SMTP events for TX %p", tx);
1752 
1753  return ((SMTPTransaction *)tx)->decoder_events;
1754 }
1755 
1756 static DetectEngineState *SMTPGetTxDetectState(void *vtx)
1757 {
1758  SMTPTransaction *tx = (SMTPTransaction *)vtx;
1759  return tx->de_state;
1760 }
1761 
1762 static int SMTPSetTxDetectState(void *vtx, DetectEngineState *s)
1763 {
1764  SMTPTransaction *tx = (SMTPTransaction *)vtx;
1765  tx->de_state = s;
1766  return 0;
1767 }
1768 
1769 static AppLayerTxData *SMTPGetTxData(void *vtx)
1770 {
1771  SMTPTransaction *tx = (SMTPTransaction *)vtx;
1772  return &tx->tx_data;
1773 }
1774 
1775 /**
1776  * \brief Register the SMTP Protocol parser.
1777  */
1779 {
1780  const char *proto_name = "smtp";
1781 
1782  if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
1784  if (SMTPRegisterPatternsForProtocolDetection() < 0 )
1785  return;
1786  } else {
1787  SCLogInfo("Protocol detection and parser disabled for %s protocol.",
1788  proto_name);
1789  return;
1790  }
1791 
1792  if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
1793  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree);
1794 
1796  SMTPParseClientRecord);
1798  SMTPParseServerRecord);
1799 
1800  AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo);
1801  AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfoById);
1802  AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetEvents);
1804  SMTPGetTxDetectState, SMTPSetTxDetectState);
1805 
1806  AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc,
1807  SMTPLocalStorageFree);
1808 
1809  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTransactionFree);
1810  AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetFiles);
1811  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress);
1812  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt);
1813  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx);
1814  AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxData);
1816  AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTruncate);
1817  } else {
1818  SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
1819  "still on.", proto_name);
1820  }
1821 
1822  SMTPSetMpmState();
1823 
1824  SMTPConfigure();
1825 
1826 #ifdef UNITTESTS
1828 #endif
1829  return;
1830 }
1831 
1832 /**
1833  * \brief Free memory allocated for global SMTP parser state.
1834  */
1836 {
1837  SMTPFreeMpmState();
1838 }
1839 
1840 /***************************************Unittests******************************/
1841 
1842 #ifdef UNITTESTS
1843 
1844 static void SMTPTestInitConfig(void)
1845 {
1847 
1851 
1853 }
1854 
1855 /*
1856  * \test Test STARTTLS.
1857  */
1858 static int SMTPParserTest01(void)
1859 {
1860  int result = 0;
1861  Flow f;
1862  int r = 0;
1863 
1864  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
1865  uint8_t welcome_reply[] = {
1866  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
1867  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1868  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
1869  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
1870  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
1871  0x0d, 0x0a
1872  };
1873  uint32_t welcome_reply_len = sizeof(welcome_reply);
1874 
1875  /* EHLO [192.168.0.158]<CR><LF> */
1876  uint8_t request1[] = {
1877  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39,
1878  0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e,
1879  0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a
1880  };
1881  uint32_t request1_len = sizeof(request1);
1882  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
1883  * 250-SIZE 35882577<CR><LF>
1884  * 250-8BITMIME<CR><LF>
1885  * 250-STARTTLS<CR><LF>
1886  * 250 ENHANCEDSTATUSCODES<CR><LF>
1887  */
1888  uint8_t reply1[] = {
1889  0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67,
1890  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1891  0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75,
1892  0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
1893  0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e,
1894  0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e,
1895  0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30,
1896  0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35,
1897  0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a,
1898  0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54,
1899  0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35,
1900  0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54,
1901  0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20,
1902  0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44,
1903  0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f,
1904  0x44, 0x45, 0x53, 0x0d, 0x0a
1905  };
1906  uint32_t reply1_len = sizeof(reply1);
1907 
1908  /* STARTTLS<CR><LF> */
1909  uint8_t request2[] = {
1910  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
1911  0x0d, 0x0a
1912  };
1913  uint32_t request2_len = sizeof(request2);
1914  /* 220 2.0.0 Ready to start TLS<CR><LF> */
1915  uint8_t reply2[] = {
1916  0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1917  0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20,
1918  0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74,
1919  0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a
1920  };
1921  uint32_t reply2_len = sizeof(reply2);
1922 
1923  TcpSession ssn;
1925 
1926  memset(&f, 0, sizeof(f));
1927  memset(&ssn, 0, sizeof(ssn));
1928 
1929  FLOW_INITIALIZE(&f);
1930  f.protoctx = (void *)&ssn;
1931  f.proto = IPPROTO_TCP;
1932  f.alproto = ALPROTO_SMTP;
1933 
1935  SMTPTestInitConfig();
1936 
1937  FLOWLOCK_WRLOCK(&f);
1938  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1939  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
1940  if (r != 0) {
1941  printf("smtp check returned %" PRId32 ", expected 0: ", r);
1942  FLOWLOCK_UNLOCK(&f);
1943  goto end;
1944  }
1945  FLOWLOCK_UNLOCK(&f);
1946  SMTPState *smtp_state = f.alstate;
1947  if (smtp_state == NULL) {
1948  printf("no smtp state: ");
1949  goto end;
1950  }
1951  if (smtp_state->input_len != 0 ||
1952  smtp_state->cmds_cnt != 0 ||
1953  smtp_state->cmds_idx != 0 ||
1955  printf("smtp parser in inconsistent state\n");
1956  goto end;
1957  }
1958 
1959  FLOWLOCK_WRLOCK(&f);
1960  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1961  STREAM_TOSERVER, request1, request1_len);
1962  if (r != 0) {
1963  printf("smtp check returned %" PRId32 ", expected 0: ", r);
1964  FLOWLOCK_UNLOCK(&f);
1965  goto end;
1966  }
1967  FLOWLOCK_UNLOCK(&f);
1968  if (smtp_state->input_len != 0 ||
1969  smtp_state->cmds_cnt != 1 ||
1970  smtp_state->cmds_idx != 0 ||
1971  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1973  printf("smtp parser in inconsistent state\n");
1974  goto end;
1975  }
1976 
1977  FLOWLOCK_WRLOCK(&f);
1978  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1979  STREAM_TOCLIENT, reply1, reply1_len);
1980  if (r != 0) {
1981  printf("smtp check returned %" PRId32 ", expected 0: ", r);
1982  FLOWLOCK_UNLOCK(&f);
1983  goto end;
1984  }
1985  FLOWLOCK_UNLOCK(&f);
1986  if (smtp_state->input_len != 0 ||
1987  smtp_state->cmds_cnt != 0 ||
1988  smtp_state->cmds_idx != 0 ||
1990  printf("smtp parser in inconsistent state\n");
1991  goto end;
1992  }
1993 
1994  FLOWLOCK_WRLOCK(&f);
1995  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1996  STREAM_TOSERVER, request2, request2_len);
1997  if (r != 0) {
1998  printf("smtp check returned %" PRId32 ", expected 0: ", r);
1999  FLOWLOCK_UNLOCK(&f);
2000  goto end;
2001  }
2002  FLOWLOCK_UNLOCK(&f);
2003  if (smtp_state->input_len != 0 ||
2004  smtp_state->cmds_cnt != 1 ||
2005  smtp_state->cmds_idx != 0 ||
2006  smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
2008  printf("smtp parser in inconsistent state\n");
2009  goto end;
2010  }
2011 
2012  FLOWLOCK_WRLOCK(&f);
2013  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2014  STREAM_TOCLIENT, reply2, reply2_len);
2015  if (r != 0) {
2016  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2017  FLOWLOCK_UNLOCK(&f);
2018  goto end;
2019  }
2020  FLOWLOCK_UNLOCK(&f);
2021  if (smtp_state->input_len != 0 ||
2022  smtp_state->cmds_cnt != 0 ||
2023  smtp_state->cmds_idx != 0 ||
2026  printf("smtp parser in inconsistent state\n");
2027  goto end;
2028  }
2029 
2030  if (!FlowChangeProto(&f)) {
2031  goto end;
2032  }
2033 
2034  result = 1;
2035 end:
2036  if (alp_tctx != NULL)
2039  FLOW_DESTROY(&f);
2040  return result;
2041 }
2042 
2043 /**
2044  * \test Test multiple DATA commands(full mail transactions).
2045  */
2046 static int SMTPParserTest02(void)
2047 {
2048  int result = 0;
2049  Flow f;
2050  int r = 0;
2051 
2052  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
2053  uint8_t welcome_reply[] = {
2054  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
2055  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
2056  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
2057  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
2058  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
2059  0x0d, 0x0a
2060  };
2061  uint32_t welcome_reply_len = sizeof(welcome_reply);
2062 
2063  /* EHLO boo.com<CR><LF> */
2064  uint8_t request1[] = {
2065  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2066  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2067  };
2068  uint32_t request1_len = sizeof(request1);
2069  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
2070  * 250-SIZE 35882577<CR><LF>
2071  * 250-8BITMIME<CR><LF>
2072  * 250-STARTTLS<CR><LF>
2073  * 250 ENHANCEDSTATUSCODES<CR><LF>
2074  */
2075  uint8_t reply1[] = {
2076  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2077  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2078  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2079  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2080  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2081  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2082  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2083  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2084  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2085  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2086  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2087  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2088  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2089  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2090  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2091  };
2092  uint32_t reply1_len = sizeof(reply1);
2093 
2094  /* MAIL FROM:asdff@asdf.com<CR><LF> */
2095  uint8_t request2[] = {
2096  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2097  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
2098  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2099  0x0d, 0x0a
2100  };
2101  uint32_t request2_len = sizeof(request2);
2102  /* 250 2.1.0 Ok<CR><LF> */
2103  uint8_t reply2[] = {
2104  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2105  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2106  };
2107  uint32_t reply2_len = sizeof(reply2);
2108 
2109  /* RCPT TO:bimbs@gmail.com<CR><LF> */
2110  uint8_t request3[] = {
2111  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2112  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2113  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2114  0x0a
2115  };
2116  uint32_t request3_len = sizeof(request3);
2117  /* 250 2.1.5 Ok<CR><LF> */
2118  uint8_t reply3[] = {
2119  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2120  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2121  };
2122  uint32_t reply3_len = sizeof(reply3);
2123 
2124  /* DATA<CR><LF> */
2125  uint8_t request4[] = {
2126  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2127  };
2128  uint32_t request4_len = sizeof(request4);
2129  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2130  uint8_t reply4[] = {
2131  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2132  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2133  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2134  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2135  0x4c, 0x46, 0x3e, 0x0d, 0x0a
2136  };
2137  uint32_t reply4_len = sizeof(reply4);
2138 
2139  /* FROM:asdff@asdf.com<CR><LF> */
2140  uint8_t request5_1[] = {
2141  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2142  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2143  0x63, 0x6f, 0x6d, 0x0d, 0x0a
2144  };
2145  uint32_t request5_1_len = sizeof(request5_1);
2146  /* TO:bimbs@gmail.com<CR><LF> */
2147  uint8_t request5_2[] = {
2148  0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2149  0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2150  0x6f, 0x6d, 0x0d, 0x0a
2151  };
2152  uint32_t request5_2_len = sizeof(request5_2);
2153  /* <CR><LF> */
2154  uint8_t request5_3[] = {
2155  0x0d, 0x0a
2156  };
2157  uint32_t request5_3_len = sizeof(request5_3);
2158  /* this is test mail1<CR><LF> */
2159  uint8_t request5_4[] = {
2160  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2161  0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2162  0x6c, 0x31, 0x0d, 0x0a
2163  };
2164  uint32_t request5_4_len = sizeof(request5_4);
2165  /* .<CR><LF> */
2166  uint8_t request5_5[] = {
2167  0x2e, 0x0d, 0x0a
2168  };
2169  uint32_t request5_5_len = sizeof(request5_5);
2170  /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
2171  uint8_t reply5[] = {
2172  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2173  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2174  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2175  0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
2176  0x46, 0x32, 0x0d, 0x0a
2177  };
2178  uint32_t reply5_len = sizeof(reply5);
2179 
2180  /* MAIL FROM:asdfg@asdf.com<CR><LF> */
2181  uint8_t request6[] = {
2182  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2183  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40,
2184  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2185  0x0d, 0x0a
2186  };
2187  uint32_t request6_len = sizeof(request6);
2188  /* 250 2.1.0 Ok<CR><LF> */
2189  uint8_t reply6[] = {
2190  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2191  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2192  };
2193  uint32_t reply6_len = sizeof(reply6);
2194 
2195  /* RCPT TO:bimbs@gmail.com<CR><LF> */
2196  uint8_t request7[] = {
2197  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2198  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2199  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2200  0x0a
2201  };
2202  uint32_t request7_len = sizeof(request7);
2203  /* 250 2.1.5 Ok<CR><LF> */
2204  uint8_t reply7[] = {
2205  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2206  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2207  };
2208  uint32_t reply7_len = sizeof(reply7);
2209 
2210  /* DATA<CR><LF> */
2211  uint8_t request8[] = {
2212  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2213  };
2214  uint32_t request8_len = sizeof(request8);
2215  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2216  uint8_t reply8[] = {
2217  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2218  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2219  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2220  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2221  0x4c, 0x46, 0x3e, 0x0d, 0x0a
2222  };
2223  uint32_t reply8_len = sizeof(reply8);
2224 
2225  /* FROM:asdfg@gmail.com<CR><LF> */
2226  uint8_t request9_1[] = {
2227  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2228  0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
2229  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2230  };
2231  uint32_t request9_1_len = sizeof(request9_1);
2232  /* TO:bimbs@gmail.com<CR><LF> */
2233  uint8_t request9_2[] = {
2234  0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2235  0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2236  0x6f, 0x6d, 0x0d, 0x0a
2237  };
2238  uint32_t request9_2_len = sizeof(request9_2);
2239  /* <CR><LF> */
2240  uint8_t request9_3[] = {
2241  0x0d, 0x0a
2242  };
2243  uint32_t request9_3_len = sizeof(request9_3);
2244  /* this is test mail2<CR><LF> */
2245  uint8_t request9_4[] = {
2246  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2247  0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2248  0x6c, 0x32, 0x0d, 0x0a
2249  };
2250  uint32_t request9_4_len = sizeof(request9_4);
2251  /* .<CR><LF> */
2252  uint8_t request9_5[] = {
2253  0x2e, 0x0d, 0x0a
2254  };
2255  uint32_t request9_5_len = sizeof(request9_5);
2256  /* 250 2.0.0 Ok: queued as 28CFF20BF2<CR><LF> */
2257  uint8_t reply9[] = {
2258  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2259  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2260  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2261  0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42,
2262  0x46, 0x32, 0x0d, 0x0a
2263  };
2264  uint32_t reply9_len = sizeof(reply9);
2265 
2266  /* QUIT<CR><LF> */
2267  uint8_t request10[] = {
2268  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
2269  };
2270  uint32_t request10_len = sizeof(request10);
2271  /* 221 2.0.0 Bye<CR><LF> */
2272  uint8_t reply10[] = {
2273  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2274  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
2275  };
2276  uint32_t reply10_len = sizeof(reply10);
2277 
2278  TcpSession ssn;
2280 
2281  memset(&f, 0, sizeof(f));
2282  memset(&ssn, 0, sizeof(ssn));
2283 
2284  FLOW_INITIALIZE(&f);
2285  f.protoctx = (void *)&ssn;
2286  f.proto = IPPROTO_TCP;
2287  f.alproto = ALPROTO_SMTP;
2288 
2290  SMTPTestInitConfig();
2291 
2292  FLOWLOCK_WRLOCK(&f);
2293  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2294  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2295  if (r != 0) {
2296  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2297  FLOWLOCK_UNLOCK(&f);
2298  goto end;
2299  }
2300  FLOWLOCK_UNLOCK(&f);
2301  SMTPState *smtp_state = f.alstate;
2302  if (smtp_state == NULL) {
2303  printf("no smtp state: ");
2304  goto end;
2305  }
2306  if (smtp_state->input_len != 0 ||
2307  smtp_state->cmds_cnt != 0 ||
2308  smtp_state->cmds_idx != 0 ||
2310  printf("smtp parser in inconsistent state\n");
2311  goto end;
2312  }
2313 
2314  FLOWLOCK_WRLOCK(&f);
2315  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2316  STREAM_TOSERVER, request1, request1_len);
2317  if (r != 0) {
2318  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2319  FLOWLOCK_UNLOCK(&f);
2320  goto end;
2321  }
2322  FLOWLOCK_UNLOCK(&f);
2323  if (smtp_state->input_len != 0 ||
2324  smtp_state->cmds_cnt != 1 ||
2325  smtp_state->cmds_idx != 0 ||
2326  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2328  printf("smtp parser in inconsistent state\n");
2329  goto end;
2330  }
2331 
2332  FLOWLOCK_WRLOCK(&f);
2333  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2334  STREAM_TOCLIENT, reply1, reply1_len);
2335  if (r != 0) {
2336  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2337  FLOWLOCK_UNLOCK(&f);
2338  goto end;
2339  }
2340  FLOWLOCK_UNLOCK(&f);
2341  if (smtp_state->input_len != 0 ||
2342  smtp_state->cmds_cnt != 0 ||
2343  smtp_state->cmds_idx != 0 ||
2345  printf("smtp parser in inconsistent state\n");
2346  goto end;
2347  }
2348 
2349  FLOWLOCK_WRLOCK(&f);
2350  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2351  STREAM_TOSERVER, request2, request2_len);
2352  if (r != 0) {
2353  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2354  FLOWLOCK_UNLOCK(&f);
2355  goto end;
2356  }
2357  FLOWLOCK_UNLOCK(&f);
2358  if (smtp_state->input_len != 0 ||
2359  smtp_state->cmds_cnt != 1 ||
2360  smtp_state->cmds_idx != 0 ||
2361  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2363  printf("smtp parser in inconsistent state\n");
2364  goto end;
2365  }
2366 
2367  FLOWLOCK_WRLOCK(&f);
2368  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2369  STREAM_TOCLIENT, reply2, reply2_len);
2370  if (r != 0) {
2371  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2372  FLOWLOCK_UNLOCK(&f);
2373  goto end;
2374  }
2375  FLOWLOCK_UNLOCK(&f);
2376  if (smtp_state->input_len != 0 ||
2377  smtp_state->cmds_cnt != 0 ||
2378  smtp_state->cmds_idx != 0 ||
2380  printf("smtp parser in inconsistent state\n");
2381  goto end;
2382  }
2383 
2384  FLOWLOCK_WRLOCK(&f);
2385  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2386  STREAM_TOSERVER, request3, request3_len);
2387  if (r != 0) {
2388  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2389  FLOWLOCK_UNLOCK(&f);
2390  goto end;
2391  }
2392  FLOWLOCK_UNLOCK(&f);
2393  if (smtp_state->input_len != 0 ||
2394  smtp_state->cmds_cnt != 1 ||
2395  smtp_state->cmds_idx != 0 ||
2396  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2398  printf("smtp parser in inconsistent state\n");
2399  goto end;
2400  }
2401 
2402  FLOWLOCK_WRLOCK(&f);
2403  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2404  STREAM_TOCLIENT, reply3, reply3_len);
2405  if (r != 0) {
2406  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2407  FLOWLOCK_UNLOCK(&f);
2408  goto end;
2409  }
2410  FLOWLOCK_UNLOCK(&f);
2411  if (smtp_state->input_len != 0 ||
2412  smtp_state->cmds_cnt != 0 ||
2413  smtp_state->cmds_idx != 0 ||
2415  printf("smtp parser in inconsistent state\n");
2416  goto end;
2417  }
2418 
2419  FLOWLOCK_WRLOCK(&f);
2420  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2421  STREAM_TOSERVER, request4, request4_len);
2422  if (r != 0) {
2423  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2424  FLOWLOCK_UNLOCK(&f);
2425  goto end;
2426  }
2427  FLOWLOCK_UNLOCK(&f);
2428  if (smtp_state->input_len != 0 ||
2429  smtp_state->cmds_cnt != 1 ||
2430  smtp_state->cmds_idx != 0 ||
2431  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2433  printf("smtp parser in inconsistent state\n");
2434  goto end;
2435  }
2436 
2437  FLOWLOCK_WRLOCK(&f);
2438  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2439  STREAM_TOCLIENT, reply4, reply4_len);
2440  if (r != 0) {
2441  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2442  FLOWLOCK_UNLOCK(&f);
2443  goto end;
2444  }
2445  FLOWLOCK_UNLOCK(&f);
2446  if (smtp_state->input_len != 0 ||
2447  smtp_state->cmds_cnt != 0 ||
2448  smtp_state->cmds_idx != 0 ||
2451  printf("smtp parser in inconsistent state\n");
2452  goto end;
2453  }
2454 
2455  FLOWLOCK_WRLOCK(&f);
2456  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2457  STREAM_TOSERVER, request5_1, request5_1_len);
2458  if (r != 0) {
2459  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2460  FLOWLOCK_UNLOCK(&f);
2461  goto end;
2462  }
2463  FLOWLOCK_UNLOCK(&f);
2464  if (smtp_state->input_len != 0 ||
2465  smtp_state->cmds_cnt != 0 ||
2466  smtp_state->cmds_idx != 0 ||
2469 
2470  printf("smtp parser in inconsistent state\n");
2471  goto end;
2472  }
2473 
2474  FLOWLOCK_WRLOCK(&f);
2475  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2476  STREAM_TOSERVER, request5_2, request5_2_len);
2477  if (r != 0) {
2478  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2479  FLOWLOCK_UNLOCK(&f);
2480  goto end;
2481  }
2482  FLOWLOCK_UNLOCK(&f);
2483  if (smtp_state->input_len != 0 ||
2484  smtp_state->cmds_cnt != 0 ||
2485  smtp_state->cmds_idx != 0 ||
2488 
2489  printf("smtp parser in inconsistent state\n");
2490  goto end;
2491  }
2492 
2493  FLOWLOCK_WRLOCK(&f);
2494  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2495  STREAM_TOSERVER, request5_3, request5_3_len);
2496  if (r != 0) {
2497  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2498  FLOWLOCK_UNLOCK(&f);
2499  goto end;
2500  }
2501  FLOWLOCK_UNLOCK(&f);
2502  if (smtp_state->input_len != 0 ||
2503  smtp_state->cmds_cnt != 0 ||
2504  smtp_state->cmds_idx != 0 ||
2507 
2508  printf("smtp parser in inconsistent state\n");
2509  goto end;
2510  }
2511 
2512  FLOWLOCK_WRLOCK(&f);
2513  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2514  STREAM_TOSERVER, request5_4, request5_4_len);
2515  if (r != 0) {
2516  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2517  FLOWLOCK_UNLOCK(&f);
2518  goto end;
2519  }
2520  FLOWLOCK_UNLOCK(&f);
2521  if (smtp_state->input_len != 0 ||
2522  smtp_state->cmds_cnt != 0 ||
2523  smtp_state->cmds_idx != 0 ||
2526 
2527  printf("smtp parser in inconsistent state\n");
2528  goto end;
2529  }
2530 
2531  FLOWLOCK_WRLOCK(&f);
2532  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2533  STREAM_TOSERVER, request5_5, request5_5_len);
2534  if (r != 0) {
2535  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2536  FLOWLOCK_UNLOCK(&f);
2537  goto end;
2538  }
2539  FLOWLOCK_UNLOCK(&f);
2540  if (smtp_state->input_len != 0 ||
2541  smtp_state->cmds_cnt != 1 ||
2542  smtp_state->cmds_idx != 0 ||
2543  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2545  printf("smtp parser in inconsistent state\n");
2546  goto end;
2547  }
2548 
2549  FLOWLOCK_WRLOCK(&f);
2550  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2551  STREAM_TOCLIENT, reply5, reply5_len);
2552  if (r != 0) {
2553  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2554  FLOWLOCK_UNLOCK(&f);
2555  goto end;
2556  }
2557  FLOWLOCK_UNLOCK(&f);
2558  if (smtp_state->input_len != 0 ||
2559  smtp_state->cmds_cnt != 0 ||
2560  smtp_state->cmds_idx != 0 ||
2562  printf("smtp parser in inconsistent state\n");
2563  goto end;
2564  }
2565 
2566  FLOWLOCK_WRLOCK(&f);
2567  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2568  STREAM_TOSERVER, request6, request6_len);
2569  if (r != 0) {
2570  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2571  FLOWLOCK_UNLOCK(&f);
2572  goto end;
2573  }
2574  FLOWLOCK_UNLOCK(&f);
2575  if (smtp_state->input_len != 0 ||
2576  smtp_state->cmds_cnt != 1 ||
2577  smtp_state->cmds_idx != 0 ||
2578  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2580  printf("smtp parser in inconsistent state\n");
2581  goto end;
2582  }
2583 
2584  FLOWLOCK_WRLOCK(&f);
2585  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2586  STREAM_TOCLIENT, reply6, reply6_len);
2587  if (r != 0) {
2588  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2589  FLOWLOCK_UNLOCK(&f);
2590  goto end;
2591  }
2592  FLOWLOCK_UNLOCK(&f);
2593  if (smtp_state->input_len != 0 ||
2594  smtp_state->cmds_cnt != 0 ||
2595  smtp_state->cmds_idx != 0 ||
2597  printf("smtp parser in inconsistent state\n");
2598  goto end;
2599  }
2600 
2601  FLOWLOCK_WRLOCK(&f);
2602  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2603  STREAM_TOSERVER, request7, request7_len);
2604  if (r != 0) {
2605  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2606  FLOWLOCK_UNLOCK(&f);
2607  goto end;
2608  }
2609  FLOWLOCK_UNLOCK(&f);
2610  if (smtp_state->input_len != 0 ||
2611  smtp_state->cmds_cnt != 1 ||
2612  smtp_state->cmds_idx != 0 ||
2613  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2615  printf("smtp parser in inconsistent state\n");
2616  goto end;
2617  }
2618 
2619  FLOWLOCK_WRLOCK(&f);
2620  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2621  STREAM_TOCLIENT, reply7, reply7_len);
2622  if (r != 0) {
2623  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2624  FLOWLOCK_UNLOCK(&f);
2625  goto end;
2626  }
2627  FLOWLOCK_UNLOCK(&f);
2628  if (smtp_state->input_len != 0 ||
2629  smtp_state->cmds_cnt != 0 ||
2630  smtp_state->cmds_idx != 0 ||
2632  printf("smtp parser in inconsistent state\n");
2633  goto end;
2634  }
2635 
2636  FLOWLOCK_WRLOCK(&f);
2637  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2638  STREAM_TOSERVER, request8, request8_len);
2639  if (r != 0) {
2640  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2641  FLOWLOCK_UNLOCK(&f);
2642  goto end;
2643  }
2644  FLOWLOCK_UNLOCK(&f);
2645  if (smtp_state->input_len != 0 ||
2646  smtp_state->cmds_cnt != 1 ||
2647  smtp_state->cmds_idx != 0 ||
2648  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2650  printf("smtp parser in inconsistent state\n");
2651  goto end;
2652  }
2653 
2654  FLOWLOCK_WRLOCK(&f);
2655  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2656  STREAM_TOCLIENT, reply8, reply8_len);
2657  if (r != 0) {
2658  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2659  FLOWLOCK_UNLOCK(&f);
2660  goto end;
2661  }
2662  FLOWLOCK_UNLOCK(&f);
2663  if (smtp_state->input_len != 0 ||
2664  smtp_state->cmds_cnt != 0 ||
2665  smtp_state->cmds_idx != 0 ||
2668  printf("smtp parser in inconsistent state\n");
2669  goto end;
2670  }
2671 
2672  FLOWLOCK_WRLOCK(&f);
2673  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2674  STREAM_TOSERVER, request9_1, request9_1_len);
2675  if (r != 0) {
2676  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2677  FLOWLOCK_UNLOCK(&f);
2678  goto end;
2679  }
2680  FLOWLOCK_UNLOCK(&f);
2681  if (smtp_state->input_len != 0 ||
2682  smtp_state->cmds_cnt != 0 ||
2683  smtp_state->cmds_idx != 0 ||
2686 
2687  printf("smtp parser in inconsistent state\n");
2688  goto end;
2689  }
2690 
2691  FLOWLOCK_WRLOCK(&f);
2692  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2693  STREAM_TOSERVER, request9_2, request9_2_len);
2694  if (r != 0) {
2695  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2696  FLOWLOCK_UNLOCK(&f);
2697  goto end;
2698  }
2699  FLOWLOCK_UNLOCK(&f);
2700  if (smtp_state->input_len != 0 ||
2701  smtp_state->cmds_cnt != 0 ||
2702  smtp_state->cmds_idx != 0 ||
2705 
2706  printf("smtp parser in inconsistent state\n");
2707  goto end;
2708  }
2709 
2710  FLOWLOCK_WRLOCK(&f);
2711  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2712  STREAM_TOSERVER, request9_3, request9_3_len);
2713  if (r != 0) {
2714  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2715  FLOWLOCK_UNLOCK(&f);
2716  goto end;
2717  }
2718  FLOWLOCK_UNLOCK(&f);
2719  if (smtp_state->input_len != 0 ||
2720  smtp_state->cmds_cnt != 0 ||
2721  smtp_state->cmds_idx != 0 ||
2724 
2725  printf("smtp parser in inconsistent state\n");
2726  goto end;
2727  }
2728 
2729  FLOWLOCK_WRLOCK(&f);
2730  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2731  STREAM_TOSERVER, request9_4, request9_4_len);
2732  if (r != 0) {
2733  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2734  FLOWLOCK_UNLOCK(&f);
2735  goto end;
2736  }
2737  FLOWLOCK_UNLOCK(&f);
2738  if (smtp_state->input_len != 0 ||
2739  smtp_state->cmds_cnt != 0 ||
2740  smtp_state->cmds_idx != 0 ||
2743 
2744  printf("smtp parser in inconsistent state\n");
2745  goto end;
2746  }
2747 
2748  FLOWLOCK_WRLOCK(&f);
2749  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2750  STREAM_TOSERVER, request9_5, request9_5_len);
2751  if (r != 0) {
2752  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2753  FLOWLOCK_UNLOCK(&f);
2754  goto end;
2755  }
2756  FLOWLOCK_UNLOCK(&f);
2757  if (smtp_state->input_len != 0 ||
2758  smtp_state->cmds_cnt != 1 ||
2759  smtp_state->cmds_idx != 0 ||
2760  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2762  printf("smtp parser in inconsistent state\n");
2763  goto end;
2764  }
2765 
2766  FLOWLOCK_WRLOCK(&f);
2767  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2768  STREAM_TOCLIENT, reply9, reply9_len);
2769  if (r != 0) {
2770  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2771  FLOWLOCK_UNLOCK(&f);
2772  goto end;
2773  }
2774  FLOWLOCK_UNLOCK(&f);
2775  if (smtp_state->input_len != 0 ||
2776  smtp_state->cmds_cnt != 0 ||
2777  smtp_state->cmds_idx != 0 ||
2779  printf("smtp parser in inconsistent state\n");
2780  goto end;
2781  }
2782 
2783  FLOWLOCK_WRLOCK(&f);
2784  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2785  STREAM_TOSERVER, request10, request10_len);
2786  if (r != 0) {
2787  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2788  FLOWLOCK_UNLOCK(&f);
2789  goto end;
2790  }
2791  FLOWLOCK_UNLOCK(&f);
2792  if (smtp_state->input_len != 0 ||
2793  smtp_state->cmds_cnt != 1 ||
2794  smtp_state->cmds_idx != 0 ||
2795  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2797  printf("smtp parser in inconsistent state\n");
2798  goto end;
2799  }
2800 
2801  FLOWLOCK_WRLOCK(&f);
2802  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2803  STREAM_TOCLIENT, reply10, reply10_len);
2804  if (r != 0) {
2805  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2806  FLOWLOCK_UNLOCK(&f);
2807  goto end;
2808  }
2809  FLOWLOCK_UNLOCK(&f);
2810  if (smtp_state->input_len != 0 ||
2811  smtp_state->cmds_cnt != 0 ||
2812  smtp_state->cmds_idx != 0 ||
2814  printf("smtp parser in inconsistent state\n");
2815  goto end;
2816  }
2817 
2818  result = 1;
2819 end:
2820  if (alp_tctx != NULL)
2823  FLOW_DESTROY(&f);
2824  return result;
2825 }
2826 
2827 /**
2828  * \test Testing parsing pipelined commands.
2829  */
2830 static int SMTPParserTest03(void)
2831 {
2832  int result = 0;
2833  Flow f;
2834  int r = 0;
2835 
2836  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2837  uint8_t welcome_reply[] = {
2838  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2839  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2840  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2841  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2842  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2843  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2844  };
2845  uint32_t welcome_reply_len = sizeof(welcome_reply);
2846 
2847  /* EHLO boo.com<CR><LF> */
2848  uint8_t request1[] = {
2849  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2850  0x2e, 0x63, 0x6f, 0x6d, 0x0a
2851  };
2852  uint32_t request1_len = sizeof(request1);
2853  /* 250-poona_slack_vm1.localdomain<CR><LF>
2854  * 250-PIPELINING<CR><LF>
2855  * 250-SIZE 10240000<CR><LF>
2856  * 250-VRFY<CR><LF>
2857  * 250-ETRN<CR><LF>
2858  * 250-ENHANCEDSTATUSCODES<CR><LF>
2859  * 250-8BITMIME<CR><LF>
2860  * 250 DSN<CR><LF>
2861  */
2862  uint8_t reply1[] = {
2863  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2864  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2865  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2866  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2867  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
2868  0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
2869  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2870  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2871  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2872  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2873  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2874  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2875  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2876  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2877  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2878  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2879  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2880  };
2881  uint32_t reply1_len = sizeof(reply1);
2882 
2883  /* MAIL FROM:pbsf@asdfs.com<CR><LF>
2884  * RCPT TO:pbsf@asdfs.com<CR><LF>
2885  * DATA<CR><LF>
2886  * Immediate data
2887  */
2888  uint8_t request2[] = {
2889  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2890  0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2891  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2892  0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
2893  0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2894  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2895  0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
2896  0x49, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74,
2897  0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0d, 0x0a,
2898  };
2899  uint32_t request2_len = sizeof(request2);
2900  /* 250 2.1.0 Ok<CR><LF>
2901  * 250 2.1.5 Ok<CR><LF>
2902  * 354 End data with <CR><LF>.<CR><LF>|<CR><LF>|
2903  */
2904  uint8_t reply2[] = {
2905  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2906  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35,
2907  0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20,
2908  0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20,
2909  0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61,
2910  0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43,
2911  0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c,
2912  0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d,
2913  0x0a
2914  };
2915  uint32_t reply2_len = sizeof(reply2);
2916 
2917  TcpSession ssn;
2919 
2920  memset(&f, 0, sizeof(f));
2921  memset(&ssn, 0, sizeof(ssn));
2922 
2923  FLOW_INITIALIZE(&f);
2924  f.protoctx = (void *)&ssn;
2925  f.proto = IPPROTO_TCP;
2926  f.alproto = ALPROTO_SMTP;
2927 
2929  SMTPTestInitConfig();
2930 
2931  FLOWLOCK_WRLOCK(&f);
2932  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2933  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2934  if (r != 0) {
2935  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2936  FLOWLOCK_UNLOCK(&f);
2937  goto end;
2938  }
2939  FLOWLOCK_UNLOCK(&f);
2940  SMTPState *smtp_state = f.alstate;
2941  if (smtp_state == NULL) {
2942  printf("no smtp state: ");
2943  goto end;
2944  }
2945  if (smtp_state->input_len != 0 ||
2946  smtp_state->cmds_cnt != 0 ||
2947  smtp_state->cmds_idx != 0 ||
2949  printf("smtp parser in inconsistent state\n");
2950  goto end;
2951  }
2952 
2953  FLOWLOCK_WRLOCK(&f);
2954  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2955  STREAM_TOSERVER, request1, request1_len);
2956  if (r != 0) {
2957  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2958  FLOWLOCK_UNLOCK(&f);
2959  goto end;
2960  }
2961  FLOWLOCK_UNLOCK(&f);
2962  if (smtp_state->input_len != 0 ||
2963  smtp_state->cmds_cnt != 1 ||
2964  smtp_state->cmds_idx != 0 ||
2965  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2967  printf("smtp parser in inconsistent state\n");
2968  goto end;
2969  }
2970 
2971  FLOWLOCK_WRLOCK(&f);
2972  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2973  STREAM_TOCLIENT, reply1, reply1_len);
2974  if (r != 0) {
2975  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2976  FLOWLOCK_UNLOCK(&f);
2977  goto end;
2978  }
2979  FLOWLOCK_UNLOCK(&f);
2980  if (smtp_state->input_len != 0 ||
2981  smtp_state->cmds_cnt != 0 ||
2982  smtp_state->cmds_idx != 0 ||
2985  printf("smtp parser in inconsistent state\n");
2986  goto end;
2987  }
2988 
2989  FLOWLOCK_WRLOCK(&f);
2990  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2991  STREAM_TOSERVER, request2, request2_len);
2992  if (r != 0) {
2993  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2994  FLOWLOCK_UNLOCK(&f);
2995  goto end;
2996  }
2997  FLOWLOCK_UNLOCK(&f);
2998  if (smtp_state->input_len != 0 ||
2999  smtp_state->cmds_cnt != 3 ||
3000  smtp_state->cmds_idx != 0 ||
3001  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3002  smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD ||
3003  smtp_state->cmds[2] != SMTP_COMMAND_DATA ||
3007  printf("smtp parser in inconsistent state\n");
3008  goto end;
3009  }
3010 
3011  FLOWLOCK_WRLOCK(&f);
3012  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3013  STREAM_TOCLIENT, reply2, reply2_len);
3014  if (r != 0) {
3015  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3016  FLOWLOCK_UNLOCK(&f);
3017  goto end;
3018  }
3019  FLOWLOCK_UNLOCK(&f);
3020  if (smtp_state->input_len != 0 ||
3021  smtp_state->cmds_cnt != 0 ||
3022  smtp_state->cmds_idx != 0 ||
3026  printf("smtp parser in inconsistent state\n");
3027  goto end;
3028  }
3029 
3030  result = 1;
3031 end:
3032  if (alp_tctx != NULL)
3035  FLOW_DESTROY(&f);
3036  return result;
3037 }
3038 
3039 /*
3040  * \test Test smtp with just <LF> delimiter instead of <CR><LF>.
3041  */
3042 static int SMTPParserTest04(void)
3043 {
3044  int result = 0;
3045  Flow f;
3046  int r = 0;
3047 
3048  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
3049  uint8_t welcome_reply[] = {
3050  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3051  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3052  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3053  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3054  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3055  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3056  };
3057  uint32_t welcome_reply_len = sizeof(welcome_reply);
3058 
3059  /* EHLO boo.com<CR><LF> */
3060  uint8_t request1[] = {
3061  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3062  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3063  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3064  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3065  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3066  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3067  };
3068  uint32_t request1_len = sizeof(request1);
3069 
3070  TcpSession ssn;
3072 
3073  memset(&f, 0, sizeof(f));
3074  memset(&ssn, 0, sizeof(ssn));
3075 
3076  FLOW_INITIALIZE(&f);
3077  f.protoctx = (void *)&ssn;
3078  f.proto = IPPROTO_TCP;
3079  f.alproto = ALPROTO_SMTP;
3080 
3082  SMTPTestInitConfig();
3083 
3084  FLOWLOCK_WRLOCK(&f);
3085  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3086  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3087  if (r != 0) {
3088  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3089  FLOWLOCK_UNLOCK(&f);
3090  goto end;
3091  }
3092  FLOWLOCK_UNLOCK(&f);
3093  SMTPState *smtp_state = f.alstate;
3094  if (smtp_state == NULL) {
3095  printf("no smtp state: ");
3096  goto end;
3097  }
3098  if (smtp_state->input_len != 0 ||
3099  smtp_state->cmds_cnt != 0 ||
3100  smtp_state->cmds_idx != 0 ||
3102  printf("smtp parser in inconsistent state\n");
3103  goto end;
3104  }
3105 
3106  FLOWLOCK_WRLOCK(&f);
3107  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3108  STREAM_TOSERVER, request1, request1_len);
3109  if (r != 0) {
3110  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3111  FLOWLOCK_UNLOCK(&f);
3112  goto end;
3113  }
3114  FLOWLOCK_UNLOCK(&f);
3115  if (smtp_state->input_len != 0 ||
3116  smtp_state->cmds_cnt != 1 ||
3117  smtp_state->cmds_idx != 0 ||
3118  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3120  printf("smtp parser in inconsistent state\n");
3121  goto end;
3122  }
3123 
3124  result = 1;
3125 end:
3126  if (alp_tctx != NULL)
3129  FLOW_DESTROY(&f);
3130  return result;
3131 }
3132 
3133 /*
3134  * \test Test STARTTLS fail.
3135  */
3136 static int SMTPParserTest05(void)
3137 {
3138  int result = 0;
3139  Flow f;
3140  int r = 0;
3141 
3142  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
3143  uint8_t welcome_reply[] = {
3144  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3145  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3146  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3147  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3148  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3149  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3150  };
3151  uint32_t welcome_reply_len = sizeof(welcome_reply);
3152 
3153  /* EHLO boo.com<CR><LF> */
3154  uint8_t request1[] = {
3155  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3156  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
3157  };
3158  uint32_t request1_len = sizeof(request1);
3159  /* 250-poona_slack_vm1.localdomain<CR><LF>
3160  * 250-PIPELINING<CR><LF>
3161  * 250-SIZE 10240000<CR><LF>
3162  * 250-VRFY<CR><LF>
3163  * 250-ETRN<CR><LF>
3164  * 250-ENHANCEDSTATUSCODES<CR><LF>
3165  * 250-8BITMIME<CR><LF>
3166  * 250 DSN<CR><LF>
3167  */
3168  uint8_t reply1[] = {
3169  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
3170  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3171  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3172  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
3173  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
3174  0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
3175  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
3176  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
3177  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3178  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
3179  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
3180  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
3181  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
3182  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
3183  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
3184  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
3185  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
3186  };
3187  uint32_t reply1_len = sizeof(reply1);
3188 
3189  /* STARTTLS<CR><LF> */
3190  uint8_t request2[] = {
3191  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
3192  0x0d, 0x0a
3193  };
3194  uint32_t request2_len = sizeof(request2);
3195  /* 502 5.5.2 Error: command not recognized<CR><LF> */
3196  uint8_t reply2[] = {
3197  0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e,
3198  0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a,
3199  0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
3200  0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63,
3201  0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d,
3202  0x0a
3203  };
3204  uint32_t reply2_len = sizeof(reply2);
3205 
3206  /* QUIT<CR><LF> */
3207  uint8_t request3[] = {
3208  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
3209 
3210  };
3211  uint32_t request3_len = sizeof(request3);
3212  /* 221 2.0.0 Bye<CR><LF> */
3213  uint8_t reply3[] = {
3214  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
3215  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
3216  };
3217  uint32_t reply3_len = sizeof(reply3);
3218 
3219  TcpSession ssn;
3221 
3222  memset(&f, 0, sizeof(f));
3223  memset(&ssn, 0, sizeof(ssn));
3224 
3225  FLOW_INITIALIZE(&f);
3226  f.protoctx = (void *)&ssn;
3227  f.proto = IPPROTO_TCP;
3228  f.alproto = ALPROTO_SMTP;
3229 
3231  SMTPTestInitConfig();
3232 
3233  FLOWLOCK_WRLOCK(&f);
3234  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3235  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3236  if (r != 0) {
3237  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3238  FLOWLOCK_UNLOCK(&f);
3239  goto end;
3240  }
3241  FLOWLOCK_UNLOCK(&f);
3242  SMTPState *smtp_state = f.alstate;
3243  if (smtp_state == NULL) {
3244  printf("no smtp state: ");
3245  goto end;
3246  }
3247  if (smtp_state->input_len != 0 ||
3248  smtp_state->cmds_cnt != 0 ||
3249  smtp_state->cmds_idx != 0 ||
3251  printf("smtp parser in inconsistent state\n");
3252  goto end;
3253  }
3254 
3255  FLOWLOCK_WRLOCK(&f);
3256  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3257  STREAM_TOSERVER, request1, request1_len);
3258  if (r != 0) {
3259  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3260  FLOWLOCK_UNLOCK(&f);
3261  goto end;
3262  }
3263  FLOWLOCK_UNLOCK(&f);
3264  if (smtp_state->input_len != 0 ||
3265  smtp_state->cmds_cnt != 1 ||
3266  smtp_state->cmds_idx != 0 ||
3267  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3269  printf("smtp parser in inconsistent state\n");
3270  goto end;
3271  }
3272 
3273  FLOWLOCK_WRLOCK(&f);
3274  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3275  STREAM_TOCLIENT, reply1, reply1_len);
3276  if (r != 0) {
3277  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3278  FLOWLOCK_UNLOCK(&f);
3279  goto end;
3280  }
3281  FLOWLOCK_UNLOCK(&f);
3282  if (smtp_state->input_len != 0 ||
3283  smtp_state->cmds_cnt != 0 ||
3284  smtp_state->cmds_idx != 0 ||
3287  printf("smtp parser in inconsistent state\n");
3288  goto end;
3289  }
3290 
3291  FLOWLOCK_WRLOCK(&f);
3292  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3293  STREAM_TOSERVER, request2, request2_len);
3294  if (r != 0) {
3295  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3296  FLOWLOCK_UNLOCK(&f);
3297  goto end;
3298  }
3299  FLOWLOCK_UNLOCK(&f);
3300  if (smtp_state->input_len != 0 ||
3301  smtp_state->cmds_cnt != 1 ||
3302  smtp_state->cmds_idx != 0 ||
3303  smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
3306  printf("smtp parser in inconsistent state\n");
3307  goto end;
3308  }
3309 
3310  FLOWLOCK_WRLOCK(&f);
3311  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3312  STREAM_TOCLIENT, reply2, reply2_len);
3313  if (r != 0) {
3314  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3315  FLOWLOCK_UNLOCK(&f);
3316  goto end;
3317  }
3318  FLOWLOCK_UNLOCK(&f);
3319  if (smtp_state->input_len != 0 ||
3320  smtp_state->cmds_cnt != 0 ||
3321  smtp_state->cmds_idx != 0 ||
3324  printf("smtp parser in inconsistent state\n");
3325  goto end;
3326  }
3327 
3328  if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
3330  (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
3331  (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
3332  goto end;
3333  }
3334 
3335  FLOWLOCK_WRLOCK(&f);
3336  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3337  STREAM_TOSERVER, request3, request3_len);
3338  if (r != 0) {
3339  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3340  FLOWLOCK_UNLOCK(&f);
3341  goto end;
3342  }
3343  FLOWLOCK_UNLOCK(&f);
3344  if (smtp_state->input_len != 0 ||
3345  smtp_state->cmds_cnt != 1 ||
3346  smtp_state->cmds_idx != 0 ||
3347  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3350  printf("smtp parser in inconsistent state\n");
3351  goto end;
3352  }
3353 
3354  FLOWLOCK_WRLOCK(&f);
3355  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3356  STREAM_TOCLIENT, reply3, reply3_len);
3357  if (r != 0) {
3358  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3359  FLOWLOCK_UNLOCK(&f);
3360  goto end;
3361  }
3362  FLOWLOCK_UNLOCK(&f);
3363  if (smtp_state->input_len != 0 ||
3364  smtp_state->cmds_cnt != 0 ||
3365  smtp_state->cmds_idx != 0 ||
3368  printf("smtp parser in inconsistent state\n");
3369  goto end;
3370  }
3371 
3372  result = 1;
3373 end:
3374  if (alp_tctx != NULL)
3377  FLOW_DESTROY(&f);
3378  return result;
3379 }
3380 
3381 /**
3382  * \test Test multiple DATA commands(full mail transactions).
3383  */
3384 static int SMTPParserTest06(void)
3385 {
3386  int result = 0;
3387  Flow f;
3388  int r = 0;
3389 
3390  uint8_t welcome_reply[] = {
3391  0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30,
3392  0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3393  0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3394  0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3395  0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e,
3396  0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69,
3397  0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f,
3398  0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c,
3399  0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b,
3400  0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20,
3401  0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f,
3402  0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63,
3403  0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20,
3404  0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
3405  0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69,
3406  0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f,
3407  0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73,
3408  0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e,
3409  0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f,
3410  0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68,
3411  0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72,
3412  0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73,
3413  0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e,
3414  0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f,
3415  0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74,
3416  0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c,
3417  0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
3418  0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20,
3419  0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70,
3420  0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63,
3421  0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
3422  0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
3423  0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f,
3424  0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61,
3425  0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69,
3426  0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62,
3427  0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35,
3428  0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d,
3429  0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a
3430  };
3431  uint32_t welcome_reply_len = sizeof(welcome_reply);
3432 
3433  uint8_t request1[] = {
3434  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43,
3435  0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63,
3436  0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69,
3437  0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d,
3438  0x0a
3439  };
3440  uint32_t request1_len = sizeof(request1);
3441 
3442  uint8_t reply1[] = {
3443  0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30,
3444  0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3445  0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3446  0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3447  0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31,
3448  0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c,
3449  0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31,
3450  0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39,
3451  0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53,
3452  0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39,
3453  0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35,
3454  0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69,
3455  0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3456  0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49,
3457  0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3458  0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47,
3459  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3460  0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3461  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3462  0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3463  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b,
3464  0x0d, 0x0a
3465  };
3466  uint32_t reply1_len = sizeof(reply1);
3467 
3468  /* MAIL FROM:asdff@asdf.com<CR><LF> */
3469  uint8_t request2[] = {
3470  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3471  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
3472  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
3473  0x0d, 0x0a
3474  };
3475  uint32_t request2_len = sizeof(request2);
3476  /* 250 2.1.0 Ok<CR><LF> */
3477  uint8_t reply2[] = {
3478  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3479  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3480  };
3481  uint32_t reply2_len = sizeof(reply2);
3482 
3483  /* RCPT TO:bimbs@gmail.com<CR><LF> */
3484  uint8_t request3[] = {
3485  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
3486  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
3487  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3488  0x0a
3489  };
3490  uint32_t request3_len = sizeof(request3);
3491  /* 250 2.1.5 Ok<CR><LF> */
3492  uint8_t reply3[] = {
3493  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3494  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3495  };
3496  uint32_t reply3_len = sizeof(reply3);
3497 
3498  /* BDAT 51<CR><LF> */
3499  uint8_t request4[] = {
3500  0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d,
3501  0x0a,
3502  };
3503  uint32_t request4_len = sizeof(request4);
3504 
3505  uint8_t request5[] = {
3506  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3507  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3508  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3509  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a,
3510  };
3511  uint32_t request5_len = sizeof(request5);
3512 
3513  uint8_t request6[] = {
3514  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3515  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3516  0x66, 0x0d, 0x0a,
3517  };
3518  uint32_t request6_len = sizeof(request6);
3519 
3520  TcpSession ssn;
3522 
3523  memset(&f, 0, sizeof(f));
3524  memset(&ssn, 0, sizeof(ssn));
3525 
3526  FLOW_INITIALIZE(&f);
3527  f.protoctx = (void *)&ssn;
3528  f.proto = IPPROTO_TCP;
3529  f.alproto = ALPROTO_SMTP;
3530 
3532  SMTPTestInitConfig();
3533 
3534  FLOWLOCK_WRLOCK(&f);
3535  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3536  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3537  if (r != 0) {
3538  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3539  FLOWLOCK_UNLOCK(&f);
3540  goto end;
3541  }
3542  FLOWLOCK_UNLOCK(&f);
3543  SMTPState *smtp_state = f.alstate;
3544  if (smtp_state == NULL) {
3545  printf("no smtp state: ");
3546  goto end;
3547  }
3548  if (smtp_state->input_len != 0 ||
3549  smtp_state->cmds_cnt != 0 ||
3550  smtp_state->cmds_idx != 0 ||
3552  printf("smtp parser in inconsistent state\n");
3553  goto end;
3554  }
3555 
3556  FLOWLOCK_WRLOCK(&f);
3557  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3558  STREAM_TOSERVER, request1, request1_len);
3559  if (r != 0) {
3560  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3561  FLOWLOCK_UNLOCK(&f);
3562  goto end;
3563  }
3564  FLOWLOCK_UNLOCK(&f);
3565  if (smtp_state->input_len != 0 ||
3566  smtp_state->cmds_cnt != 1 ||
3567  smtp_state->cmds_idx != 0 ||
3568  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3570  printf("smtp parser in inconsistent state\n");
3571  goto end;
3572  }
3573 
3574  FLOWLOCK_WRLOCK(&f);
3575  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3576  STREAM_TOCLIENT, reply1, reply1_len);
3577  if (r != 0) {
3578  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3579  FLOWLOCK_UNLOCK(&f);
3580  goto end;
3581  }
3582  FLOWLOCK_UNLOCK(&f);
3583  if (smtp_state->input_len != 0 ||
3584  smtp_state->cmds_cnt != 0 ||
3585  smtp_state->cmds_idx != 0 ||
3587  printf("smtp parser in inconsistent state\n");
3588  goto end;
3589  }
3590 
3591  FLOWLOCK_WRLOCK(&f);
3592  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3593  STREAM_TOSERVER, request2, request2_len);
3594  if (r != 0) {
3595  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3596  FLOWLOCK_UNLOCK(&f);
3597  goto end;
3598  }
3599  FLOWLOCK_UNLOCK(&f);
3600  if (smtp_state->input_len != 0 ||
3601  smtp_state->cmds_cnt != 1 ||
3602  smtp_state->cmds_idx != 0 ||
3603  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3605  printf("smtp parser in inconsistent state\n");
3606  goto end;
3607  }
3608 
3609  FLOWLOCK_WRLOCK(&f);
3610  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3611  STREAM_TOCLIENT, reply2, reply2_len);
3612  if (r != 0) {
3613  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3614  FLOWLOCK_UNLOCK(&f);
3615  goto end;
3616  }
3617  FLOWLOCK_UNLOCK(&f);
3618  if (smtp_state->input_len != 0 ||
3619  smtp_state->cmds_cnt != 0 ||
3620  smtp_state->cmds_idx != 0 ||
3622  printf("smtp parser in inconsistent state\n");
3623  goto end;
3624  }
3625 
3626  FLOWLOCK_WRLOCK(&f);
3627  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3628  STREAM_TOSERVER, request3, request3_len);
3629  if (r != 0) {
3630  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3631  FLOWLOCK_UNLOCK(&f);
3632  goto end;
3633  }
3634  FLOWLOCK_UNLOCK(&f);
3635  if (smtp_state->input_len != 0 ||
3636  smtp_state->cmds_cnt != 1 ||
3637  smtp_state->cmds_idx != 0 ||
3638  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3640  printf("smtp parser in inconsistent state\n");
3641  goto end;
3642  }
3643 
3644  FLOWLOCK_WRLOCK(&f);
3645  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3646  STREAM_TOCLIENT, reply3, reply3_len);
3647  if (r != 0) {
3648  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3649  FLOWLOCK_UNLOCK(&f);
3650  goto end;
3651  }
3652  FLOWLOCK_UNLOCK(&f);
3653  if (smtp_state->input_len != 0 ||
3654  smtp_state->cmds_cnt != 0 ||
3655  smtp_state->cmds_idx != 0 ||
3657  printf("smtp parser in inconsistent state\n");
3658  goto end;
3659  }
3660 
3661  FLOWLOCK_WRLOCK(&f);
3662  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3663  STREAM_TOSERVER, request4, request4_len);
3664  if (r != 0) {
3665  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3666  FLOWLOCK_UNLOCK(&f);
3667  goto end;
3668  }
3669  FLOWLOCK_UNLOCK(&f);
3670  if (smtp_state->input_len != 0 ||
3671  smtp_state->cmds_cnt != 1 ||
3672  smtp_state->cmds_idx != 0 ||
3673  smtp_state->cmds[0] != SMTP_COMMAND_BDAT ||
3676  smtp_state->bdat_chunk_len != 51 ||
3677  smtp_state->bdat_chunk_idx != 0) {
3678  printf("smtp parser in inconsistent state\n");
3679  goto end;
3680  }
3681 
3682  FLOWLOCK_WRLOCK(&f);
3683  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3684  STREAM_TOSERVER, request5, request5_len);
3685  if (r != 0) {
3686  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3687  FLOWLOCK_UNLOCK(&f);
3688  goto end;
3689  }
3690  FLOWLOCK_UNLOCK(&f);
3691  if (smtp_state->input_len != 0 ||
3692  smtp_state->cmds_cnt != 1 ||
3693  smtp_state->cmds_idx != 0 ||
3696  smtp_state->bdat_chunk_len != 51 ||
3697  smtp_state->bdat_chunk_idx != 32) {
3698  printf("smtp parser in inconsistent state\n");
3699  goto end;
3700  }
3701 
3702  FLOWLOCK_WRLOCK(&f);
3703  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3704  STREAM_TOSERVER, request6, request6_len);
3705  if (r != 0) {
3706  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3707  FLOWLOCK_UNLOCK(&f);
3708  goto end;
3709  }
3710  FLOWLOCK_UNLOCK(&f);
3711  if (smtp_state->input_len != 0 ||
3712  smtp_state->cmds_cnt != 1 ||
3713  smtp_state->cmds_idx != 0 ||
3715  smtp_state->bdat_chunk_len != 51 ||
3716  smtp_state->bdat_chunk_idx != 51) {
3717  printf("smtp parser in inconsistent state\n");
3718  goto end;
3719  }
3720 
3721  result = 1;
3722 end:
3723  if (alp_tctx != NULL)
3726  FLOW_DESTROY(&f);
3727  return result;
3728 }
3729 
3730 /*
3731  * \test Test retrieving lines when frag'ed.
3732  */
3733 static int SMTPParserTest07(void)
3734 {
3735  int result = 0;
3736  Flow f;
3737  int r = 0;
3738 
3739  const char *request1_str = "EHLO boo.com";
3740  /* EHLO boo.com<CR> */
3741  uint8_t request1_1[] = {
3742  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3743  0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3744  };
3745  int32_t request1_1_len = sizeof(request1_1);
3746 
3747  /* <LF> */
3748  uint8_t request1_2[] = {
3749  0x0a
3750  };
3751  int32_t request1_2_len = sizeof(request1_2);
3752 
3753  /* EHLO boo.com<CR><LF> */
3754  uint8_t request2[] = {
3755  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3756  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3757  };
3758  int32_t request2_len = sizeof(request2);
3759 
3760  TcpSession ssn;
3762 
3763  memset(&f, 0, sizeof(f));
3764  memset(&ssn, 0, sizeof(ssn));
3765 
3766  FLOW_INITIALIZE(&f);
3767  f.protoctx = (void *)&ssn;
3768  f.proto = IPPROTO_TCP;
3769  f.alproto = ALPROTO_SMTP;
3770 
3772  SMTPTestInitConfig();
3773 
3774  FLOWLOCK_WRLOCK(&f);
3775  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3776  STREAM_TOSERVER, request1_1, request1_1_len);
3777  if (r != 0) {
3778  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3779  FLOWLOCK_UNLOCK(&f);
3780  goto end;
3781  }
3782  FLOWLOCK_UNLOCK(&f);
3783  SMTPState *smtp_state = f.alstate;
3784  if (smtp_state == NULL) {
3785  printf("no smtp state: ");
3786  goto end;
3787  }
3788  if (smtp_state->current_line != NULL ||
3789  smtp_state->current_line_len != 0 ||
3790  smtp_state->ts_current_line_db != 1 ||
3791  smtp_state->ts_db == NULL ||
3792  smtp_state->ts_db_len != request1_1_len ||
3793  memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3794  printf("smtp parser in inconsistent state\n");
3795  goto end;
3796  }
3797 
3798  FLOWLOCK_WRLOCK(&f);
3799  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3800  STREAM_TOSERVER, request1_2, request1_2_len);
3801  if (r != 0) {
3802  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3803  FLOWLOCK_UNLOCK(&f);
3804  goto end;
3805  }
3806  FLOWLOCK_UNLOCK(&f);
3807  if (smtp_state->ts_current_line_db != 1 ||
3808  smtp_state->ts_db == NULL ||
3809  smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3810  memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3811  smtp_state->current_line != smtp_state->ts_db ||
3812  smtp_state->current_line_len != smtp_state->ts_db_len) {
3813  printf("smtp parser in inconsistent state\n");
3814  goto end;
3815  }
3816 
3817  FLOWLOCK_WRLOCK(&f);
3818  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3819  STREAM_TOSERVER, request2, request2_len);
3820  if (r != 0) {
3821  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3822  FLOWLOCK_UNLOCK(&f);
3823  goto end;
3824  }
3825  FLOWLOCK_UNLOCK(&f);
3826  if (smtp_state->ts_current_line_db != 0 ||
3827  smtp_state->ts_db != NULL ||
3828  smtp_state->ts_db_len != 0 ||
3829  smtp_state->current_line == NULL ||
3830  smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
3831  memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3832  printf("smtp parser in inconsistent state\n");
3833  goto end;
3834  }
3835 
3836  result = 1;
3837 end:
3838  if (alp_tctx != NULL)
3841  FLOW_DESTROY(&f);
3842  return result;
3843 }
3844 
3845 /*
3846  * \test Test retrieving lines when frag'ed.
3847  */
3848 static int SMTPParserTest08(void)
3849 {
3850  int result = 0;
3851  Flow f;
3852  int r = 0;
3853 
3854  const char *request1_str = "EHLO boo.com";
3855  /* EHLO boo.com */
3856  uint8_t request1_1[] = {
3857  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3858  0x2e, 0x63, 0x6f, 0x6d,
3859  };
3860  int32_t request1_1_len = sizeof(request1_1);
3861 
3862  /* <CR><LF> */
3863  uint8_t request1_2[] = {
3864  0x0d, 0x0a
3865  };
3866  int32_t request1_2_len = sizeof(request1_2);
3867 
3868  /* EHLO boo.com<CR><LF> */
3869  uint8_t request2[] = {
3870  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3871  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3872  };
3873  int32_t request2_len = sizeof(request2);
3874 
3875  TcpSession ssn;
3877 
3878  memset(&f, 0, sizeof(f));
3879  memset(&ssn, 0, sizeof(ssn));
3880 
3881  FLOW_INITIALIZE(&f);
3882  f.protoctx = (void *)&ssn;
3883  f.proto = IPPROTO_TCP;
3884  f.alproto = ALPROTO_SMTP;
3885 
3887  SMTPTestInitConfig();
3888 
3889  FLOWLOCK_WRLOCK(&f);
3890  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3891  STREAM_TOSERVER, request1_1, request1_1_len);
3892  if (r != 0) {
3893  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3894  FLOWLOCK_UNLOCK(&f);
3895  goto end;
3896  }
3897  FLOWLOCK_UNLOCK(&f);
3898  SMTPState *smtp_state = f.alstate;
3899  if (smtp_state == NULL) {
3900  printf("no smtp state: ");
3901  goto end;
3902  }
3903  if (smtp_state->current_line != NULL ||
3904  smtp_state->current_line_len != 0 ||
3905  smtp_state->ts_current_line_db != 1 ||
3906  smtp_state->ts_db == NULL ||
3907  smtp_state->ts_db_len != request1_1_len ||
3908  memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3909  printf("smtp parser in inconsistent state\n");
3910  goto end;
3911  }
3912 
3913  FLOWLOCK_WRLOCK(&f);
3914  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3915  STREAM_TOSERVER, request1_2, request1_2_len);
3916  if (r != 0) {
3917  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3918  FLOWLOCK_UNLOCK(&f);
3919  goto end;
3920  }
3921  FLOWLOCK_UNLOCK(&f);
3922  if (smtp_state->ts_current_line_db != 1 ||
3923  smtp_state->ts_db == NULL ||
3924  smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3925  memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3926  smtp_state->current_line != smtp_state->ts_db ||
3927  smtp_state->current_line_len != smtp_state->ts_db_len) {
3928  printf("smtp parser in inconsistent state\n");
3929  goto end;
3930  }
3931 
3932  FLOWLOCK_WRLOCK(&f);
3933  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3934  STREAM_TOSERVER, request2, request2_len);
3935  if (r != 0) {
3936  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3937  FLOWLOCK_UNLOCK(&f);
3938  goto end;
3939  }
3940  FLOWLOCK_UNLOCK(&f);
3941  if (smtp_state->ts_current_line_db != 0 ||
3942  smtp_state->ts_db != NULL ||
3943  smtp_state->ts_db_len != 0 ||
3944  smtp_state->current_line == NULL ||
3945  smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
3946  memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3947  printf("smtp parser in inconsistent state\n");
3948  goto end;
3949  }
3950 
3951  result = 1;
3952 end:
3953  if (alp_tctx != NULL)
3956  FLOW_DESTROY(&f);
3957  return result;
3958 }
3959 
3960 /*
3961  * \test Test retrieving lines when frag'ed.
3962  */
3963 static int SMTPParserTest09(void)
3964 {
3965  int result = 0;
3966  Flow f;
3967  int r = 0;
3968 
3969  const char *request1_str = "EHLO boo.com";
3970  /* EHLO boo. */
3971  uint8_t request1_1[] = {
3972  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3973  0x2e,
3974  };
3975  int32_t request1_1_len = sizeof(request1_1);
3976 
3977  /* com<CR><LF> */
3978  uint8_t request1_2[] = {
3979  0x63, 0x6f, 0x6d, 0x0d, 0x0a
3980  };
3981  int32_t request1_2_len = sizeof(request1_2);
3982 
3983  /* EHLO boo.com<CR><LF> */
3984  uint8_t request2[] = {
3985  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3986  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3987  };
3988  int32_t request2_len = sizeof(request2);
3989 
3990  TcpSession ssn;
3992 
3993  memset(&f, 0, sizeof(f));
3994  memset(&ssn, 0, sizeof(ssn));
3995 
3996  FLOW_INITIALIZE(&f);
3997  f.protoctx = (void *)&ssn;
3998  f.proto = IPPROTO_TCP;
3999  f.alproto = ALPROTO_SMTP;
4000 
4002  SMTPTestInitConfig();
4003 
4004  FLOWLOCK_WRLOCK(&f);
4005  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4006  STREAM_TOSERVER, request1_1, request1_1_len);
4007  if (r != 0) {
4008  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4009  FLOWLOCK_UNLOCK(&f);
4010  goto end;
4011  }
4012  FLOWLOCK_UNLOCK(&f);
4013  SMTPState *smtp_state = f.alstate;
4014  if (smtp_state == NULL) {
4015  printf("no smtp state: ");
4016  goto end;
4017  }
4018  if (smtp_state->current_line != NULL ||
4019  smtp_state->current_line_len != 0 ||
4020  smtp_state->ts_current_line_db != 1 ||
4021  smtp_state->ts_db == NULL ||
4022  smtp_state->ts_db_len != request1_1_len ||
4023  memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
4024  printf("smtp parser in inconsistent state\n");
4025  goto end;
4026  }
4027 
4028  FLOWLOCK_WRLOCK(&f);
4029  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4030  STREAM_TOSERVER, request1_2, request1_2_len);
4031  if (r != 0) {
4032  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4033  FLOWLOCK_UNLOCK(&f);
4034  goto end;
4035  }
4036  FLOWLOCK_UNLOCK(&f);
4037  if (smtp_state->ts_current_line_db != 1 ||
4038  smtp_state->ts_db == NULL ||
4039  smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
4040  memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
4041  smtp_state->current_line != smtp_state->ts_db ||
4042  smtp_state->current_line_len != smtp_state->ts_db_len) {
4043  printf("smtp parser in inconsistent state\n");
4044  goto end;
4045  }
4046 
4047  FLOWLOCK_WRLOCK(&f);
4048  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4049  STREAM_TOSERVER, request2, request2_len);
4050  if (r != 0) {
4051  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4052  FLOWLOCK_UNLOCK(&f);
4053  goto end;
4054  }
4055  FLOWLOCK_UNLOCK(&f);
4056  if (smtp_state->ts_current_line_db != 0 ||
4057  smtp_state->ts_db != NULL ||
4058  smtp_state->ts_db_len != 0 ||
4059  smtp_state->current_line == NULL ||
4060  smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
4061  memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
4062  printf("smtp parser in inconsistent state\n");
4063  goto end;
4064  }
4065 
4066  result = 1;
4067 end:
4068  if (alp_tctx != NULL)
4071  FLOW_DESTROY(&f);
4072  return result;
4073 }
4074 
4075 /*
4076  * \test Test retrieving lines when frag'ed.
4077  */
4078 static int SMTPParserTest10(void)
4079 {
4080  int result = 0;
4081  Flow f;
4082  int r = 0;
4083 
4084  const char *request1_str = "";
4085  /* EHLO boo. */
4086  uint8_t request1_1[] = {
4087  0x0d,
4088  };
4089  int32_t request1_1_len = sizeof(request1_1);
4090 
4091  /* com<CR><LF> */
4092  uint8_t request1_2[] = {
4093  0x0a,
4094  };
4095  int32_t request1_2_len = sizeof(request1_2);
4096 
4097  const char *request2_str = "EHLO boo.com";
4098  /* EHLO boo.com<CR><LF> */
4099  uint8_t request2[] = {
4100  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4101  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4102  };
4103  int32_t request2_len = sizeof(request2);
4104 
4105  TcpSession ssn;
4107 
4108  memset(&f, 0, sizeof(f));
4109  memset(&ssn, 0, sizeof(ssn));
4110 
4111  FLOW_INITIALIZE(&f);
4112  f.protoctx = (void *)&ssn;
4113  f.proto = IPPROTO_TCP;
4114  f.alproto = ALPROTO_SMTP;
4115 
4117  SMTPTestInitConfig();
4118 
4119  FLOWLOCK_WRLOCK(&f);
4120  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4121  STREAM_TOSERVER, request1_1, request1_1_len);
4122  if (r != 0) {
4123  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4124  FLOWLOCK_UNLOCK(&f);
4125  goto end;
4126  }
4127  FLOWLOCK_UNLOCK(&f);
4128  SMTPState *smtp_state = f.alstate;
4129  if (smtp_state == NULL) {
4130  printf("no smtp state: ");
4131  goto end;
4132  }
4133  if (smtp_state->current_line != NULL ||
4134  smtp_state->current_line_len != 0 ||
4135  smtp_state->ts_current_line_db != 1 ||
4136  smtp_state->ts_db == NULL ||
4137  smtp_state->ts_db_len != request1_1_len ||
4138  memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
4139  printf("smtp parser in inconsistent state\n");
4140  goto end;
4141  }
4142 
4143  FLOWLOCK_WRLOCK(&f);
4144  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4145  STREAM_TOSERVER, request1_2, request1_2_len);
4146  if (r != 0) {
4147  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4148  FLOWLOCK_UNLOCK(&f);
4149  goto end;
4150  }
4151  FLOWLOCK_UNLOCK(&f);
4152  if (smtp_state->ts_current_line_db != 1 ||
4153  smtp_state->ts_db == NULL ||
4154  smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
4155  memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
4156  smtp_state->current_line != smtp_state->ts_db ||
4157  smtp_state->current_line_len != smtp_state->ts_db_len) {
4158  printf("smtp parser in inconsistent state\n");
4159  goto end;
4160  }
4161 
4162  FLOWLOCK_WRLOCK(&f);
4163  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4164  STREAM_TOSERVER, request2, request2_len);
4165  if (r != 0) {
4166  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4167  FLOWLOCK_UNLOCK(&f);
4168  goto end;
4169  }
4170  FLOWLOCK_UNLOCK(&f);
4171  if (smtp_state->ts_current_line_db != 0 ||
4172  smtp_state->ts_db != NULL ||
4173  smtp_state->ts_db_len != 0 ||
4174  smtp_state->current_line == NULL ||
4175  smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
4176  memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
4177  printf("smtp parser in inconsistent state\n");
4178  goto end;
4179  }
4180 
4181  result = 1;
4182 end:
4183  if (alp_tctx != NULL)
4186  FLOW_DESTROY(&f);
4187  return result;
4188 }
4189 
4190 /*
4191  * \test Test retrieving lines when frag'ed.
4192  */
4193 static int SMTPParserTest11(void)
4194 {
4195  int result = 0;
4196  Flow f;
4197  int r = 0;
4198 
4199  const char *request1_str = "";
4200  /* EHLO boo. */
4201  uint8_t request1[] = {
4202  0x0a,
4203  };
4204  int32_t request1_len = sizeof(request1);
4205 
4206  const char *request2_str = "EHLO boo.com";
4207  /* EHLO boo.com<CR><LF> */
4208  uint8_t request2[] = {
4209  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4210  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4211  };
4212  int32_t request2_len = sizeof(request2);
4213 
4214  TcpSession ssn;
4216 
4217  memset(&f, 0, sizeof(f));
4218  memset(&ssn, 0, sizeof(ssn));
4219 
4220  FLOW_INITIALIZE(&f);
4221  f.protoctx = (void *)&ssn;
4222  f.proto = IPPROTO_TCP;
4223  f.alproto = ALPROTO_SMTP;
4224 
4226  SMTPTestInitConfig();
4227 
4228  FLOWLOCK_WRLOCK(&f);
4229  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4230  STREAM_TOSERVER, request1, request1_len);
4231  if (r != 0) {
4232  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4233  FLOWLOCK_UNLOCK(&f);
4234  goto end;
4235  }
4236  FLOWLOCK_UNLOCK(&f);
4237  SMTPState *smtp_state = f.alstate;
4238  if (smtp_state == NULL) {
4239  printf("no smtp state: ");
4240  goto end;
4241  }
4242  if (smtp_state->current_line == NULL ||
4243  smtp_state->current_line_len != 0 ||
4244  smtp_state->ts_current_line_db == 1 ||
4245  smtp_state->ts_db != NULL ||
4246  smtp_state->ts_db_len != 0 ||
4247  memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
4248  printf("smtp parser in inconsistent state\n");
4249  goto end;
4250  }
4251 
4252  FLOWLOCK_WRLOCK(&f);
4253  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4254  STREAM_TOSERVER, request2, request2_len);
4255  if (r != 0) {
4256  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4257  FLOWLOCK_UNLOCK(&f);
4258  goto end;
4259  }
4260  FLOWLOCK_UNLOCK(&f);
4261  if (smtp_state->ts_current_line_db != 0 ||
4262  smtp_state->ts_db != NULL ||
4263  smtp_state->ts_db_len != 0 ||
4264  smtp_state->current_line == NULL ||
4265  smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
4266  memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
4267  printf("smtp parser in inconsistent state\n");
4268  goto end;
4269  }
4270 
4271  result = 1;
4272 end:
4273  if (alp_tctx != NULL)
4276  FLOW_DESTROY(&f);
4277  return result;
4278 }
4279 
4280 static int SMTPParserTest12(void)
4281 {
4282  int result = 0;
4283  Signature *s = NULL;
4284  ThreadVars th_v;
4285  Packet *p = NULL;
4286  Flow f;
4287  TcpSession ssn;
4288  DetectEngineThreadCtx *det_ctx = NULL;
4289  DetectEngineCtx *de_ctx = NULL;
4290  SMTPState *smtp_state = NULL;
4291  int r = 0;
4292 
4293  /* EHLO boo.com<CR><LF> */
4294  uint8_t request1[] = {
4295  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4296  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4297  };
4298  int32_t request1_len = sizeof(request1);
4299 
4300  /* 388<CR><LF>
4301  */
4302  uint8_t reply1[] = {
4303  0x31, 0x38, 0x38, 0x0d, 0x0a,
4304  };
4305  uint32_t reply1_len = sizeof(reply1);
4306 
4308 
4309  memset(&th_v, 0, sizeof(th_v));
4310  memset(&f, 0, sizeof(f));
4311  memset(&ssn, 0, sizeof(ssn));
4312 
4313  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
4314 
4315  FLOW_INITIALIZE(&f);
4316  f.protoctx = (void *)&ssn;
4317  f.proto = IPPROTO_TCP;
4318  f.alproto = ALPROTO_SMTP;
4319  p->flow = &f;
4323  f.alproto = ALPROTO_SMTP;
4324 
4326  SMTPTestInitConfig();
4327 
4329  if (de_ctx == NULL)
4330  goto end;
4331 
4332  de_ctx->flags |= DE_QUIET;
4333 
4334  s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any "
4335  "(msg:\"SMTP event handling\"; "
4336  "app-layer-event: smtp.invalid_reply; "
4337  "sid:1;)");
4338  if (s == NULL)
4339  goto end;
4340 
4342  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4343 
4344  FLOWLOCK_WRLOCK(&f);
4345  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4346  STREAM_TOSERVER | STREAM_START, request1,
4347  request1_len);
4348  if (r != 0) {
4349  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4350  FLOWLOCK_UNLOCK(&f);
4351  goto end;
4352  }
4353  FLOWLOCK_UNLOCK(&f);
4354 
4355  smtp_state = f.alstate;
4356  if (smtp_state == NULL) {
4357  printf("no smtp state: ");
4358  goto end;
4359  }
4360 
4361  /* do detect */
4362  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4363 
4364  if (PacketAlertCheck(p, 1)) {
4365  printf("sid 1 matched. It shouldn't match: ");
4366  goto end;
4367  }
4368 
4369  FLOWLOCK_WRLOCK(&f);
4370  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4371  STREAM_TOCLIENT | STREAM_TOCLIENT, reply1,
4372  reply1_len);
4373  if (r == 0) {
4374  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4375  FLOWLOCK_UNLOCK(&f);
4376  goto end;
4377  }
4378  FLOWLOCK_UNLOCK(&f);
4379 
4380  /* do detect */
4381  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4382 
4383  if (!PacketAlertCheck(p, 1)) {
4384  printf("sid 1 didn't match. Should have matched: ");
4385  goto end;
4386  }
4387 
4388  result = 1;
4389 
4390 end:
4393 
4394  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4396 
4397  if (alp_tctx != NULL)
4400  FLOW_DESTROY(&f);
4401  UTHFreePackets(&p, 1);
4402  return result;
4403 }
4404 
4405 static int SMTPParserTest13(void)
4406 {
4407  int result = 0;
4408  Signature *s = NULL;
4409  ThreadVars th_v;
4410  Packet *p = NULL;
4411  Flow f;
4412  TcpSession ssn;
4413  DetectEngineThreadCtx *det_ctx = NULL;
4414  DetectEngineCtx *de_ctx = NULL;
4415  SMTPState *smtp_state = NULL;
4416  int r = 0;
4417 
4418  /* EHLO boo.com<CR><LF> */
4419  uint8_t request1[] = {
4420  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4421  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4422  };
4423  int32_t request1_len = sizeof(request1);
4424 
4425  /* 250<CR><LF>
4426  */
4427  uint8_t reply1[] = {
4428  0x32, 0x35, 0x30, 0x0d, 0x0a,
4429  };
4430  uint32_t reply1_len = sizeof(reply1);
4431 
4432  /* MAIL FROM:pbsf@asdfs.com<CR><LF>
4433  * RCPT TO:pbsf@asdfs.com<CR><LF>
4434  * DATA<CR><LF>
4435  * STARTTLS<CR><LF>
4436  */
4437  uint8_t request2[] = {
4438  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
4439  0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
4440  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
4441  0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
4442  0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
4443  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
4444  0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
4445  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
4446  0x0d, 0x0a
4447  };
4448  uint32_t request2_len = sizeof(request2);
4449 
4451 
4452  memset(&th_v, 0, sizeof(th_v));
4453  memset(&f, 0, sizeof(f));
4454  memset(&ssn, 0, sizeof(ssn));
4455 
4456  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
4457 
4458  FLOW_INITIALIZE(&f);
4459  f.protoctx = (void *)&ssn;
4460  f.proto = IPPROTO_TCP;
4461  f.alproto = ALPROTO_SMTP;
4462  p->flow = &f;
4466  f.alproto = ALPROTO_SMTP;
4467 
4469  SMTPTestInitConfig();
4470 
4472  if (de_ctx == NULL)
4473  goto end;
4474 
4475  de_ctx->flags |= DE_QUIET;
4476 
4477  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
4478  "(msg:\"SMTP event handling\"; "
4479  "app-layer-event: "
4480  "smtp.invalid_pipelined_sequence; "
4481  "sid:1;)");
4482  if (s == NULL)
4483  goto end;
4484 
4486  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4487 
4488  FLOWLOCK_WRLOCK(&f);
4489  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4490  STREAM_TOSERVER | STREAM_START, request1,
4491  request1_len);
4492  if (r != 0) {
4493  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4494  FLOWLOCK_UNLOCK(&f);
4495  goto end;
4496  }
4497  FLOWLOCK_UNLOCK(&f);
4498 
4499  smtp_state = f.alstate;
4500  if (smtp_state == NULL) {
4501  printf("no smtp state: ");
4502  goto end;
4503  }
4504 
4505  /* do detect */
4506  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4507 
4508  if (PacketAlertCheck(p, 1)) {
4509  printf("sid 1 matched. It shouldn't match: ");
4510  goto end;
4511  }
4512 
4513  FLOWLOCK_WRLOCK(&f);
4514  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4515  STREAM_TOCLIENT, reply1, reply1_len);
4516  if (r != 0) {
4517  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4518  FLOWLOCK_UNLOCK(&f);
4519  goto end;
4520  }
4521  FLOWLOCK_UNLOCK(&f);
4522 
4523  /* do detect */
4524  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4525 
4526  if (PacketAlertCheck(p, 1)) {
4527  printf("sid 1 matched. It shouldn't match: ");
4528  goto end;
4529  }
4530 
4531  FLOWLOCK_WRLOCK(&f);
4532  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4533  STREAM_TOSERVER, request2, request2_len);
4534  if (r != 0) {
4535  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4536  FLOWLOCK_UNLOCK(&f);
4537  goto end;
4538  }
4539  FLOWLOCK_UNLOCK(&f);
4540 
4541  /* do detect */
4542  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4543 
4544  if (!PacketAlertCheck(p, 1)) {
4545  printf("sid 1 didn't match. Should have matched: ");
4546  goto end;
4547  }
4548 
4549  result = 1;
4550 
4551 end:
4554 
4555  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4557 
4558  if (alp_tctx != NULL)
4561  FLOW_DESTROY(&f);
4562  UTHFreePackets(&p, 1);
4563  return result;
4564 }
4565 
4566 /**
4567  * \test Test DATA command w/MIME message.
4568  */
4569 static int SMTPParserTest14(void)
4570 {
4571  int result = 0;
4572  Flow f;
4573  int r = 0;
4574 
4575  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
4576  static uint8_t welcome_reply[] = {
4577  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
4578  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
4579  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
4580  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
4581  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
4582  0x0d, 0x0a
4583  };
4584  static uint32_t welcome_reply_len = sizeof(welcome_reply);
4585 
4586  /* EHLO boo.com<CR><LF> */
4587  static uint8_t request1[] = {
4588  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4589  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
4590  };
4591  static uint32_t request1_len = sizeof(request1);
4592  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
4593  * 250-SIZE 35882577<CR><LF>
4594  * 250-8BITMIME<CR><LF>
4595  * 250-STARTTLS<CR><LF>
4596  * 250 ENHANCEDSTATUSCODES<CR><LF>
4597  */
4598  static uint8_t reply1[] = {
4599  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
4600  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
4601  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
4602  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
4603  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
4604  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
4605  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
4606  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
4607  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
4608  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
4609  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
4610  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
4611  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
4612  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
4613  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
4614  };
4615  static uint32_t reply1_len = sizeof(reply1);
4616 
4617  /* MAIL FROM:asdff@asdf.com<CR><LF> */
4618  static uint8_t request2[] = {
4619  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
4620  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
4621  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
4622  0x0d, 0x0a
4623  };
4624  static uint32_t request2_len = sizeof(request2);
4625  /* 250 2.1.0 Ok<CR><LF> */
4626  static uint8_t reply2[] = {
4627  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4628  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4629  };
4630  static uint32_t reply2_len = sizeof(reply2);
4631 
4632  /* RCPT TO:bimbs@gmail.com<CR><LF> */
4633  static uint8_t request3[] = {
4634  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
4635  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
4636  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
4637  0x0a
4638  };
4639  static uint32_t request3_len = sizeof(request3);
4640  /* 250 2.1.5 Ok<CR><LF> */
4641  static uint8_t reply3[] = {
4642  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4643  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4644  };
4645  static uint32_t reply3_len = sizeof(reply3);
4646 
4647  /* DATA<CR><LF> */
4648  static uint8_t request4[] = {
4649  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
4650  };
4651  static uint32_t request4_len = sizeof(request4);
4652  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
4653  static uint8_t reply4[] = {
4654  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
4655  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
4656  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
4657  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
4658  0x4c, 0x46, 0x3e, 0x0d, 0x0a
4659  };
4660  static uint32_t reply4_len = sizeof(reply4);
4661 
4662  /* MIME_MSG */
4663  static uint64_t filesize = 133;
4664  static uint8_t request4_msg[] = {
4665  0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
4666  0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
4667  0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4668  0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
4669  0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
4670  0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
4671  0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
4672  0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4673  0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
4674  0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
4675  0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
4676  0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
4677  0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
4678  0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
4679  0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
4680  0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
4681  0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
4682  0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
4683  0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
4684  0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
4685  0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
4686  0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
4687  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4688  0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
4689  0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
4690  0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
4691  0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
4692  0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
4693  0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
4694  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4695  0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
4696  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4697  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4698  0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
4699  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4700  0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4701  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4702  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4703  0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
4704  0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
4705  0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
4706  0x41, 0x3D, 0x3D, 0x0D,0x0A };
4707  static uint32_t request4_msg_len = sizeof(request4_msg);
4708 
4709  /* DATA COMPLETED */
4710  static uint8_t request4_end[] = {
4711  0x0d, 0x0a, 0x2e, 0x0d, 0x0a
4712  };
4713  static uint32_t request4_end_len = sizeof(request4_end);
4714  /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
4715  static uint8_t reply4_end[] = {
4716  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4717  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
4718  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
4719  0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
4720  0x46, 0x32, 0x0d, 0x0a
4721  };
4722  static uint32_t reply4_end_len = sizeof(reply4_end);
4723 
4724  /* QUIT<CR><LF> */
4725  static uint8_t request5[] = {
4726  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
4727  };
4728  static uint32_t request5_len = sizeof(request5);
4729  /* 221 2.0.0 Bye<CR><LF> */
4730  static uint8_t reply5[] = {
4731  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4732  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
4733  };
4734  static uint32_t reply5_len = sizeof(reply5);
4735 
4736  TcpSession ssn;
4738 
4739  memset(&f, 0, sizeof(f));
4740  memset(&ssn, 0, sizeof(ssn));
4741 
4742  FLOW_INITIALIZE(&f);
4743  f.protoctx = (void *)&ssn;
4744  f.proto = IPPROTO_TCP;
4745  f.alproto = ALPROTO_SMTP;
4746 
4748  SMTPTestInitConfig();
4749 
4750  FLOWLOCK_WRLOCK(&f);
4751  /* Welcome reply */
4752  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4753  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
4754  if (r != 0) {
4755  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4756  FLOWLOCK_UNLOCK(&f);
4757  goto end;
4758  }
4759  FLOWLOCK_UNLOCK(&f);
4760  SMTPState *smtp_state = f.alstate;
4761  if (smtp_state == NULL) {
4762  printf("no smtp state: ");
4763  goto end;
4764  }
4765  if (smtp_state->input_len != 0 ||
4766  smtp_state->cmds_cnt != 0 ||
4767  smtp_state->cmds_idx != 0 ||
4769  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4770  goto end;
4771  }
4772 
4773  FLOWLOCK_WRLOCK(&f);
4774  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4775  STREAM_TOSERVER, request1, request1_len);
4776  if (r != 0) {
4777  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4778  FLOWLOCK_UNLOCK(&f);
4779  goto end;
4780  }
4781  FLOWLOCK_UNLOCK(&f);
4782  if (smtp_state->input_len != 0 ||
4783  smtp_state->cmds_cnt != 1 ||
4784  smtp_state->cmds_idx != 0 ||
4785  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4787  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4788  goto end;
4789  }
4790 
4791  FLOWLOCK_WRLOCK(&f);
4792  /* EHLO Reply */
4793  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4794  STREAM_TOCLIENT, reply1, reply1_len);
4795  if (r != 0) {
4796  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4797  FLOWLOCK_UNLOCK(&f);
4798  goto end;
4799  }
4800 
4801  if ((smtp_state->helo_len != 7) || strncmp("boo.com", (char *)smtp_state->helo, 7)) {
4802  printf("incorrect parsing of HELO field '%s' (%d)\n", smtp_state->helo, smtp_state->helo_len);
4803  FLOWLOCK_UNLOCK(&f);
4804  goto end;
4805  }
4806 
4807  FLOWLOCK_UNLOCK(&f);
4808  if (smtp_state->input_len != 0 ||
4809  smtp_state->cmds_cnt != 0 ||
4810  smtp_state->cmds_idx != 0 ||
4812  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4813  goto end;
4814  }
4815 
4816  FLOWLOCK_WRLOCK(&f);
4817  /* MAIL FROM Request */
4818  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4819  STREAM_TOSERVER, request2, request2_len);
4820  if (r != 0) {
4821  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4822  FLOWLOCK_UNLOCK(&f);
4823  goto end;
4824  }
4825  FLOWLOCK_UNLOCK(&f);
4826  if (smtp_state->input_len != 0 ||
4827  smtp_state->cmds_cnt != 1 ||
4828  smtp_state->cmds_idx != 0 ||
4829  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4831  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4832  goto end;
4833  }
4834 
4835  FLOWLOCK_WRLOCK(&f);
4836  /* MAIL FROM Reply */
4837  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4838  STREAM_TOCLIENT, reply2, reply2_len);
4839  if (r != 0) {
4840  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4841  FLOWLOCK_UNLOCK(&f);
4842  goto end;
4843  }
4844 
4845  if ((smtp_state->curr_tx->mail_from_len != 14) ||
4846  strncmp("asdff@asdf.com", (char *)smtp_state->curr_tx->mail_from, 14)) {
4847  printf("incorrect parsing of MAIL FROM field '%s' (%d)\n",
4848  smtp_state->curr_tx->mail_from,
4849  smtp_state->curr_tx->mail_from_len);
4850  FLOWLOCK_UNLOCK(&f);
4851  goto end;
4852  }
4853 
4854  FLOWLOCK_UNLOCK(&f);
4855  if (smtp_state->input_len != 0 ||
4856  smtp_state->cmds_cnt != 0 ||
4857  smtp_state->cmds_idx != 0 ||
4859  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4860  goto end;
4861  }
4862 
4863  FLOWLOCK_WRLOCK(&f);
4864  /* RCPT TO Request */
4865  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4866  STREAM_TOSERVER, request3, request3_len);
4867  if (r != 0) {
4868  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4869  FLOWLOCK_UNLOCK(&f);
4870  goto end;
4871  }
4872  FLOWLOCK_UNLOCK(&f);
4873  if (smtp_state->input_len != 0 ||
4874  smtp_state->cmds_cnt != 1 ||
4875  smtp_state->cmds_idx != 0 ||
4876  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4878  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4879  goto end;
4880  }
4881 
4882  FLOWLOCK_WRLOCK(&f);
4883  /* RCPT TO Reply */
4884  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4885  STREAM_TOCLIENT, reply3, reply3_len);
4886  if (r != 0) {
4887  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4888  FLOWLOCK_UNLOCK(&f);
4889  goto end;
4890  }
4891  FLOWLOCK_UNLOCK(&f);
4892  if (smtp_state->input_len != 0 ||
4893  smtp_state->cmds_cnt != 0 ||
4894  smtp_state->cmds_idx != 0 ||
4896  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4897  goto end;
4898  }
4899 
4900  /* Enable mime decoding */
4905 
4906  FLOWLOCK_WRLOCK(&f);
4907  /* DATA request */
4908  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4909  STREAM_TOSERVER, request4, request4_len);
4910  if (r != 0) {
4911  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4912  FLOWLOCK_UNLOCK(&f);
4913  goto end;
4914  }
4915  FLOWLOCK_UNLOCK(&f);
4916 
4917  if (smtp_state->input_len != 0 ||
4918  smtp_state->cmds_cnt != 1 ||
4919  smtp_state->cmds_idx != 0 ||
4920  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
4922  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4923  goto end;
4924  }
4925 
4926  FLOWLOCK_WRLOCK(&f);
4927  /* Data reply */
4928  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4929  STREAM_TOCLIENT, reply4, reply4_len);
4930  if (r != 0) {
4931  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4932  FLOWLOCK_UNLOCK(&f);
4933  goto end;
4934  }
4935  FLOWLOCK_UNLOCK(&f);
4936  if (smtp_state->input_len != 0 ||
4937  smtp_state->cmds_cnt != 0 ||
4938  smtp_state->cmds_idx != 0 ||
4941  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4942  goto end;
4943  }
4944 
4945  FLOWLOCK_WRLOCK(&f);
4946  /* DATA message */
4947  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4948  STREAM_TOSERVER, request4_msg, request4_msg_len);
4949  if (r != 0) {
4950  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4951  FLOWLOCK_UNLOCK(&f);
4952  goto end;
4953  }
4954  FLOWLOCK_UNLOCK(&f);
4955 
4956  if (smtp_state->input_len != 0 ||
4957  smtp_state->cmds_cnt != 0 ||
4958  smtp_state->cmds_idx != 0 ||
4959  smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */
4962  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4963  goto end;
4964  }
4965 
4966  FLOWLOCK_WRLOCK(&f);
4967  /* DATA . request */
4968  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4969  STREAM_TOSERVER, request4_end, request4_end_len);
4970  if (r != 0) {
4971  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4972  FLOWLOCK_UNLOCK(&f);
4973  goto end;
4974  }
4975  FLOWLOCK_UNLOCK(&f);
4976 
4977  if (smtp_state->input_len != 0 ||
4978  smtp_state->cmds_cnt != 1 ||
4979  smtp_state->cmds_idx != 0 ||
4980  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
4981  smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */
4983  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4984  goto end;
4985  }
4986 
4987  SMTPState *state = (SMTPState *) f.alstate;
4988  FileContainer *files = state->files_ts;
4989  if (files != NULL && files->head != NULL) {
4990  File *file = files->head;
4991 
4992  if(strncmp((const char *)file->name, "test.exe", 8) != 0){
4993  printf("smtp-mime file name is incorrect");
4994  goto end;
4995  }
4996  if (FileTrackedSize(file) != filesize){
4997  printf("smtp-mime file size %"PRIu64" is incorrect", FileDataSize(file));
4998  goto end;
4999  }
5000  static uint8_t org_binary[] = {
5001  0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00,
5002  0x4C, 0x01, 0x01, 0x00, 0x6A, 0x2A, 0x58, 0xC3,
5003  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5004  0x04, 0x00, 0x03, 0x01, 0x0B, 0x01, 0x08, 0x00,
5005  0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
5006  0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
5007  0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
5008  0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00,
5009  0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00,
5010  0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
5011  0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00,
5012  0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5013  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5014  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5015  0x00, 0x00, 0x00, 0x00, 0x5C, 0x5C, 0x36, 0x36,
5016  0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36,
5017  0x5C, 0x7A, 0x00, 0x00, 0x38,};
5018 
5020  org_binary, sizeof(org_binary)) != 1)
5021  {
5022  printf("smtp-mime file data incorrect\n");
5023  goto end;
5024  }
5025  }
5026 
5027  FLOWLOCK_WRLOCK(&f);
5028  /* DATA . reply */
5029  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
5030  STREAM_TOCLIENT, reply4_end, reply4_end_len);
5031  if (r != 0) {
5032  printf("smtp check returned %" PRId32 ", expected 0: ", r);
5033  FLOWLOCK_UNLOCK(&f);
5034  goto end;
5035  }
5036  FLOWLOCK_UNLOCK(&f);
5037  if (smtp_state->input_len != 0 ||
5038  smtp_state->cmds_cnt != 0 ||
5039  smtp_state->cmds_idx != 0 ||
5041  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
5042  goto end;
5043  }
5044 
5045  FLOWLOCK_WRLOCK(&f);
5046  /* QUIT Request */
5047  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
5048  STREAM_TOSERVER, request5, request5_len);
5049  if (r != 0) {
5050  printf("smtp check returned %" PRId32 ", expected 0: ", r);
5051  FLOWLOCK_UNLOCK(&f);
5052  goto end;
5053  }
5054  FLOWLOCK_UNLOCK(&f);
5055  if (smtp_state->input_len != 0 ||
5056  smtp_state->cmds_cnt != 1 ||
5057  smtp_state->cmds_idx != 0 ||
5058  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
5060  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
5061  goto end;
5062  }
5063 
5064  FLOWLOCK_WRLOCK(&f);
5065  /* QUIT Reply */
5066  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
5067  STREAM_TOCLIENT, reply5, reply5_len);
5068  if (r != 0) {
5069  printf("smtp check returned %" PRId32 ", expected 0: ", r);
5070  FLOWLOCK_UNLOCK(&f);
5071  goto end;
5072  }
5073  FLOWLOCK_UNLOCK(&f);
5074  if (smtp_state->input_len != 0 ||
5075  smtp_state->cmds_cnt != 0 ||
5076  smtp_state->cmds_idx != 0 ||
5078  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
5079  goto end;
5080  }
5081 
5082  result = 1;
5083 end:
5084  if (alp_tctx != NULL)
5087  FLOW_DESTROY(&f);
5088  return result;
5089 }
5090 
5091 static int SMTPProcessDataChunkTest01(void){
5092  Flow f;
5093  FLOW_INITIALIZE(&f);
5095  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5096  int ret;
5097  ret = SMTPProcessDataChunk(NULL, 0, state);
5098 
5099  return ret == 0;
5100 }
5101 
5102 
5103 static int SMTPProcessDataChunkTest02(void){
5104  char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
5105  0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
5106  0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
5107  0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
5108  0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
5109  0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
5110  0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
5111  0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
5112  0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
5113  0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
5114  0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
5115  0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
5116  0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
5117  0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
5118  0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
5119  0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
5120  0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
5121  0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
5122  0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
5123  0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
5124  0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
5125  0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
5126  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
5127  0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
5128  0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
5129  0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
5130  0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
5131  0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
5132  0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
5133  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
5134  0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
5135  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
5136  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
5137  0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
5138  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
5139  0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
5140  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
5141  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
5142  0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
5143  0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
5144  0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
5145  0x41, 0x3D, 0x3D, 0x0D, 0x0A,};
5146 
5147  Flow f;
5148  TcpSession ssn;
5149  memset(&ssn, 0, sizeof(ssn));
5150  FLOW_INITIALIZE(&f);
5151  f.protoctx = &ssn;
5153  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5154  ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
5155  state->body_begin = 1;
5156  int ret;
5157  ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
5158 
5159  return ret == 0;
5160 }
5161 
5162 
5163 
5164 static int SMTPProcessDataChunkTest03(void){
5165  char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, };
5166  char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, };
5167  char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5168  char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, };
5169  char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, };
5170  char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, };
5171  char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, };
5172  char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5173  char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, };
5174  char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, };
5175  char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, };
5176  char mimemsg12[] = {0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F, };
5177 
5178  TcpSession ssn;
5179  memset(&ssn, 0, sizeof(ssn));
5180  Flow f;
5181  FLOW_INITIALIZE(&f);
5182  f.protoctx = &ssn;
5184  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5185  ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
5186  int ret;
5187 
5188  state->body_begin = 1;
5189  ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
5190  if(ret) goto end;
5191  state->body_begin = 0;
5192  ret = SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state);
5193  if(ret) goto end;
5194  ret = SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state);
5195  if(ret) goto end;
5196  ret = SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state);
5197  if(ret) goto end;
5198  ret = SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state);
5199  if(ret) goto end;
5200  ret = SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state);
5201  if(ret) goto end;
5202  ret = SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state);
5203  if(ret) goto end;
5204  ret = SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state);
5205  if(ret) goto end;
5206  ret = SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state);
5207  if(ret) goto end;
5208  ret = SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state);
5209  if(ret) goto end;
5210  ret = SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state);
5211  if(ret) goto end;
5212  state->body_end = 1;
5213  ret = SMTPProcessDataChunk((uint8_t *)mimemsg12, sizeof(mimemsg12), state);
5214  if(ret) goto end;
5215 
5216  end:
5217  return ret == 0;
5218 }
5219 
5220 
5221 static int SMTPProcessDataChunkTest04(void){
5222  char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, };
5223  char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, };
5224  char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5225  char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, };
5226  char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, };
5227  char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, };
5228  char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, };
5229  char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5230  char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, };
5231  char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, };
5232  char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, };
5233 
5234  TcpSession ssn;
5235  memset(&ssn, 0, sizeof(ssn));
5236  Flow f;
5237  FLOW_INITIALIZE(&f);
5238  f.protoctx = &ssn;
5240  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5241  ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
5242  int ret = MIME_DEC_OK;
5243 
5244  state->body_begin = 1;
5245  if(SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state) != 0) goto end;
5246  if(SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state) != 0) goto end;
5247  if(SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state) != 0) goto end;
5248  if(SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state) != 0) goto end;
5249  if(SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state) != 0) goto end;
5250  if(SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state) != 0) goto end;
5251  if(SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state) != 0) goto end;
5252  state->body_begin = 0;
5253  state->body_end = 1;
5254  if(SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state) != 0) goto end;
5255  state->body_end = 0;
5256  if(SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state) != 0) goto end;
5257  if(SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state) != 0) goto end;
5258  if(SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state) != 0) goto end;
5259 
5260  end:
5261  return ret == 0;
5262 }
5263 
5264 static int SMTPProcessDataChunkTest05(void){
5265  char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
5266  0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
5267  0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
5268  0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
5269  0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
5270  0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
5271  0x41, 0x3D, 0x3D, 0x0D, 0x0A,};
5272 
5273  TcpSession ssn;
5274  memset(&ssn, 0, sizeof(ssn));
5275  Flow f;
5276  int ret;
5277  FLOW_INITIALIZE(&f);
5278  f.protoctx = &ssn;
5280  FAIL_IF(f.alstate == NULL);
5281  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5282  ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
5283  FAIL_IF(state == NULL);
5284  state->body_begin = 1;
5285  ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
5286  FAIL_IF(ret != 0);
5287  state->body_begin = 0;
5288  SMTPState *smtp_state = (SMTPState *)((Flow *)state->data)->alstate;
5289  FileContainer *files = smtp_state->files_ts;
5290  FAIL_IF(files == NULL);
5291  File *file = files->head;
5292  FAIL_IF(file == NULL);
5293  ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
5294  FAIL_IF(ret != 0);
5295  FAIL_IF((uint32_t)FileDataSize(file) != 106);
5296  SMTPStateFree(smtp_state);
5297  FLOW_DESTROY(&f);
5298  PASS;
5299 }
5300 
5301 #endif /* UNITTESTS */
5302 
5304 {
5305 #ifdef UNITTESTS
5306  UtRegisterTest("SMTPParserTest01", SMTPParserTest01);
5307  UtRegisterTest("SMTPParserTest02", SMTPParserTest02);
5308  UtRegisterTest("SMTPParserTest03", SMTPParserTest03);
5309  UtRegisterTest("SMTPParserTest04", SMTPParserTest04);
5310  UtRegisterTest("SMTPParserTest05", SMTPParserTest05);
5311  UtRegisterTest("SMTPParserTest06", SMTPParserTest06);
5312  UtRegisterTest("SMTPParserTest07", SMTPParserTest07);
5313  UtRegisterTest("SMTPParserTest08", SMTPParserTest08);
5314  UtRegisterTest("SMTPParserTest09", SMTPParserTest09);
5315  UtRegisterTest("SMTPParserTest10", SMTPParserTest10);
5316  UtRegisterTest("SMTPParserTest11", SMTPParserTest11);
5317  UtRegisterTest("SMTPParserTest12", SMTPParserTest12);
5318  UtRegisterTest("SMTPParserTest13", SMTPParserTest13);
5319  UtRegisterTest("SMTPParserTest14", SMTPParserTest14);
5320  UtRegisterTest("SMTPProcessDataChunkTest01", SMTPProcessDataChunkTest01);
5321  UtRegisterTest("SMTPProcessDataChunkTest02", SMTPProcessDataChunkTest02);
5322  UtRegisterTest("SMTPProcessDataChunkTest03", SMTPProcessDataChunkTest03);
5323  UtRegisterTest("SMTPProcessDataChunkTest04", SMTPProcessDataChunkTest04);
5324  UtRegisterTest("SMTPProcessDataChunkTest05", SMTPProcessDataChunkTest05);
5325 #endif /* UNITTESTS */
5326 
5327  return;
5328 }
MpmInitThreadCtx
void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher)
Definition: util-mpm.c:256
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:45
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:2517
AppLayerParserRegisterGetStateProgressFunc
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, int(*StateGetProgress)(void *alstate, uint8_t direction))
Definition: app-layer-parser.c:476
FileContainer_
Definition: util-file.h:107
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
SMTPCode
SMTPCode
Definition: app-layer-smtp.c:174
DetectEngineStateDirection_::flags
uint8_t flags
Definition: detect-engine-state.h:89
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:1812
SMTPState_::cmds_cnt
uint16_t cmds_cnt
Definition: app-layer-smtp.h:158
SMTP_DECODER_EVENT_TLS_REJECTED
@ SMTP_DECODER_EVENT_TLS_REJECTED
Definition: app-layer-smtp.h:41
StreamingBufferConfig_::buf_size
uint32_t buf_size
Definition: util-streaming-buffer.h:70
PKT_HAS_FLOW
#define PKT_HAS_FLOW
Definition: decode.h:1126
SMTP_DECODER_EVENT_MIME_MALFORMED_MSG
@ SMTP_DECODER_EVENT_MIME_MALFORMED_MSG
Definition: app-layer-smtp.h:46
AppLayerParserRegisterLocalStorageFunc
void AppLayerParserRegisterLocalStorageFunc(uint8_t ipproto, AppProto alproto, void *(*LocalStorageAlloc)(void), void(*LocalStorageFree)(void *))
Definition: app-layer-parser.c:412
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
SMTP_DECODER_EVENT_MIME_INVALID_QP
@ SMTP_DECODER_EVENT_MIME_INVALID_QP
Definition: app-layer-smtp.h:48
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:426
DetectEngineState_
Definition: detect-engine-state.h:93
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
SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED
@ SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED
Definition: app-layer-smtp.h:36
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:208
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:2585
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:261
Flow_::proto
uint8_t proto
Definition: flow.h:372
SMTPState_::tc_db
uint8_t * tc_db
Definition: app-layer-smtp.h:128
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:77
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:302
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
AppLayerParserTriggerRawStreamReassembly
void AppLayerParserTriggerRawStreamReassembly(Flow *f, int direction)
Definition: app-layer-parser.c:1430
StreamTcpReassemblySetMinInspectDepth
void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
Definition: stream-tcp-reassemble.c:1963
STREAMING_BUFFER_CONFIG_INITIALIZER
#define STREAMING_BUFFER_CONFIG_INITIALIZER
Definition: util-streaming-buffer.h:77
Packet_::flags
uint32_t flags
Definition: decode.h:450
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:63
ANOM_LONG_LINE
#define ANOM_LONG_LINE
Definition: util-decode-mime.h:58
Flow_
Flow data structure.
Definition: flow.h:350
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
AppLayerParserRegisterGetEventsFunc
void AppLayerParserRegisterGetEventsFunc(uint8_t ipproto, AppProto alproto, AppLayerDecoderEvents *(*StateGetEvents)(void *))
Definition: app-layer-parser.c:437
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:466
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:755
AppLayerParserRegisterStateProgressCompletionStatus
void AppLayerParserRegisterStateProgressCompletionStatus(AppProto alproto, const int ts, const int tc)
Definition: app-layer-parser.c:528
FILE_STORE
#define FILE_STORE
Definition: util-file.h:55
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:487
FileSetTx
int FileSetTx(File *ff, uint64_t txid)
Set the TX id for a file.
Definition: util-file.c:567
FLOW_NOPAYLOAD_INSPECTION
#define FLOW_NOPAYLOAD_INSPECTION
Definition: flow.h:65
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:2040
DetectEngineState_::dir_state
DetectEngineStateDirection dir_state[2]
Definition: detect-engine-state.h:94
AppLayerParserThreadCtxFree
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
Definition: app-layer-parser.c:279
SMTPState_::cmds_idx
uint16_t cmds_idx
Definition: app-layer-smtp.h:161
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:222
FileContainer_::tail
File * tail
Definition: util-file.h:109
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:567
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:135
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:2425
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
SMTPThreadCtx_
Definition: app-layer-smtp.c:163
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:446
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:448
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:720
SMTP_REPLY_251
@ SMTP_REPLY_251
Definition: app-layer-smtp.c:181
SMTPState_::direction
uint8_t direction
Definition: app-layer-smtp.h:117
SMTP_DECODER_EVENT_MIME_LONG_FILENAME
@ SMTP_DECODER_EVENT_MIME_LONG_FILENAME
Definition: app-layer-smtp.h:54
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:267
STREAM_START
#define STREAM_START
Definition: stream.h:29
File_::sb
StreamingBuffer * sb
Definition: util-file.h:76
util-memcmp.h
MimeDecParseState::body_begin
int body_begin
Definition: util-decode-mime.h:205
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
app-layer-detect-proto.h
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:1638
SMTP_DECODER_EVENT_INVALID_REPLY
@ SMTP_DECODER_EVENT_INVALID_REPLY
Definition: app-layer-smtp.h:34
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:155
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
FileFlowToFlags
uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction)
Definition: util-file.c:234
DetectEngineThreadCtx_
Definition: detect.h:999
FLOWFILE_NO_STORE_TS
#define FLOWFILE_NO_STORE_TS
Definition: flow.h:123
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:20
FLOWLOCK_WRLOCK
#define FLOWLOCK_WRLOCK(fb)
Definition: flow.h:264
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:426
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:108
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
SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE
@ SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE
Definition: app-layer-smtp.h:38
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:311
AppLayerParserRegisterStateFuncs
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void *, AppProto), void(*StateFree)(void *))
Definition: app-layer-parser.c:399
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_DECODER_EVENT_DATA_COMMAND_REJECTED
@ SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED
Definition: app-layer-smtp.h:42
SMTP_DECODER_EVENT_UNPARSABLE_CONTENT
@ SMTP_DECODER_EVENT_UNPARSABLE_CONTENT
Definition: app-layer-smtp.h:58
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
Definition: detect.c:1688
P