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  // copy in temporary null-terminated buffer to call strtoul
1112  char strbuf[24];
1113  int len = 23;
1114  if (state->current_line_len - i < len) {
1115  len = state->current_line_len - i;
1116  }
1117  memcpy(strbuf, (const char *)state->current_line + i, len);
1118  strbuf[len] = '\0';
1119  state->bdat_chunk_len = strtoul((const char *)strbuf,
1120  (char **)&endptr, 10);
1121  if ((uint8_t *)endptr == state->current_line + i) {
1122  /* decoder event */
1123  return -1;
1124  }
1125 
1126  return 0;
1127 }
1128 
1129 static int SMTPParseCommandWithParam(SMTPState *state, uint8_t prefix_len, uint8_t **target, uint16_t *target_len)
1130 {
1131  int i = prefix_len + 1;
1132  int spc_i = 0;
1133 
1134  while (i < state->current_line_len) {
1135  if (state->current_line[i] != ' ') {
1136  break;
1137  }
1138  i++;
1139  }
1140 
1141  /* rfc1870: with the size extension the mail from can be followed by an option.
1142  We use the space separator to detect it. */
1143  spc_i = i;
1144  while (spc_i < state->current_line_len) {
1145  if (state->current_line[spc_i] == ' ') {
1146  break;
1147  }
1148  spc_i++;
1149  }
1150 
1151  *target = SCMalloc(spc_i - i + 1);
1152  if (*target == NULL)
1153  return -1;
1154  memcpy(*target, state->current_line + i, spc_i - i);
1155  (*target)[spc_i - i] = '\0';
1156  *target_len = spc_i - i;
1157 
1158  return 0;
1159 }
1160 
1161 static int SMTPParseCommandHELO(SMTPState *state)
1162 {
1163  if (state->helo) {
1164  SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1165  return 0;
1166  }
1167  return SMTPParseCommandWithParam(state, 4, &state->helo, &state->helo_len);
1168 }
1169 
1170 static int SMTPParseCommandMAILFROM(SMTPState *state)
1171 {
1172  if (state->curr_tx->mail_from) {
1173  SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1174  return 0;
1175  }
1176  return SMTPParseCommandWithParam(state, 9,
1177  &state->curr_tx->mail_from,
1178  &state->curr_tx->mail_from_len);
1179 }
1180 
1181 static int SMTPParseCommandRCPTTO(SMTPState *state)
1182 {
1183  uint8_t *rcptto;
1184  uint16_t rcptto_len;
1185 
1186  if (SMTPParseCommandWithParam(state, 7, &rcptto, &rcptto_len) == 0) {
1187  SMTPString *rcptto_str = SMTPStringAlloc();
1188  if (rcptto_str) {
1189  rcptto_str->str = rcptto;
1190  rcptto_str->len = rcptto_len;
1191  TAILQ_INSERT_TAIL(&state->curr_tx->rcpt_to_list, rcptto_str, next);
1192  } else {
1193  SCFree(rcptto);
1194  return -1;
1195  }
1196  } else {
1197  return -1;
1198  }
1199  return 0;
1200 }
1201 
1202 /* consider 'rset' and 'quit' to be part of the existing state */
1203 static int NoNewTx(SMTPState *state)
1204 {
1206  if (state->current_line_len >= 4 &&
1207  SCMemcmpLowercase("rset", state->current_line, 4) == 0) {
1208  return 1;
1209  } else if (state->current_line_len >= 4 &&
1210  SCMemcmpLowercase("quit", state->current_line, 4) == 0) {
1211  return 1;
1212  }
1213  }
1214  return 0;
1215 }
1216 
1217 static int SMTPProcessRequest(SMTPState *state, Flow *f,
1218  AppLayerParserState *pstate)
1219 {
1220  SCEnter();
1221  SMTPTransaction *tx = state->curr_tx;
1222 
1223  if (state->curr_tx == NULL || (state->curr_tx->done && !NoNewTx(state))) {
1224  tx = SMTPTransactionCreate();
1225  if (tx == NULL)
1226  return -1;
1227  state->curr_tx = tx;
1228  TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
1229  tx->tx_id = state->tx_cnt++;
1230 
1231  /* keep track of the start of the tx */
1235  }
1236 
1237  state->toserver_data_count += (
1238  state->current_line_len +
1240 
1242  SMTPSetEvent(state, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE);
1243  }
1244 
1245  /* there are 2 commands that can push it into this COMMAND_DATA mode -
1246  * STARTTLS and DATA */
1248  int r = 0;
1249 
1250  if (state->current_line_len >= 8 &&
1251  SCMemcmpLowercase("starttls", state->current_line, 8) == 0) {
1253  } else if (state->current_line_len >= 4 &&
1254  SCMemcmpLowercase("data", state->current_line, 4) == 0) {
1257  const char *msgname = "rawmsg"; /* XXX have a better name */
1258  if (state->files_ts == NULL)
1259  state->files_ts = FileContainerAlloc();
1260  if (state->files_ts == NULL) {
1261  return -1;
1262  }
1263  if (state->tx_cnt > 1 && !state->curr_tx->done) {
1264  // we did not close the previous tx, set error
1265  SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT);
1266  FileCloseFile(state->files_ts, NULL, 0, FILE_TRUNCATED);
1267  tx = SMTPTransactionCreate();
1268  if (tx == NULL)
1269  return -1;
1270  state->curr_tx = tx;
1271  TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
1272  tx->tx_id = state->tx_cnt++;
1273  }
1275  state->file_track_id++,
1276  (uint8_t*) msgname, strlen(msgname), NULL, 0,
1278  SMTPNewFile(state->curr_tx, state->files_ts->tail);
1279  }
1280  } else if (smtp_config.decode_mime) {
1281  if (tx->mime_state) {
1282  /* We have 2 chained mails and did not detect the end
1283  * of first one. So we start a new transaction. */
1285  SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT);
1286  tx = SMTPTransactionCreate();
1287  if (tx == NULL)
1288  return -1;
1289  state->curr_tx = tx;
1290  TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
1291  tx->tx_id = state->tx_cnt++;
1292  }
1294  if (tx->mime_state == NULL) {
1295  SCLogError(SC_ERR_MEM_ALLOC, "MimeDecInitParser() failed to "
1296  "allocate data");
1297  return MIME_DEC_ERR_MEM;
1298  }
1299 
1300  /* Add new MIME message to end of list */
1301  if (tx->msg_head == NULL) {
1302  tx->msg_head = tx->mime_state->msg;
1303  tx->msg_tail = tx->mime_state->msg;
1304  }
1305  else {
1306  tx->msg_tail->next = tx->mime_state->msg;
1307  tx->msg_tail = tx->mime_state->msg;
1308  }
1309  }
1310  /* Enter immediately data mode without waiting for server reply */
1313  }
1314  } else if (state->current_line_len >= 4 &&
1315  SCMemcmpLowercase("bdat", state->current_line, 4) == 0) {
1316  r = SMTPParseCommandBDAT(state);
1317  if (r == -1) {
1318  SCReturnInt(-1);
1319  }
1322  } else if (state->current_line_len >= 4 &&
1323  ((SCMemcmpLowercase("helo", state->current_line, 4) == 0) ||
1324  SCMemcmpLowercase("ehlo", state->current_line, 4) == 0)) {
1325  r = SMTPParseCommandHELO(state);
1326  if (r == -1) {
1327  SCReturnInt(-1);
1328  }
1330  } else if (state->current_line_len >= 9 &&
1331  SCMemcmpLowercase("mail from", state->current_line, 9) == 0) {
1332  r = SMTPParseCommandMAILFROM(state);
1333  if (r == -1) {
1334  SCReturnInt(-1);
1335  }
1337  } else if (state->current_line_len >= 7 &&
1338  SCMemcmpLowercase("rcpt to", state->current_line, 7) == 0) {
1339  r = SMTPParseCommandRCPTTO(state);
1340  if (r == -1) {
1341  SCReturnInt(-1);
1342  }
1344  } else if (state->current_line_len >= 4 &&
1345  SCMemcmpLowercase("rset", state->current_line, 4) == 0) {
1346  // Resets chunk index in case of connection reuse
1347  state->bdat_chunk_idx = 0;
1349  } else {
1351  }
1352 
1353  /* Every command is inserted into a command buffer, to be matched
1354  * against reply(ies) sent by the server */
1355  if (SMTPInsertCommandIntoCommandBuffer(state->current_command,
1356  state, f) == -1) {
1357  SCReturnInt(-1);
1358  }
1359 
1360  SCReturnInt(r);
1361  }
1362 
1363  switch (state->current_command) {
1364  case SMTP_COMMAND_STARTTLS:
1365  return SMTPProcessCommandSTARTTLS(state, f, pstate);
1366 
1367  case SMTP_COMMAND_DATA:
1368  return SMTPProcessCommandDATA(state, f, pstate);
1369 
1370  case SMTP_COMMAND_BDAT:
1371  return SMTPProcessCommandBDAT(state, f, pstate);
1372 
1373  default:
1374  /* we have nothing to do with any other command at this instant.
1375  * Just let it go through */
1376  SCReturnInt(0);
1377  }
1378 }
1379 
1380 static AppLayerResult SMTPParse(int direction, Flow *f, SMTPState *state,
1381  AppLayerParserState *pstate, const uint8_t *input,
1382  uint32_t input_len,
1383  SMTPThreadCtx *thread_data)
1384 {
1385  SCEnter();
1386 
1387  if (input == NULL &&
1388  ((direction == 0 && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) ||
1389  (direction == 1 && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC)))) {
1391  } else if (input == NULL || input_len == 0) {
1393  }
1394 
1395  state->input = input;
1396  state->input_len = input_len;
1397  state->direction = direction;
1398 
1399  /* toserver */
1400  if (direction == 0) {
1401  while (SMTPGetLine(state) >= 0) {
1402  if (SMTPProcessRequest(state, f, pstate) == -1)
1404  }
1405 
1406  /* toclient */
1407  } else {
1408  while (SMTPGetLine(state) >= 0) {
1409  if (SMTPProcessReply(state, f, pstate, thread_data) == -1)
1411  }
1412  }
1413 
1415 }
1416 
1417 static AppLayerResult SMTPParseClientRecord(Flow *f, void *alstate,
1418  AppLayerParserState *pstate,
1419  const uint8_t *input, uint32_t input_len,
1420  void *local_data, const uint8_t flags)
1421 {
1422  SCEnter();
1423 
1424  /* first arg 0 is toserver */
1425  return SMTPParse(0, f, alstate, pstate, input, input_len, local_data);
1426 }
1427 
1428 static AppLayerResult SMTPParseServerRecord(Flow *f, void *alstate,
1429  AppLayerParserState *pstate,
1430  const uint8_t *input, uint32_t input_len,
1431  void *local_data, const uint8_t flags)
1432 {
1433  SCEnter();
1434 
1435  /* first arg 1 is toclient */
1436  return SMTPParse(1, f, alstate, pstate, input, input_len, local_data);
1437 }
1438 
1439 /**
1440  * \internal
1441  * \brief Function to allocate SMTP state memory.
1442  */
1443 void *SMTPStateAlloc(void *orig_state, AppProto proto_orig)
1444 {
1445  SMTPState *smtp_state = SCMalloc(sizeof(SMTPState));
1446  if (unlikely(smtp_state == NULL))
1447  return NULL;
1448  memset(smtp_state, 0, sizeof(SMTPState));
1449 
1450  smtp_state->cmds = SCMalloc(sizeof(uint8_t) *
1452  if (smtp_state->cmds == NULL) {
1453  SCFree(smtp_state);
1454  return NULL;
1455  }
1457 
1458  TAILQ_INIT(&smtp_state->tx_list);
1459 
1460  return smtp_state;
1461 }
1462 
1463 static SMTPString *SMTPStringAlloc(void)
1464 {
1465  SMTPString *smtp_string = SCMalloc(sizeof(SMTPString));
1466  if (unlikely(smtp_string == NULL))
1467  return NULL;
1468  memset(smtp_string, 0, sizeof(SMTPString));
1469 
1470  return smtp_string;
1471 }
1472 
1473 
1474 static void SMTPStringFree(SMTPString *str)
1475 {
1476  if (str->str) {
1477  SCFree(str->str);
1478  }
1479  SCFree(str);
1480 }
1481 
1482 static void *SMTPLocalStorageAlloc(void)
1483 {
1484  /* needed by the mpm */
1485  SMTPThreadCtx *td = SCCalloc(1, sizeof(*td));
1486  if (td == NULL) {
1487  exit(EXIT_FAILURE);
1488  }
1489 
1490  td->pmq = SCCalloc(1, sizeof(*td->pmq));
1491  if (td->pmq == NULL) {
1492  exit(EXIT_FAILURE);
1493  }
1494  PmqSetup(td->pmq);
1495 
1496  td->smtp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx));
1497  if (unlikely(td->smtp_mpm_thread_ctx == NULL)) {
1498  exit(EXIT_FAILURE);
1499  }
1501  return td;
1502 }
1503 
1504 static void SMTPLocalStorageFree(void *ptr)
1505 {
1506  SMTPThreadCtx *td = ptr;
1507  if (td != NULL) {
1508  if (td->pmq != NULL) {
1509  PmqFree(td->pmq);
1510  SCFree(td->pmq);
1511  }
1512 
1513  if (td->smtp_mpm_thread_ctx != NULL) {
1516  }
1517 
1518  SCFree(td);
1519  }
1520 
1521  return;
1522 }
1523 
1524 static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state)
1525 {
1526  if (tx->mime_state != NULL) {
1528  }
1529  /* Free list of MIME message recursively */
1531 
1532  if (tx->decoder_events != NULL)
1534 
1535  if (tx->de_state != NULL)
1537 
1538  if (tx->mail_from)
1539  SCFree(tx->mail_from);
1540 
1541  SMTPString *str = NULL;
1542  while ((str = TAILQ_FIRST(&tx->rcpt_to_list))) {
1543  TAILQ_REMOVE(&tx->rcpt_to_list, str, next);
1544  SMTPStringFree(str);
1545  }
1546 #if 0
1547  if (tx->decoder_events->cnt <= smtp_state->events)
1548  smtp_state->events -= tx->decoder_events->cnt;
1549  else
1550  smtp_state->events = 0;
1551 #endif
1552  SCFree(tx);
1553 }
1554 
1555 /**
1556  * \internal
1557  * \brief Function to free SMTP state memory.
1558  */
1559 static void SMTPStateFree(void *p)
1560 {
1561  SMTPState *smtp_state = (SMTPState *)p;
1562 
1563  if (smtp_state->cmds != NULL) {
1564  SCFree(smtp_state->cmds);
1565  }
1566  if (smtp_state->ts_current_line_db) {
1567  SCFree(smtp_state->ts_db);
1568  }
1569  if (smtp_state->tc_current_line_db) {
1570  SCFree(smtp_state->tc_db);
1571  }
1572 
1573  if (smtp_state->helo) {
1574  SCFree(smtp_state->helo);
1575  }
1576 
1577  FileContainerFree(smtp_state->files_ts);
1578 
1579  SMTPTransaction *tx = NULL;
1580  while ((tx = TAILQ_FIRST(&smtp_state->tx_list))) {
1581  TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1582  SMTPTransactionFree(tx, smtp_state);
1583  }
1584 
1585  SCFree(smtp_state);
1586 
1587  return;
1588 }
1589 
1590 static void SMTPSetMpmState(void)
1591 {
1592  smtp_mpm_ctx = SCMalloc(sizeof(MpmCtx));
1593  if (unlikely(smtp_mpm_ctx == NULL)) {
1594  exit(EXIT_FAILURE);
1595  }
1596  memset(smtp_mpm_ctx, 0, sizeof(MpmCtx));
1597  MpmInitCtx(smtp_mpm_ctx, SMTP_MPM);
1598 
1599  uint32_t i = 0;
1600  for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) {
1601  SCEnumCharMap *map = &smtp_reply_map[i];
1602  /* The third argument is 3, because reply code is always 3 bytes. */
1603  MpmAddPatternCI(smtp_mpm_ctx, (uint8_t *)map->enum_name, 3,
1604  0 /* defunct */, 0 /* defunct */,
1605  i /* pattern id */, i /* rule id */ , 0 /* no flags */);
1606  }
1607 
1608  mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx);
1609 
1610 }
1611 
1612 static void SMTPFreeMpmState(void)
1613 {
1614  if (smtp_mpm_ctx != NULL) {
1615  mpm_table[SMTP_MPM].DestroyCtx(smtp_mpm_ctx);
1616  SCFree(smtp_mpm_ctx);
1617  smtp_mpm_ctx = NULL;
1618  }
1619 }
1620 
1621 static int SMTPStateGetEventInfo(const char *event_name,
1622  int *event_id, AppLayerEventType *event_type)
1623 {
1624  *event_id = SCMapEnumNameToValue(event_name, smtp_decoder_event_table);
1625  if (*event_id == -1) {
1626  SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
1627  "smtp's enum map table.", event_name);
1628  /* yes this is fatal */
1629  return -1;
1630  }
1631 
1632  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
1633 
1634  return 0;
1635 }
1636 
1637 static int SMTPStateGetEventInfoById(int event_id, const char **event_name,
1638  AppLayerEventType *event_type)
1639 {
1640  *event_name = SCMapEnumValueToName(event_id, smtp_decoder_event_table);
1641  if (*event_name == NULL) {
1642  SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%d\" not present in "
1643  "smtp's enum map table.", event_id);
1644  /* yes this is fatal */
1645  return -1;
1646  }
1647 
1648  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
1649 
1650  return 0;
1651 }
1652 
1653 static int SMTPRegisterPatternsForProtocolDetection(void)
1654 {
1656  "EHLO", 4, 0, STREAM_TOSERVER) < 0)
1657  {
1658  return -1;
1659  }
1661  "HELO", 4, 0, STREAM_TOSERVER) < 0)
1662  {
1663  return -1;
1664  }
1666  "QUIT", 4, 0, STREAM_TOSERVER) < 0)
1667  {
1668  return -1;
1669  }
1670 
1671  return 0;
1672 }
1673 
1674 static void SMTPStateTransactionFree (void *state, uint64_t tx_id)
1675 {
1676  SMTPState *smtp_state = state;
1677  SMTPTransaction *tx = NULL;
1678  TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
1679  if (tx_id < tx->tx_id)
1680  break;
1681  else if (tx_id > tx->tx_id)
1682  continue;
1683 
1684  if (tx == smtp_state->curr_tx)
1685  smtp_state->curr_tx = NULL;
1686  TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1687  SMTPTransactionFree(tx, state);
1688  break;
1689  }
1690 
1691 
1692 }
1693 
1694 /** \retval cnt highest tx id */
1695 static uint64_t SMTPStateGetTxCnt(void *state)
1696 {
1697  uint64_t cnt = 0;
1698  SMTPState *smtp_state = state;
1699  if (smtp_state) {
1700  cnt = smtp_state->tx_cnt;
1701  }
1702  SCLogDebug("returning %"PRIu64, cnt);
1703  return cnt;
1704 }
1705 
1706 static void *SMTPStateGetTx(void *state, uint64_t id)
1707 {
1708  SMTPState *smtp_state = state;
1709  if (smtp_state) {
1710  SMTPTransaction *tx = NULL;
1711 
1712  if (smtp_state->curr_tx == NULL)
1713  return NULL;
1714  if (smtp_state->curr_tx->tx_id == id)
1715  return smtp_state->curr_tx;
1716 
1717  TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
1718  if (tx->tx_id == id)
1719  return tx;
1720  }
1721  }
1722  return NULL;
1723 
1724 }
1725 
1726 static int SMTPStateGetAlstateProgress(void *vtx, uint8_t direction)
1727 {
1728  SMTPTransaction *tx = vtx;
1729  return tx->done;
1730 }
1731 
1732 static FileContainer *SMTPStateGetFiles(void *state, uint8_t direction)
1733 {
1734  if (state == NULL)
1735  return NULL;
1736 
1737  SMTPState *smtp_state = (SMTPState *)state;
1738 
1739  if (direction & STREAM_TOCLIENT) {
1740  SCReturnPtr(NULL, "FileContainer");
1741  } else {
1742  SCLogDebug("smtp_state->files_ts %p", smtp_state->files_ts);
1743  SCReturnPtr(smtp_state->files_ts, "FileContainer");
1744  }
1745 }
1746 
1747 static void SMTPStateTruncate(void *state, uint8_t direction)
1748 {
1749  FileContainer *fc = SMTPStateGetFiles(state, direction);
1750  if (fc != NULL) {
1751  SCLogDebug("truncating stream, closing files in %s direction (container %p)",
1752  direction & STREAM_TOCLIENT ? "STREAM_TOCLIENT" : "STREAM_TOSERVER", fc);
1754  }
1755 }
1756 
1757 static AppLayerDecoderEvents *SMTPGetEvents(void *tx)
1758 {
1759  SCLogDebug("get SMTP events for TX %p", tx);
1760 
1761  return ((SMTPTransaction *)tx)->decoder_events;
1762 }
1763 
1764 static DetectEngineState *SMTPGetTxDetectState(void *vtx)
1765 {
1766  SMTPTransaction *tx = (SMTPTransaction *)vtx;
1767  return tx->de_state;
1768 }
1769 
1770 static int SMTPSetTxDetectState(void *vtx, DetectEngineState *s)
1771 {
1772  SMTPTransaction *tx = (SMTPTransaction *)vtx;
1773  tx->de_state = s;
1774  return 0;
1775 }
1776 
1777 static AppLayerTxData *SMTPGetTxData(void *vtx)
1778 {
1779  SMTPTransaction *tx = (SMTPTransaction *)vtx;
1780  return &tx->tx_data;
1781 }
1782 
1783 /**
1784  * \brief Register the SMTP Protocol parser.
1785  */
1787 {
1788  const char *proto_name = "smtp";
1789 
1790  if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
1792  if (SMTPRegisterPatternsForProtocolDetection() < 0 )
1793  return;
1794  } else {
1795  SCLogInfo("Protocol detection and parser disabled for %s protocol.",
1796  proto_name);
1797  return;
1798  }
1799 
1800  if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
1801  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree);
1802 
1804  SMTPParseClientRecord);
1806  SMTPParseServerRecord);
1807 
1808  AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo);
1809  AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfoById);
1810  AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetEvents);
1812  SMTPGetTxDetectState, SMTPSetTxDetectState);
1813 
1814  AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc,
1815  SMTPLocalStorageFree);
1816 
1817  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTransactionFree);
1818  AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetFiles);
1819  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress);
1820  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt);
1821  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx);
1822  AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxData);
1824  AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTruncate);
1825  } else {
1826  SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
1827  "still on.", proto_name);
1828  }
1829 
1830  SMTPSetMpmState();
1831 
1832  SMTPConfigure();
1833 
1834 #ifdef UNITTESTS
1836 #endif
1837  return;
1838 }
1839 
1840 /**
1841  * \brief Free memory allocated for global SMTP parser state.
1842  */
1844 {
1845  SMTPFreeMpmState();
1846 }
1847 
1848 /***************************************Unittests******************************/
1849 
1850 #ifdef UNITTESTS
1851 
1852 static void SMTPTestInitConfig(void)
1853 {
1855 
1859 
1861 }
1862 
1863 /*
1864  * \test Test STARTTLS.
1865  */
1866 static int SMTPParserTest01(void)
1867 {
1868  int result = 0;
1869  Flow f;
1870  int r = 0;
1871 
1872  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
1873  uint8_t welcome_reply[] = {
1874  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
1875  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1876  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
1877  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
1878  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
1879  0x0d, 0x0a
1880  };
1881  uint32_t welcome_reply_len = sizeof(welcome_reply);
1882 
1883  /* EHLO [192.168.0.158]<CR><LF> */
1884  uint8_t request1[] = {
1885  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39,
1886  0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e,
1887  0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a
1888  };
1889  uint32_t request1_len = sizeof(request1);
1890  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
1891  * 250-SIZE 35882577<CR><LF>
1892  * 250-8BITMIME<CR><LF>
1893  * 250-STARTTLS<CR><LF>
1894  * 250 ENHANCEDSTATUSCODES<CR><LF>
1895  */
1896  uint8_t reply1[] = {
1897  0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67,
1898  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1899  0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75,
1900  0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
1901  0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e,
1902  0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e,
1903  0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30,
1904  0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35,
1905  0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a,
1906  0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54,
1907  0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35,
1908  0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54,
1909  0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20,
1910  0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44,
1911  0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f,
1912  0x44, 0x45, 0x53, 0x0d, 0x0a
1913  };
1914  uint32_t reply1_len = sizeof(reply1);
1915 
1916  /* STARTTLS<CR><LF> */
1917  uint8_t request2[] = {
1918  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
1919  0x0d, 0x0a
1920  };
1921  uint32_t request2_len = sizeof(request2);
1922  /* 220 2.0.0 Ready to start TLS<CR><LF> */
1923  uint8_t reply2[] = {
1924  0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1925  0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20,
1926  0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74,
1927  0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a
1928  };
1929  uint32_t reply2_len = sizeof(reply2);
1930 
1931  TcpSession ssn;
1933 
1934  memset(&f, 0, sizeof(f));
1935  memset(&ssn, 0, sizeof(ssn));
1936 
1937  FLOW_INITIALIZE(&f);
1938  f.protoctx = (void *)&ssn;
1939  f.proto = IPPROTO_TCP;
1940  f.alproto = ALPROTO_SMTP;
1941 
1942  StreamTcpInitConfig(true);
1943  SMTPTestInitConfig();
1944 
1945  FLOWLOCK_WRLOCK(&f);
1946  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1947  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
1948  if (r != 0) {
1949  printf("smtp check returned %" PRId32 ", expected 0: ", r);
1950  FLOWLOCK_UNLOCK(&f);
1951  goto end;
1952  }
1953  FLOWLOCK_UNLOCK(&f);
1954  SMTPState *smtp_state = f.alstate;
1955  if (smtp_state == NULL) {
1956  printf("no smtp state: ");
1957  goto end;
1958  }
1959  if (smtp_state->input_len != 0 ||
1960  smtp_state->cmds_cnt != 0 ||
1961  smtp_state->cmds_idx != 0 ||
1963  printf("smtp parser in inconsistent state\n");
1964  goto end;
1965  }
1966 
1967  FLOWLOCK_WRLOCK(&f);
1968  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1969  STREAM_TOSERVER, request1, request1_len);
1970  if (r != 0) {
1971  printf("smtp check returned %" PRId32 ", expected 0: ", r);
1972  FLOWLOCK_UNLOCK(&f);
1973  goto end;
1974  }
1975  FLOWLOCK_UNLOCK(&f);
1976  if (smtp_state->input_len != 0 ||
1977  smtp_state->cmds_cnt != 1 ||
1978  smtp_state->cmds_idx != 0 ||
1979  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1981  printf("smtp parser in inconsistent state\n");
1982  goto end;
1983  }
1984 
1985  FLOWLOCK_WRLOCK(&f);
1986  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1987  STREAM_TOCLIENT, reply1, reply1_len);
1988  if (r != 0) {
1989  printf("smtp check returned %" PRId32 ", expected 0: ", r);
1990  FLOWLOCK_UNLOCK(&f);
1991  goto end;
1992  }
1993  FLOWLOCK_UNLOCK(&f);
1994  if (smtp_state->input_len != 0 ||
1995  smtp_state->cmds_cnt != 0 ||
1996  smtp_state->cmds_idx != 0 ||
1998  printf("smtp parser in inconsistent state\n");
1999  goto end;
2000  }
2001 
2002  FLOWLOCK_WRLOCK(&f);
2003  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2004  STREAM_TOSERVER, request2, request2_len);
2005  if (r != 0) {
2006  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2007  FLOWLOCK_UNLOCK(&f);
2008  goto end;
2009  }
2010  FLOWLOCK_UNLOCK(&f);
2011  if (smtp_state->input_len != 0 ||
2012  smtp_state->cmds_cnt != 1 ||
2013  smtp_state->cmds_idx != 0 ||
2014  smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
2016  printf("smtp parser in inconsistent state\n");
2017  goto end;
2018  }
2019 
2020  FLOWLOCK_WRLOCK(&f);
2021  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2022  STREAM_TOCLIENT, reply2, reply2_len);
2023  if (r != 0) {
2024  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2025  FLOWLOCK_UNLOCK(&f);
2026  goto end;
2027  }
2028  FLOWLOCK_UNLOCK(&f);
2029  if (smtp_state->input_len != 0 ||
2030  smtp_state->cmds_cnt != 0 ||
2031  smtp_state->cmds_idx != 0 ||
2034  printf("smtp parser in inconsistent state\n");
2035  goto end;
2036  }
2037 
2038  if (!FlowChangeProto(&f)) {
2039  goto end;
2040  }
2041 
2042  result = 1;
2043 end:
2044  if (alp_tctx != NULL)
2046  StreamTcpFreeConfig(true);
2047  FLOW_DESTROY(&f);
2048  return result;
2049 }
2050 
2051 /**
2052  * \test Test multiple DATA commands(full mail transactions).
2053  */
2054 static int SMTPParserTest02(void)
2055 {
2056  int result = 0;
2057  Flow f;
2058  int r = 0;
2059 
2060  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
2061  uint8_t welcome_reply[] = {
2062  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
2063  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
2064  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
2065  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
2066  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
2067  0x0d, 0x0a
2068  };
2069  uint32_t welcome_reply_len = sizeof(welcome_reply);
2070 
2071  /* EHLO boo.com<CR><LF> */
2072  uint8_t request1[] = {
2073  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2074  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2075  };
2076  uint32_t request1_len = sizeof(request1);
2077  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
2078  * 250-SIZE 35882577<CR><LF>
2079  * 250-8BITMIME<CR><LF>
2080  * 250-STARTTLS<CR><LF>
2081  * 250 ENHANCEDSTATUSCODES<CR><LF>
2082  */
2083  uint8_t reply1[] = {
2084  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2085  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2086  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2087  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2088  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2089  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2090  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2091  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2092  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2093  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2094  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2095  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2096  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2097  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2098  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2099  };
2100  uint32_t reply1_len = sizeof(reply1);
2101 
2102  /* MAIL FROM:asdff@asdf.com<CR><LF> */
2103  uint8_t request2[] = {
2104  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2105  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
2106  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2107  0x0d, 0x0a
2108  };
2109  uint32_t request2_len = sizeof(request2);
2110  /* 250 2.1.0 Ok<CR><LF> */
2111  uint8_t reply2[] = {
2112  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2113  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2114  };
2115  uint32_t reply2_len = sizeof(reply2);
2116 
2117  /* RCPT TO:bimbs@gmail.com<CR><LF> */
2118  uint8_t request3[] = {
2119  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2120  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2121  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2122  0x0a
2123  };
2124  uint32_t request3_len = sizeof(request3);
2125  /* 250 2.1.5 Ok<CR><LF> */
2126  uint8_t reply3[] = {
2127  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2128  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2129  };
2130  uint32_t reply3_len = sizeof(reply3);
2131 
2132  /* DATA<CR><LF> */
2133  uint8_t request4[] = {
2134  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2135  };
2136  uint32_t request4_len = sizeof(request4);
2137  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2138  uint8_t reply4[] = {
2139  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2140  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2141  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2142  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2143  0x4c, 0x46, 0x3e, 0x0d, 0x0a
2144  };
2145  uint32_t reply4_len = sizeof(reply4);
2146 
2147  /* FROM:asdff@asdf.com<CR><LF> */
2148  uint8_t request5_1[] = {
2149  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2150  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2151  0x63, 0x6f, 0x6d, 0x0d, 0x0a
2152  };
2153  uint32_t request5_1_len = sizeof(request5_1);
2154  /* TO:bimbs@gmail.com<CR><LF> */
2155  uint8_t request5_2[] = {
2156  0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2157  0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2158  0x6f, 0x6d, 0x0d, 0x0a
2159  };
2160  uint32_t request5_2_len = sizeof(request5_2);
2161  /* <CR><LF> */
2162  uint8_t request5_3[] = {
2163  0x0d, 0x0a
2164  };
2165  uint32_t request5_3_len = sizeof(request5_3);
2166  /* this is test mail1<CR><LF> */
2167  uint8_t request5_4[] = {
2168  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2169  0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2170  0x6c, 0x31, 0x0d, 0x0a
2171  };
2172  uint32_t request5_4_len = sizeof(request5_4);
2173  /* .<CR><LF> */
2174  uint8_t request5_5[] = {
2175  0x2e, 0x0d, 0x0a
2176  };
2177  uint32_t request5_5_len = sizeof(request5_5);
2178  /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
2179  uint8_t reply5[] = {
2180  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2181  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2182  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2183  0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
2184  0x46, 0x32, 0x0d, 0x0a
2185  };
2186  uint32_t reply5_len = sizeof(reply5);
2187 
2188  /* MAIL FROM:asdfg@asdf.com<CR><LF> */
2189  uint8_t request6[] = {
2190  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2191  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40,
2192  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2193  0x0d, 0x0a
2194  };
2195  uint32_t request6_len = sizeof(request6);
2196  /* 250 2.1.0 Ok<CR><LF> */
2197  uint8_t reply6[] = {
2198  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2199  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2200  };
2201  uint32_t reply6_len = sizeof(reply6);
2202 
2203  /* RCPT TO:bimbs@gmail.com<CR><LF> */
2204  uint8_t request7[] = {
2205  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2206  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2207  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2208  0x0a
2209  };
2210  uint32_t request7_len = sizeof(request7);
2211  /* 250 2.1.5 Ok<CR><LF> */
2212  uint8_t reply7[] = {
2213  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2214  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2215  };
2216  uint32_t reply7_len = sizeof(reply7);
2217 
2218  /* DATA<CR><LF> */
2219  uint8_t request8[] = {
2220  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2221  };
2222  uint32_t request8_len = sizeof(request8);
2223  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2224  uint8_t reply8[] = {
2225  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2226  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2227  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2228  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2229  0x4c, 0x46, 0x3e, 0x0d, 0x0a
2230  };
2231  uint32_t reply8_len = sizeof(reply8);
2232 
2233  /* FROM:asdfg@gmail.com<CR><LF> */
2234  uint8_t request9_1[] = {
2235  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2236  0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
2237  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2238  };
2239  uint32_t request9_1_len = sizeof(request9_1);
2240  /* TO:bimbs@gmail.com<CR><LF> */
2241  uint8_t request9_2[] = {
2242  0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2243  0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2244  0x6f, 0x6d, 0x0d, 0x0a
2245  };
2246  uint32_t request9_2_len = sizeof(request9_2);
2247  /* <CR><LF> */
2248  uint8_t request9_3[] = {
2249  0x0d, 0x0a
2250  };
2251  uint32_t request9_3_len = sizeof(request9_3);
2252  /* this is test mail2<CR><LF> */
2253  uint8_t request9_4[] = {
2254  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2255  0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2256  0x6c, 0x32, 0x0d, 0x0a
2257  };
2258  uint32_t request9_4_len = sizeof(request9_4);
2259  /* .<CR><LF> */
2260  uint8_t request9_5[] = {
2261  0x2e, 0x0d, 0x0a
2262  };
2263  uint32_t request9_5_len = sizeof(request9_5);
2264  /* 250 2.0.0 Ok: queued as 28CFF20BF2<CR><LF> */
2265  uint8_t reply9[] = {
2266  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2267  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2268  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2269  0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42,
2270  0x46, 0x32, 0x0d, 0x0a
2271  };
2272  uint32_t reply9_len = sizeof(reply9);
2273 
2274  /* QUIT<CR><LF> */
2275  uint8_t request10[] = {
2276  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
2277  };
2278  uint32_t request10_len = sizeof(request10);
2279  /* 221 2.0.0 Bye<CR><LF> */
2280  uint8_t reply10[] = {
2281  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2282  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
2283  };
2284  uint32_t reply10_len = sizeof(reply10);
2285 
2286  TcpSession ssn;
2288 
2289  memset(&f, 0, sizeof(f));
2290  memset(&ssn, 0, sizeof(ssn));
2291 
2292  FLOW_INITIALIZE(&f);
2293  f.protoctx = (void *)&ssn;
2294  f.proto = IPPROTO_TCP;
2295  f.alproto = ALPROTO_SMTP;
2296 
2297  StreamTcpInitConfig(true);
2298  SMTPTestInitConfig();
2299 
2300  FLOWLOCK_WRLOCK(&f);
2301  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2302  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2303  if (r != 0) {
2304  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2305  FLOWLOCK_UNLOCK(&f);
2306  goto end;
2307  }
2308  FLOWLOCK_UNLOCK(&f);
2309  SMTPState *smtp_state = f.alstate;
2310  if (smtp_state == NULL) {
2311  printf("no smtp state: ");
2312  goto end;
2313  }
2314  if (smtp_state->input_len != 0 ||
2315  smtp_state->cmds_cnt != 0 ||
2316  smtp_state->cmds_idx != 0 ||
2318  printf("smtp parser in inconsistent state\n");
2319  goto end;
2320  }
2321 
2322  FLOWLOCK_WRLOCK(&f);
2323  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2324  STREAM_TOSERVER, request1, request1_len);
2325  if (r != 0) {
2326  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2327  FLOWLOCK_UNLOCK(&f);
2328  goto end;
2329  }
2330  FLOWLOCK_UNLOCK(&f);
2331  if (smtp_state->input_len != 0 ||
2332  smtp_state->cmds_cnt != 1 ||
2333  smtp_state->cmds_idx != 0 ||
2334  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2336  printf("smtp parser in inconsistent state\n");
2337  goto end;
2338  }
2339 
2340  FLOWLOCK_WRLOCK(&f);
2341  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2342  STREAM_TOCLIENT, reply1, reply1_len);
2343  if (r != 0) {
2344  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2345  FLOWLOCK_UNLOCK(&f);
2346  goto end;
2347  }
2348  FLOWLOCK_UNLOCK(&f);
2349  if (smtp_state->input_len != 0 ||
2350  smtp_state->cmds_cnt != 0 ||
2351  smtp_state->cmds_idx != 0 ||
2353  printf("smtp parser in inconsistent state\n");
2354  goto end;
2355  }
2356 
2357  FLOWLOCK_WRLOCK(&f);
2358  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2359  STREAM_TOSERVER, request2, request2_len);
2360  if (r != 0) {
2361  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2362  FLOWLOCK_UNLOCK(&f);
2363  goto end;
2364  }
2365  FLOWLOCK_UNLOCK(&f);
2366  if (smtp_state->input_len != 0 ||
2367  smtp_state->cmds_cnt != 1 ||
2368  smtp_state->cmds_idx != 0 ||
2369  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2371  printf("smtp parser in inconsistent state\n");
2372  goto end;
2373  }
2374 
2375  FLOWLOCK_WRLOCK(&f);
2376  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2377  STREAM_TOCLIENT, reply2, reply2_len);
2378  if (r != 0) {
2379  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2380  FLOWLOCK_UNLOCK(&f);
2381  goto end;
2382  }
2383  FLOWLOCK_UNLOCK(&f);
2384  if (smtp_state->input_len != 0 ||
2385  smtp_state->cmds_cnt != 0 ||
2386  smtp_state->cmds_idx != 0 ||
2388  printf("smtp parser in inconsistent state\n");
2389  goto end;
2390  }
2391 
2392  FLOWLOCK_WRLOCK(&f);
2393  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2394  STREAM_TOSERVER, request3, request3_len);
2395  if (r != 0) {
2396  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2397  FLOWLOCK_UNLOCK(&f);
2398  goto end;
2399  }
2400  FLOWLOCK_UNLOCK(&f);
2401  if (smtp_state->input_len != 0 ||
2402  smtp_state->cmds_cnt != 1 ||
2403  smtp_state->cmds_idx != 0 ||
2404  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2406  printf("smtp parser in inconsistent state\n");
2407  goto end;
2408  }
2409 
2410  FLOWLOCK_WRLOCK(&f);
2411  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2412  STREAM_TOCLIENT, reply3, reply3_len);
2413  if (r != 0) {
2414  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2415  FLOWLOCK_UNLOCK(&f);
2416  goto end;
2417  }
2418  FLOWLOCK_UNLOCK(&f);
2419  if (smtp_state->input_len != 0 ||
2420  smtp_state->cmds_cnt != 0 ||
2421  smtp_state->cmds_idx != 0 ||
2423  printf("smtp parser in inconsistent state\n");
2424  goto end;
2425  }
2426 
2427  FLOWLOCK_WRLOCK(&f);
2428  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2429  STREAM_TOSERVER, request4, request4_len);
2430  if (r != 0) {
2431  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2432  FLOWLOCK_UNLOCK(&f);
2433  goto end;
2434  }
2435  FLOWLOCK_UNLOCK(&f);
2436  if (smtp_state->input_len != 0 ||
2437  smtp_state->cmds_cnt != 1 ||
2438  smtp_state->cmds_idx != 0 ||
2439  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2441  printf("smtp parser in inconsistent state\n");
2442  goto end;
2443  }
2444 
2445  FLOWLOCK_WRLOCK(&f);
2446  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2447  STREAM_TOCLIENT, reply4, reply4_len);
2448  if (r != 0) {
2449  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2450  FLOWLOCK_UNLOCK(&f);
2451  goto end;
2452  }
2453  FLOWLOCK_UNLOCK(&f);
2454  if (smtp_state->input_len != 0 ||
2455  smtp_state->cmds_cnt != 0 ||
2456  smtp_state->cmds_idx != 0 ||
2459  printf("smtp parser in inconsistent state\n");
2460  goto end;
2461  }
2462 
2463  FLOWLOCK_WRLOCK(&f);
2464  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2465  STREAM_TOSERVER, request5_1, request5_1_len);
2466  if (r != 0) {
2467  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2468  FLOWLOCK_UNLOCK(&f);
2469  goto end;
2470  }
2471  FLOWLOCK_UNLOCK(&f);
2472  if (smtp_state->input_len != 0 ||
2473  smtp_state->cmds_cnt != 0 ||
2474  smtp_state->cmds_idx != 0 ||
2477 
2478  printf("smtp parser in inconsistent state\n");
2479  goto end;
2480  }
2481 
2482  FLOWLOCK_WRLOCK(&f);
2483  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2484  STREAM_TOSERVER, request5_2, request5_2_len);
2485  if (r != 0) {
2486  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2487  FLOWLOCK_UNLOCK(&f);
2488  goto end;
2489  }
2490  FLOWLOCK_UNLOCK(&f);
2491  if (smtp_state->input_len != 0 ||
2492  smtp_state->cmds_cnt != 0 ||
2493  smtp_state->cmds_idx != 0 ||
2496 
2497  printf("smtp parser in inconsistent state\n");
2498  goto end;
2499  }
2500 
2501  FLOWLOCK_WRLOCK(&f);
2502  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2503  STREAM_TOSERVER, request5_3, request5_3_len);
2504  if (r != 0) {
2505  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2506  FLOWLOCK_UNLOCK(&f);
2507  goto end;
2508  }
2509  FLOWLOCK_UNLOCK(&f);
2510  if (smtp_state->input_len != 0 ||
2511  smtp_state->cmds_cnt != 0 ||
2512  smtp_state->cmds_idx != 0 ||
2515 
2516  printf("smtp parser in inconsistent state\n");
2517  goto end;
2518  }
2519 
2520  FLOWLOCK_WRLOCK(&f);
2521  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2522  STREAM_TOSERVER, request5_4, request5_4_len);
2523  if (r != 0) {
2524  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2525  FLOWLOCK_UNLOCK(&f);
2526  goto end;
2527  }
2528  FLOWLOCK_UNLOCK(&f);
2529  if (smtp_state->input_len != 0 ||
2530  smtp_state->cmds_cnt != 0 ||
2531  smtp_state->cmds_idx != 0 ||
2534 
2535  printf("smtp parser in inconsistent state\n");
2536  goto end;
2537  }
2538 
2539  FLOWLOCK_WRLOCK(&f);
2540  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2541  STREAM_TOSERVER, request5_5, request5_5_len);
2542  if (r != 0) {
2543  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2544  FLOWLOCK_UNLOCK(&f);
2545  goto end;
2546  }
2547  FLOWLOCK_UNLOCK(&f);
2548  if (smtp_state->input_len != 0 ||
2549  smtp_state->cmds_cnt != 1 ||
2550  smtp_state->cmds_idx != 0 ||
2551  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2553  printf("smtp parser in inconsistent state\n");
2554  goto end;
2555  }
2556 
2557  FLOWLOCK_WRLOCK(&f);
2558  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2559  STREAM_TOCLIENT, reply5, reply5_len);
2560  if (r != 0) {
2561  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2562  FLOWLOCK_UNLOCK(&f);
2563  goto end;
2564  }
2565  FLOWLOCK_UNLOCK(&f);
2566  if (smtp_state->input_len != 0 ||
2567  smtp_state->cmds_cnt != 0 ||
2568  smtp_state->cmds_idx != 0 ||
2570  printf("smtp parser in inconsistent state\n");
2571  goto end;
2572  }
2573 
2574  FLOWLOCK_WRLOCK(&f);
2575  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2576  STREAM_TOSERVER, request6, request6_len);
2577  if (r != 0) {
2578  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2579  FLOWLOCK_UNLOCK(&f);
2580  goto end;
2581  }
2582  FLOWLOCK_UNLOCK(&f);
2583  if (smtp_state->input_len != 0 ||
2584  smtp_state->cmds_cnt != 1 ||
2585  smtp_state->cmds_idx != 0 ||
2586  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2588  printf("smtp parser in inconsistent state\n");
2589  goto end;
2590  }
2591 
2592  FLOWLOCK_WRLOCK(&f);
2593  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2594  STREAM_TOCLIENT, reply6, reply6_len);
2595  if (r != 0) {
2596  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2597  FLOWLOCK_UNLOCK(&f);
2598  goto end;
2599  }
2600  FLOWLOCK_UNLOCK(&f);
2601  if (smtp_state->input_len != 0 ||
2602  smtp_state->cmds_cnt != 0 ||
2603  smtp_state->cmds_idx != 0 ||
2605  printf("smtp parser in inconsistent state\n");
2606  goto end;
2607  }
2608 
2609  FLOWLOCK_WRLOCK(&f);
2610  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2611  STREAM_TOSERVER, request7, request7_len);
2612  if (r != 0) {
2613  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2614  FLOWLOCK_UNLOCK(&f);
2615  goto end;
2616  }
2617  FLOWLOCK_UNLOCK(&f);
2618  if (smtp_state->input_len != 0 ||
2619  smtp_state->cmds_cnt != 1 ||
2620  smtp_state->cmds_idx != 0 ||
2621  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2623  printf("smtp parser in inconsistent state\n");
2624  goto end;
2625  }
2626 
2627  FLOWLOCK_WRLOCK(&f);
2628  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2629  STREAM_TOCLIENT, reply7, reply7_len);
2630  if (r != 0) {
2631  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2632  FLOWLOCK_UNLOCK(&f);
2633  goto end;
2634  }
2635  FLOWLOCK_UNLOCK(&f);
2636  if (smtp_state->input_len != 0 ||
2637  smtp_state->cmds_cnt != 0 ||
2638  smtp_state->cmds_idx != 0 ||
2640  printf("smtp parser in inconsistent state\n");
2641  goto end;
2642  }
2643 
2644  FLOWLOCK_WRLOCK(&f);
2645  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2646  STREAM_TOSERVER, request8, request8_len);
2647  if (r != 0) {
2648  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2649  FLOWLOCK_UNLOCK(&f);
2650  goto end;
2651  }
2652  FLOWLOCK_UNLOCK(&f);
2653  if (smtp_state->input_len != 0 ||
2654  smtp_state->cmds_cnt != 1 ||
2655  smtp_state->cmds_idx != 0 ||
2656  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2658  printf("smtp parser in inconsistent state\n");
2659  goto end;
2660  }
2661 
2662  FLOWLOCK_WRLOCK(&f);
2663  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2664  STREAM_TOCLIENT, reply8, reply8_len);
2665  if (r != 0) {
2666  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2667  FLOWLOCK_UNLOCK(&f);
2668  goto end;
2669  }
2670  FLOWLOCK_UNLOCK(&f);
2671  if (smtp_state->input_len != 0 ||
2672  smtp_state->cmds_cnt != 0 ||
2673  smtp_state->cmds_idx != 0 ||
2676  printf("smtp parser in inconsistent state\n");
2677  goto end;
2678  }
2679 
2680  FLOWLOCK_WRLOCK(&f);
2681  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2682  STREAM_TOSERVER, request9_1, request9_1_len);
2683  if (r != 0) {
2684  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2685  FLOWLOCK_UNLOCK(&f);
2686  goto end;
2687  }
2688  FLOWLOCK_UNLOCK(&f);
2689  if (smtp_state->input_len != 0 ||
2690  smtp_state->cmds_cnt != 0 ||
2691  smtp_state->cmds_idx != 0 ||
2694 
2695  printf("smtp parser in inconsistent state\n");
2696  goto end;
2697  }
2698 
2699  FLOWLOCK_WRLOCK(&f);
2700  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2701  STREAM_TOSERVER, request9_2, request9_2_len);
2702  if (r != 0) {
2703  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2704  FLOWLOCK_UNLOCK(&f);
2705  goto end;
2706  }
2707  FLOWLOCK_UNLOCK(&f);
2708  if (smtp_state->input_len != 0 ||
2709  smtp_state->cmds_cnt != 0 ||
2710  smtp_state->cmds_idx != 0 ||
2713 
2714  printf("smtp parser in inconsistent state\n");
2715  goto end;
2716  }
2717 
2718  FLOWLOCK_WRLOCK(&f);
2719  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2720  STREAM_TOSERVER, request9_3, request9_3_len);
2721  if (r != 0) {
2722  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2723  FLOWLOCK_UNLOCK(&f);
2724  goto end;
2725  }
2726  FLOWLOCK_UNLOCK(&f);
2727  if (smtp_state->input_len != 0 ||
2728  smtp_state->cmds_cnt != 0 ||
2729  smtp_state->cmds_idx != 0 ||
2732 
2733  printf("smtp parser in inconsistent state\n");
2734  goto end;
2735  }
2736 
2737  FLOWLOCK_WRLOCK(&f);
2738  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2739  STREAM_TOSERVER, request9_4, request9_4_len);
2740  if (r != 0) {
2741  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2742  FLOWLOCK_UNLOCK(&f);
2743  goto end;
2744  }
2745  FLOWLOCK_UNLOCK(&f);
2746  if (smtp_state->input_len != 0 ||
2747  smtp_state->cmds_cnt != 0 ||
2748  smtp_state->cmds_idx != 0 ||
2751 
2752  printf("smtp parser in inconsistent state\n");
2753  goto end;
2754  }
2755 
2756  FLOWLOCK_WRLOCK(&f);
2757  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2758  STREAM_TOSERVER, request9_5, request9_5_len);
2759  if (r != 0) {
2760  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2761  FLOWLOCK_UNLOCK(&f);
2762  goto end;
2763  }
2764  FLOWLOCK_UNLOCK(&f);
2765  if (smtp_state->input_len != 0 ||
2766  smtp_state->cmds_cnt != 1 ||
2767  smtp_state->cmds_idx != 0 ||
2768  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2770  printf("smtp parser in inconsistent state\n");
2771  goto end;
2772  }
2773 
2774  FLOWLOCK_WRLOCK(&f);
2775  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2776  STREAM_TOCLIENT, reply9, reply9_len);
2777  if (r != 0) {
2778  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2779  FLOWLOCK_UNLOCK(&f);
2780  goto end;
2781  }
2782  FLOWLOCK_UNLOCK(&f);
2783  if (smtp_state->input_len != 0 ||
2784  smtp_state->cmds_cnt != 0 ||
2785  smtp_state->cmds_idx != 0 ||
2787  printf("smtp parser in inconsistent state\n");
2788  goto end;
2789  }
2790 
2791  FLOWLOCK_WRLOCK(&f);
2792  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2793  STREAM_TOSERVER, request10, request10_len);
2794  if (r != 0) {
2795  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2796  FLOWLOCK_UNLOCK(&f);
2797  goto end;
2798  }
2799  FLOWLOCK_UNLOCK(&f);
2800  if (smtp_state->input_len != 0 ||
2801  smtp_state->cmds_cnt != 1 ||
2802  smtp_state->cmds_idx != 0 ||
2803  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2805  printf("smtp parser in inconsistent state\n");
2806  goto end;
2807  }
2808 
2809  FLOWLOCK_WRLOCK(&f);
2810  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2811  STREAM_TOCLIENT, reply10, reply10_len);
2812  if (r != 0) {
2813  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2814  FLOWLOCK_UNLOCK(&f);
2815  goto end;
2816  }
2817  FLOWLOCK_UNLOCK(&f);
2818  if (smtp_state->input_len != 0 ||
2819  smtp_state->cmds_cnt != 0 ||
2820  smtp_state->cmds_idx != 0 ||
2822  printf("smtp parser in inconsistent state\n");
2823  goto end;
2824  }
2825 
2826  result = 1;
2827 end:
2828  if (alp_tctx != NULL)
2830  StreamTcpFreeConfig(true);
2831  FLOW_DESTROY(&f);
2832  return result;
2833 }
2834 
2835 /**
2836  * \test Testing parsing pipelined commands.
2837  */
2838 static int SMTPParserTest03(void)
2839 {
2840  int result = 0;
2841  Flow f;
2842  int r = 0;
2843 
2844  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2845  uint8_t welcome_reply[] = {
2846  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2847  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2848  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2849  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2850  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2851  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2852  };
2853  uint32_t welcome_reply_len = sizeof(welcome_reply);
2854 
2855  /* EHLO boo.com<CR><LF> */
2856  uint8_t request1[] = {
2857  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2858  0x2e, 0x63, 0x6f, 0x6d, 0x0a
2859  };
2860  uint32_t request1_len = sizeof(request1);
2861  /* 250-poona_slack_vm1.localdomain<CR><LF>
2862  * 250-PIPELINING<CR><LF>
2863  * 250-SIZE 10240000<CR><LF>
2864  * 250-VRFY<CR><LF>
2865  * 250-ETRN<CR><LF>
2866  * 250-ENHANCEDSTATUSCODES<CR><LF>
2867  * 250-8BITMIME<CR><LF>
2868  * 250 DSN<CR><LF>
2869  */
2870  uint8_t reply1[] = {
2871  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2872  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2873  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2874  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2875  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
2876  0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
2877  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2878  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2879  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2880  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2881  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2882  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2883  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2884  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2885  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2886  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2887  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2888  };
2889  uint32_t reply1_len = sizeof(reply1);
2890 
2891  /* MAIL FROM:pbsf@asdfs.com<CR><LF>
2892  * RCPT TO:pbsf@asdfs.com<CR><LF>
2893  * DATA<CR><LF>
2894  * Immediate data
2895  */
2896  uint8_t request2[] = {
2897  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2898  0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2899  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2900  0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
2901  0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2902  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2903  0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
2904  0x49, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74,
2905  0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0d, 0x0a,
2906  };
2907  uint32_t request2_len = sizeof(request2);
2908  /* 250 2.1.0 Ok<CR><LF>
2909  * 250 2.1.5 Ok<CR><LF>
2910  * 354 End data with <CR><LF>.<CR><LF>|<CR><LF>|
2911  */
2912  uint8_t reply2[] = {
2913  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2914  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35,
2915  0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20,
2916  0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20,
2917  0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61,
2918  0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43,
2919  0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c,
2920  0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d,
2921  0x0a
2922  };
2923  uint32_t reply2_len = sizeof(reply2);
2924 
2925  TcpSession ssn;
2927 
2928  memset(&f, 0, sizeof(f));
2929  memset(&ssn, 0, sizeof(ssn));
2930 
2931  FLOW_INITIALIZE(&f);
2932  f.protoctx = (void *)&ssn;
2933  f.proto = IPPROTO_TCP;
2934  f.alproto = ALPROTO_SMTP;
2935 
2936  StreamTcpInitConfig(true);
2937  SMTPTestInitConfig();
2938 
2939  FLOWLOCK_WRLOCK(&f);
2940  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2941  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2942  if (r != 0) {
2943  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2944  FLOWLOCK_UNLOCK(&f);
2945  goto end;
2946  }
2947  FLOWLOCK_UNLOCK(&f);
2948  SMTPState *smtp_state = f.alstate;
2949  if (smtp_state == NULL) {
2950  printf("no smtp state: ");
2951  goto end;
2952  }
2953  if (smtp_state->input_len != 0 ||
2954  smtp_state->cmds_cnt != 0 ||
2955  smtp_state->cmds_idx != 0 ||
2957  printf("smtp parser in inconsistent state\n");
2958  goto end;
2959  }
2960 
2961  FLOWLOCK_WRLOCK(&f);
2962  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2963  STREAM_TOSERVER, request1, request1_len);
2964  if (r != 0) {
2965  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2966  FLOWLOCK_UNLOCK(&f);
2967  goto end;
2968  }
2969  FLOWLOCK_UNLOCK(&f);
2970  if (smtp_state->input_len != 0 ||
2971  smtp_state->cmds_cnt != 1 ||
2972  smtp_state->cmds_idx != 0 ||
2973  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2975  printf("smtp parser in inconsistent state\n");
2976  goto end;
2977  }
2978 
2979  FLOWLOCK_WRLOCK(&f);
2980  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2981  STREAM_TOCLIENT, reply1, reply1_len);
2982  if (r != 0) {
2983  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2984  FLOWLOCK_UNLOCK(&f);
2985  goto end;
2986  }
2987  FLOWLOCK_UNLOCK(&f);
2988  if (smtp_state->input_len != 0 ||
2989  smtp_state->cmds_cnt != 0 ||
2990  smtp_state->cmds_idx != 0 ||
2993  printf("smtp parser in inconsistent state\n");
2994  goto end;
2995  }
2996 
2997  FLOWLOCK_WRLOCK(&f);
2998  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2999  STREAM_TOSERVER, request2, request2_len);
3000  if (r != 0) {
3001  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3002  FLOWLOCK_UNLOCK(&f);
3003  goto end;
3004  }
3005  FLOWLOCK_UNLOCK(&f);
3006  if (smtp_state->input_len != 0 ||
3007  smtp_state->cmds_cnt != 3 ||
3008  smtp_state->cmds_idx != 0 ||
3009  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3010  smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD ||
3011  smtp_state->cmds[2] != SMTP_COMMAND_DATA ||
3015  printf("smtp parser in inconsistent state\n");
3016  goto end;
3017  }
3018 
3019  FLOWLOCK_WRLOCK(&f);
3020  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3021  STREAM_TOCLIENT, reply2, reply2_len);
3022  if (r != 0) {
3023  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3024  FLOWLOCK_UNLOCK(&f);
3025  goto end;
3026  }
3027  FLOWLOCK_UNLOCK(&f);
3028  if (smtp_state->input_len != 0 ||
3029  smtp_state->cmds_cnt != 0 ||
3030  smtp_state->cmds_idx != 0 ||
3034  printf("smtp parser in inconsistent state\n");
3035  goto end;
3036  }
3037 
3038  result = 1;
3039 end:
3040  if (alp_tctx != NULL)
3042  StreamTcpFreeConfig(true);
3043  FLOW_DESTROY(&f);
3044  return result;
3045 }
3046 
3047 /*
3048  * \test Test smtp with just <LF> delimiter instead of <CR><LF>.
3049  */
3050 static int SMTPParserTest04(void)
3051 {
3052  int result = 0;
3053  Flow f;
3054  int r = 0;
3055 
3056  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
3057  uint8_t welcome_reply[] = {
3058  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3059  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3060  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3061  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3062  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3063  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3064  };
3065  uint32_t welcome_reply_len = sizeof(welcome_reply);
3066 
3067  /* EHLO boo.com<CR><LF> */
3068  uint8_t request1[] = {
3069  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3070  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3071  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3072  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3073  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3074  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3075  };
3076  uint32_t request1_len = sizeof(request1);
3077 
3078  TcpSession ssn;
3080 
3081  memset(&f, 0, sizeof(f));
3082  memset(&ssn, 0, sizeof(ssn));
3083 
3084  FLOW_INITIALIZE(&f);
3085  f.protoctx = (void *)&ssn;
3086  f.proto = IPPROTO_TCP;
3087  f.alproto = ALPROTO_SMTP;
3088 
3089  StreamTcpInitConfig(true);
3090  SMTPTestInitConfig();
3091 
3092  FLOWLOCK_WRLOCK(&f);
3093  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3094  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3095  if (r != 0) {
3096  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3097  FLOWLOCK_UNLOCK(&f);
3098  goto end;
3099  }
3100  FLOWLOCK_UNLOCK(&f);
3101  SMTPState *smtp_state = f.alstate;
3102  if (smtp_state == NULL) {
3103  printf("no smtp state: ");
3104  goto end;
3105  }
3106  if (smtp_state->input_len != 0 ||
3107  smtp_state->cmds_cnt != 0 ||
3108  smtp_state->cmds_idx != 0 ||
3110  printf("smtp parser in inconsistent state\n");
3111  goto end;
3112  }
3113 
3114  FLOWLOCK_WRLOCK(&f);
3115  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3116  STREAM_TOSERVER, request1, request1_len);
3117  if (r != 0) {
3118  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3119  FLOWLOCK_UNLOCK(&f);
3120  goto end;
3121  }
3122  FLOWLOCK_UNLOCK(&f);
3123  if (smtp_state->input_len != 0 ||
3124  smtp_state->cmds_cnt != 1 ||
3125  smtp_state->cmds_idx != 0 ||
3126  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3128  printf("smtp parser in inconsistent state\n");
3129  goto end;
3130  }
3131 
3132  result = 1;
3133 end:
3134  if (alp_tctx != NULL)
3136  StreamTcpFreeConfig(true);
3137  FLOW_DESTROY(&f);
3138  return result;
3139 }
3140 
3141 /*
3142  * \test Test STARTTLS fail.
3143  */
3144 static int SMTPParserTest05(void)
3145 {
3146  int result = 0;
3147  Flow f;
3148  int r = 0;
3149 
3150  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
3151  uint8_t welcome_reply[] = {
3152  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3153  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3154  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3155  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3156  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3157  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3158  };
3159  uint32_t welcome_reply_len = sizeof(welcome_reply);
3160 
3161  /* EHLO boo.com<CR><LF> */
3162  uint8_t request1[] = {
3163  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3164  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
3165  };
3166  uint32_t request1_len = sizeof(request1);
3167  /* 250-poona_slack_vm1.localdomain<CR><LF>
3168  * 250-PIPELINING<CR><LF>
3169  * 250-SIZE 10240000<CR><LF>
3170  * 250-VRFY<CR><LF>
3171  * 250-ETRN<CR><LF>
3172  * 250-ENHANCEDSTATUSCODES<CR><LF>
3173  * 250-8BITMIME<CR><LF>
3174  * 250 DSN<CR><LF>
3175  */
3176  uint8_t reply1[] = {
3177  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
3178  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3179  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3180  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
3181  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
3182  0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
3183  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
3184  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
3185  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3186  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
3187  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
3188  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
3189  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
3190  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
3191  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
3192  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
3193  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
3194  };
3195  uint32_t reply1_len = sizeof(reply1);
3196 
3197  /* STARTTLS<CR><LF> */
3198  uint8_t request2[] = {
3199  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
3200  0x0d, 0x0a
3201  };
3202  uint32_t request2_len = sizeof(request2);
3203  /* 502 5.5.2 Error: command not recognized<CR><LF> */
3204  uint8_t reply2[] = {
3205  0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e,
3206  0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a,
3207  0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
3208  0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63,
3209  0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d,
3210  0x0a
3211  };
3212  uint32_t reply2_len = sizeof(reply2);
3213 
3214  /* QUIT<CR><LF> */
3215  uint8_t request3[] = {
3216  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
3217 
3218  };
3219  uint32_t request3_len = sizeof(request3);
3220  /* 221 2.0.0 Bye<CR><LF> */
3221  uint8_t reply3[] = {
3222  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
3223  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
3224  };
3225  uint32_t reply3_len = sizeof(reply3);
3226 
3227  TcpSession ssn;
3229 
3230  memset(&f, 0, sizeof(f));
3231  memset(&ssn, 0, sizeof(ssn));
3232 
3233  FLOW_INITIALIZE(&f);
3234  f.protoctx = (void *)&ssn;
3235  f.proto = IPPROTO_TCP;
3236  f.alproto = ALPROTO_SMTP;
3237 
3238  StreamTcpInitConfig(true);
3239  SMTPTestInitConfig();
3240 
3241  FLOWLOCK_WRLOCK(&f);
3242  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3243  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3244  if (r != 0) {
3245  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3246  FLOWLOCK_UNLOCK(&f);
3247  goto end;
3248  }
3249  FLOWLOCK_UNLOCK(&f);
3250  SMTPState *smtp_state = f.alstate;
3251  if (smtp_state == NULL) {
3252  printf("no smtp state: ");
3253  goto end;
3254  }
3255  if (smtp_state->input_len != 0 ||
3256  smtp_state->cmds_cnt != 0 ||
3257  smtp_state->cmds_idx != 0 ||
3259  printf("smtp parser in inconsistent state\n");
3260  goto end;
3261  }
3262 
3263  FLOWLOCK_WRLOCK(&f);
3264  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3265  STREAM_TOSERVER, request1, request1_len);
3266  if (r != 0) {
3267  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3268  FLOWLOCK_UNLOCK(&f);
3269  goto end;
3270  }
3271  FLOWLOCK_UNLOCK(&f);
3272  if (smtp_state->input_len != 0 ||
3273  smtp_state->cmds_cnt != 1 ||
3274  smtp_state->cmds_idx != 0 ||
3275  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3277  printf("smtp parser in inconsistent state\n");
3278  goto end;
3279  }
3280 
3281  FLOWLOCK_WRLOCK(&f);
3282  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3283  STREAM_TOCLIENT, reply1, reply1_len);
3284  if (r != 0) {
3285  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3286  FLOWLOCK_UNLOCK(&f);
3287  goto end;
3288  }
3289  FLOWLOCK_UNLOCK(&f);
3290  if (smtp_state->input_len != 0 ||
3291  smtp_state->cmds_cnt != 0 ||
3292  smtp_state->cmds_idx != 0 ||
3295  printf("smtp parser in inconsistent state\n");
3296  goto end;
3297  }
3298 
3299  FLOWLOCK_WRLOCK(&f);
3300  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3301  STREAM_TOSERVER, request2, request2_len);
3302  if (r != 0) {
3303  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3304  FLOWLOCK_UNLOCK(&f);
3305  goto end;
3306  }
3307  FLOWLOCK_UNLOCK(&f);
3308  if (smtp_state->input_len != 0 ||
3309  smtp_state->cmds_cnt != 1 ||
3310  smtp_state->cmds_idx != 0 ||
3311  smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
3314  printf("smtp parser in inconsistent state\n");
3315  goto end;
3316  }
3317 
3318  FLOWLOCK_WRLOCK(&f);
3319  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3320  STREAM_TOCLIENT, reply2, reply2_len);
3321  if (r != 0) {
3322  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3323  FLOWLOCK_UNLOCK(&f);
3324  goto end;
3325  }
3326  FLOWLOCK_UNLOCK(&f);
3327  if (smtp_state->input_len != 0 ||
3328  smtp_state->cmds_cnt != 0 ||
3329  smtp_state->cmds_idx != 0 ||
3332  printf("smtp parser in inconsistent state\n");
3333  goto end;
3334  }
3335 
3336  if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
3338  (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
3339  (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
3340  goto end;
3341  }
3342 
3343  FLOWLOCK_WRLOCK(&f);
3344  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3345  STREAM_TOSERVER, request3, request3_len);
3346  if (r != 0) {
3347  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3348  FLOWLOCK_UNLOCK(&f);
3349  goto end;
3350  }
3351  FLOWLOCK_UNLOCK(&f);
3352  if (smtp_state->input_len != 0 ||
3353  smtp_state->cmds_cnt != 1 ||
3354  smtp_state->cmds_idx != 0 ||
3355  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3358  printf("smtp parser in inconsistent state\n");
3359  goto end;
3360  }
3361 
3362  FLOWLOCK_WRLOCK(&f);
3363  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3364  STREAM_TOCLIENT, reply3, reply3_len);
3365  if (r != 0) {
3366  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3367  FLOWLOCK_UNLOCK(&f);
3368  goto end;
3369  }
3370  FLOWLOCK_UNLOCK(&f);
3371  if (smtp_state->input_len != 0 ||
3372  smtp_state->cmds_cnt != 0 ||
3373  smtp_state->cmds_idx != 0 ||
3376  printf("smtp parser in inconsistent state\n");
3377  goto end;
3378  }
3379 
3380  result = 1;
3381 end:
3382  if (alp_tctx != NULL)
3384  StreamTcpFreeConfig(true);
3385  FLOW_DESTROY(&f);
3386  return result;
3387 }
3388 
3389 /**
3390  * \test Test multiple DATA commands(full mail transactions).
3391  */
3392 static int SMTPParserTest06(void)
3393 {
3394  int result = 0;
3395  Flow f;
3396  int r = 0;
3397 
3398  uint8_t welcome_reply[] = {
3399  0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30,
3400  0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3401  0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3402  0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3403  0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e,
3404  0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69,
3405  0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f,
3406  0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c,
3407  0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b,
3408  0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20,
3409  0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f,
3410  0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63,
3411  0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20,
3412  0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
3413  0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69,
3414  0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f,
3415  0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73,
3416  0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e,
3417  0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f,
3418  0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68,
3419  0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72,
3420  0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73,
3421  0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e,
3422  0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f,
3423  0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74,
3424  0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c,
3425  0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
3426  0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20,
3427  0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70,
3428  0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63,
3429  0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
3430  0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
3431  0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f,
3432  0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61,
3433  0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69,
3434  0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62,
3435  0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35,
3436  0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d,
3437  0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a
3438  };
3439  uint32_t welcome_reply_len = sizeof(welcome_reply);
3440 
3441  uint8_t request1[] = {
3442  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43,
3443  0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63,
3444  0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69,
3445  0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d,
3446  0x0a
3447  };
3448  uint32_t request1_len = sizeof(request1);
3449 
3450  uint8_t reply1[] = {
3451  0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30,
3452  0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3453  0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3454  0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3455  0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31,
3456  0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c,
3457  0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31,
3458  0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39,
3459  0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53,
3460  0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39,
3461  0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35,
3462  0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69,
3463  0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3464  0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49,
3465  0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3466  0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47,
3467  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3468  0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3469  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3470  0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3471  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b,
3472  0x0d, 0x0a
3473  };
3474  uint32_t reply1_len = sizeof(reply1);
3475 
3476  /* MAIL FROM:asdff@asdf.com<CR><LF> */
3477  uint8_t request2[] = {
3478  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3479  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
3480  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
3481  0x0d, 0x0a
3482  };
3483  uint32_t request2_len = sizeof(request2);
3484  /* 250 2.1.0 Ok<CR><LF> */
3485  uint8_t reply2[] = {
3486  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3487  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3488  };
3489  uint32_t reply2_len = sizeof(reply2);
3490 
3491  /* RCPT TO:bimbs@gmail.com<CR><LF> */
3492  uint8_t request3[] = {
3493  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
3494  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
3495  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3496  0x0a
3497  };
3498  uint32_t request3_len = sizeof(request3);
3499  /* 250 2.1.5 Ok<CR><LF> */
3500  uint8_t reply3[] = {
3501  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3502  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3503  };
3504  uint32_t reply3_len = sizeof(reply3);
3505 
3506  /* BDAT 51<CR><LF> */
3507  uint8_t request4[] = {
3508  0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d,
3509  0x0a,
3510  };
3511  uint32_t request4_len = sizeof(request4);
3512 
3513  uint8_t request5[] = {
3514  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3515  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3516  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3517  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a,
3518  };
3519  uint32_t request5_len = sizeof(request5);
3520 
3521  uint8_t request6[] = {
3522  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3523  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3524  0x66, 0x0d, 0x0a,
3525  };
3526  uint32_t request6_len = sizeof(request6);
3527 
3528  TcpSession ssn;
3530 
3531  memset(&f, 0, sizeof(f));
3532  memset(&ssn, 0, sizeof(ssn));
3533 
3534  FLOW_INITIALIZE(&f);
3535  f.protoctx = (void *)&ssn;
3536  f.proto = IPPROTO_TCP;
3537  f.alproto = ALPROTO_SMTP;
3538 
3539  StreamTcpInitConfig(true);
3540  SMTPTestInitConfig();
3541 
3542  FLOWLOCK_WRLOCK(&f);
3543  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3544  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3545  if (r != 0) {
3546  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3547  FLOWLOCK_UNLOCK(&f);
3548  goto end;
3549  }
3550  FLOWLOCK_UNLOCK(&f);
3551  SMTPState *smtp_state = f.alstate;
3552  if (smtp_state == NULL) {
3553  printf("no smtp state: ");
3554  goto end;
3555  }
3556  if (smtp_state->input_len != 0 ||
3557  smtp_state->cmds_cnt != 0 ||
3558  smtp_state->cmds_idx != 0 ||
3560  printf("smtp parser in inconsistent state\n");
3561  goto end;
3562  }
3563 
3564  FLOWLOCK_WRLOCK(&f);
3565  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3566  STREAM_TOSERVER, request1, request1_len);
3567  if (r != 0) {
3568  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3569  FLOWLOCK_UNLOCK(&f);
3570  goto end;
3571  }
3572  FLOWLOCK_UNLOCK(&f);
3573  if (smtp_state->input_len != 0 ||
3574  smtp_state->cmds_cnt != 1 ||
3575  smtp_state->cmds_idx != 0 ||
3576  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3578  printf("smtp parser in inconsistent state\n");
3579  goto end;
3580  }
3581 
3582  FLOWLOCK_WRLOCK(&f);
3583  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3584  STREAM_TOCLIENT, reply1, reply1_len);
3585  if (r != 0) {
3586  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3587  FLOWLOCK_UNLOCK(&f);
3588  goto end;
3589  }
3590  FLOWLOCK_UNLOCK(&f);
3591  if (smtp_state->input_len != 0 ||
3592  smtp_state->cmds_cnt != 0 ||
3593  smtp_state->cmds_idx != 0 ||
3595  printf("smtp parser in inconsistent state\n");
3596  goto end;
3597  }
3598 
3599  FLOWLOCK_WRLOCK(&f);
3600  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3601  STREAM_TOSERVER, request2, request2_len);
3602  if (r != 0) {
3603  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3604  FLOWLOCK_UNLOCK(&f);
3605  goto end;
3606  }
3607  FLOWLOCK_UNLOCK(&f);
3608  if (smtp_state->input_len != 0 ||
3609  smtp_state->cmds_cnt != 1 ||
3610  smtp_state->cmds_idx != 0 ||
3611  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3613  printf("smtp parser in inconsistent state\n");
3614  goto end;
3615  }
3616 
3617  FLOWLOCK_WRLOCK(&f);
3618  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3619  STREAM_TOCLIENT, reply2, reply2_len);
3620  if (r != 0) {
3621  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3622  FLOWLOCK_UNLOCK(&f);
3623  goto end;
3624  }
3625  FLOWLOCK_UNLOCK(&f);
3626  if (smtp_state->input_len != 0 ||
3627  smtp_state->cmds_cnt != 0 ||
3628  smtp_state->cmds_idx != 0 ||
3630  printf("smtp parser in inconsistent state\n");
3631  goto end;
3632  }
3633 
3634  FLOWLOCK_WRLOCK(&f);
3635  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3636  STREAM_TOSERVER, request3, request3_len);
3637  if (r != 0) {
3638  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3639  FLOWLOCK_UNLOCK(&f);
3640  goto end;
3641  }
3642  FLOWLOCK_UNLOCK(&f);
3643  if (smtp_state->input_len != 0 ||
3644  smtp_state->cmds_cnt != 1 ||
3645  smtp_state->cmds_idx != 0 ||
3646  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3648  printf("smtp parser in inconsistent state\n");
3649  goto end;
3650  }
3651 
3652  FLOWLOCK_WRLOCK(&f);
3653  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3654  STREAM_TOCLIENT, reply3, reply3_len);
3655  if (r != 0) {
3656  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3657  FLOWLOCK_UNLOCK(&f);
3658  goto end;
3659  }
3660  FLOWLOCK_UNLOCK(&f);
3661  if (smtp_state->input_len != 0 ||
3662  smtp_state->cmds_cnt != 0 ||
3663  smtp_state->cmds_idx != 0 ||
3665  printf("smtp parser in inconsistent state\n");
3666  goto end;
3667  }
3668 
3669  FLOWLOCK_WRLOCK(&f);
3670  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3671  STREAM_TOSERVER, request4, request4_len);
3672  if (r != 0) {
3673  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3674  FLOWLOCK_UNLOCK(&f);
3675  goto end;
3676  }
3677  FLOWLOCK_UNLOCK(&f);
3678  if (smtp_state->input_len != 0 ||
3679  smtp_state->cmds_cnt != 1 ||
3680  smtp_state->cmds_idx != 0 ||
3681  smtp_state->cmds[0] != SMTP_COMMAND_BDAT ||
3684  smtp_state->bdat_chunk_len != 51 ||
3685  smtp_state->bdat_chunk_idx != 0) {
3686  printf("smtp parser in inconsistent state\n");
3687  goto end;
3688  }
3689 
3690  FLOWLOCK_WRLOCK(&f);
3691  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3692  STREAM_TOSERVER, request5, request5_len);
3693  if (r != 0) {
3694  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3695  FLOWLOCK_UNLOCK(&f);
3696  goto end;
3697  }
3698  FLOWLOCK_UNLOCK(&f);
3699  if (smtp_state->input_len != 0 ||
3700  smtp_state->cmds_cnt != 1 ||
3701  smtp_state->cmds_idx != 0 ||
3704  smtp_state->bdat_chunk_len != 51 ||
3705  smtp_state->bdat_chunk_idx != 32) {
3706  printf("smtp parser in inconsistent state\n");
3707  goto end;
3708  }
3709 
3710  FLOWLOCK_WRLOCK(&f);
3711  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3712  STREAM_TOSERVER, request6, request6_len);
3713  if (r != 0) {
3714  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3715  FLOWLOCK_UNLOCK(&f);
3716  goto end;
3717  }
3718  FLOWLOCK_UNLOCK(&f);
3719  if (smtp_state->input_len != 0 ||
3720  smtp_state->cmds_cnt != 1 ||
3721  smtp_state->cmds_idx != 0 ||
3723  smtp_state->bdat_chunk_len != 51 ||
3724  smtp_state->bdat_chunk_idx != 51) {
3725  printf("smtp parser in inconsistent state\n");
3726  goto end;
3727  }
3728 
3729  result = 1;
3730 end:
3731  if (alp_tctx != NULL)
3733  StreamTcpFreeConfig(true);
3734  FLOW_DESTROY(&f);
3735  return result;
3736 }
3737 
3738 /*
3739  * \test Test retrieving lines when frag'ed.
3740  */
3741 static int SMTPParserTest07(void)
3742 {
3743  int result = 0;
3744  Flow f;
3745  int r = 0;
3746 
3747  const char *request1_str = "EHLO boo.com";
3748  /* EHLO boo.com<CR> */
3749  uint8_t request1_1[] = {
3750  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3751  0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3752  };
3753  int32_t request1_1_len = sizeof(request1_1);
3754 
3755  /* <LF> */
3756  uint8_t request1_2[] = {
3757  0x0a
3758  };
3759  int32_t request1_2_len = sizeof(request1_2);
3760 
3761  /* EHLO boo.com<CR><LF> */
3762  uint8_t request2[] = {
3763  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3764  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3765  };
3766  int32_t request2_len = sizeof(request2);
3767 
3768  TcpSession ssn;
3770 
3771  memset(&f, 0, sizeof(f));
3772  memset(&ssn, 0, sizeof(ssn));
3773 
3774  FLOW_INITIALIZE(&f);
3775  f.protoctx = (void *)&ssn;
3776  f.proto = IPPROTO_TCP;
3777  f.alproto = ALPROTO_SMTP;
3778 
3779  StreamTcpInitConfig(true);
3780  SMTPTestInitConfig();
3781 
3782  FLOWLOCK_WRLOCK(&f);
3783  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3784  STREAM_TOSERVER, request1_1, request1_1_len);
3785  if (r != 0) {
3786  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3787  FLOWLOCK_UNLOCK(&f);
3788  goto end;
3789  }
3790  FLOWLOCK_UNLOCK(&f);
3791  SMTPState *smtp_state = f.alstate;
3792  if (smtp_state == NULL) {
3793  printf("no smtp state: ");
3794  goto end;
3795  }
3796  if (smtp_state->current_line != NULL ||
3797  smtp_state->current_line_len != 0 ||
3798  smtp_state->ts_current_line_db != 1 ||
3799  smtp_state->ts_db == NULL ||
3800  smtp_state->ts_db_len != request1_1_len ||
3801  memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3802  printf("smtp parser in inconsistent state\n");
3803  goto end;
3804  }
3805 
3806  FLOWLOCK_WRLOCK(&f);
3807  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3808  STREAM_TOSERVER, request1_2, request1_2_len);
3809  if (r != 0) {
3810  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3811  FLOWLOCK_UNLOCK(&f);
3812  goto end;
3813  }
3814  FLOWLOCK_UNLOCK(&f);
3815  if (smtp_state->ts_current_line_db != 1 ||
3816  smtp_state->ts_db == NULL ||
3817  smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3818  memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3819  smtp_state->current_line != smtp_state->ts_db ||
3820  smtp_state->current_line_len != smtp_state->ts_db_len) {
3821  printf("smtp parser in inconsistent state\n");
3822  goto end;
3823  }
3824 
3825  FLOWLOCK_WRLOCK(&f);
3826  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3827  STREAM_TOSERVER, request2, request2_len);
3828  if (r != 0) {
3829  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3830  FLOWLOCK_UNLOCK(&f);
3831  goto end;
3832  }
3833  FLOWLOCK_UNLOCK(&f);
3834  if (smtp_state->ts_current_line_db != 0 ||
3835  smtp_state->ts_db != NULL ||
3836  smtp_state->ts_db_len != 0 ||
3837  smtp_state->current_line == NULL ||
3838  smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
3839  memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3840  printf("smtp parser in inconsistent state\n");
3841  goto end;
3842  }
3843 
3844  result = 1;
3845 end:
3846  if (alp_tctx != NULL)
3848  StreamTcpFreeConfig(true);
3849  FLOW_DESTROY(&f);
3850  return result;
3851 }
3852 
3853 /*
3854  * \test Test retrieving lines when frag'ed.
3855  */
3856 static int SMTPParserTest08(void)
3857 {
3858  int result = 0;
3859  Flow f;
3860  int r = 0;
3861 
3862  const char *request1_str = "EHLO boo.com";
3863  /* EHLO boo.com */
3864  uint8_t request1_1[] = {
3865  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3866  0x2e, 0x63, 0x6f, 0x6d,
3867  };
3868  int32_t request1_1_len = sizeof(request1_1);
3869 
3870  /* <CR><LF> */
3871  uint8_t request1_2[] = {
3872  0x0d, 0x0a
3873  };
3874  int32_t request1_2_len = sizeof(request1_2);
3875 
3876  /* EHLO boo.com<CR><LF> */
3877  uint8_t request2[] = {
3878  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3879  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3880  };
3881  int32_t request2_len = sizeof(request2);
3882 
3883  TcpSession ssn;
3885 
3886  memset(&f, 0, sizeof(f));
3887  memset(&ssn, 0, sizeof(ssn));
3888 
3889  FLOW_INITIALIZE(&f);
3890  f.protoctx = (void *)&ssn;
3891  f.proto = IPPROTO_TCP;
3892  f.alproto = ALPROTO_SMTP;
3893 
3894  StreamTcpInitConfig(true);
3895  SMTPTestInitConfig();
3896 
3897  FLOWLOCK_WRLOCK(&f);
3898  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3899  STREAM_TOSERVER, request1_1, request1_1_len);
3900  if (r != 0) {
3901  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3902  FLOWLOCK_UNLOCK(&f);
3903  goto end;
3904  }
3905  FLOWLOCK_UNLOCK(&f);
3906  SMTPState *smtp_state = f.alstate;
3907  if (smtp_state == NULL) {
3908  printf("no smtp state: ");
3909  goto end;
3910  }
3911  if (smtp_state->current_line != NULL ||
3912  smtp_state->current_line_len != 0 ||
3913  smtp_state->ts_current_line_db != 1 ||
3914  smtp_state->ts_db == NULL ||
3915  smtp_state->ts_db_len != request1_1_len ||
3916  memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3917  printf("smtp parser in inconsistent state\n");
3918  goto end;
3919  }
3920 
3921  FLOWLOCK_WRLOCK(&f);
3922  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3923  STREAM_TOSERVER, request1_2, request1_2_len);
3924  if (r != 0) {
3925  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3926  FLOWLOCK_UNLOCK(&f);
3927  goto end;
3928  }
3929  FLOWLOCK_UNLOCK(&f);
3930  if (smtp_state->ts_current_line_db != 1 ||
3931  smtp_state->ts_db == NULL ||
3932  smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3933  memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3934  smtp_state->current_line != smtp_state->ts_db ||
3935  smtp_state->current_line_len != smtp_state->ts_db_len) {
3936  printf("smtp parser in inconsistent state\n");
3937  goto end;
3938  }
3939 
3940  FLOWLOCK_WRLOCK(&f);
3941  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3942  STREAM_TOSERVER, request2, request2_len);
3943  if (r != 0) {
3944  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3945  FLOWLOCK_UNLOCK(&f);
3946  goto end;
3947  }
3948  FLOWLOCK_UNLOCK(&f);
3949  if (smtp_state->ts_current_line_db != 0 ||
3950  smtp_state->ts_db != NULL ||
3951  smtp_state->ts_db_len != 0 ||
3952  smtp_state->current_line == NULL ||
3953  smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
3954  memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3955  printf("smtp parser in inconsistent state\n");
3956  goto end;
3957  }
3958 
3959  result = 1;
3960 end:
3961  if (alp_tctx != NULL)
3963  StreamTcpFreeConfig(true);
3964  FLOW_DESTROY(&f);
3965  return result;
3966 }
3967 
3968 /*
3969  * \test Test retrieving lines when frag'ed.
3970  */
3971 static int SMTPParserTest09(void)
3972 {
3973  int result = 0;
3974  Flow f;
3975  int r = 0;
3976 
3977  const char *request1_str = "EHLO boo.com";
3978  /* EHLO boo. */
3979  uint8_t request1_1[] = {
3980  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3981  0x2e,
3982  };
3983  int32_t request1_1_len = sizeof(request1_1);
3984 
3985  /* com<CR><LF> */
3986  uint8_t request1_2[] = {
3987  0x63, 0x6f, 0x6d, 0x0d, 0x0a
3988  };
3989  int32_t request1_2_len = sizeof(request1_2);
3990 
3991  /* EHLO boo.com<CR><LF> */
3992  uint8_t request2[] = {
3993  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3994  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3995  };
3996  int32_t request2_len = sizeof(request2);
3997 
3998  TcpSession ssn;
4000 
4001  memset(&f, 0, sizeof(f));
4002  memset(&ssn, 0, sizeof(ssn));
4003 
4004  FLOW_INITIALIZE(&f);
4005  f.protoctx = (void *)&ssn;
4006  f.proto = IPPROTO_TCP;
4007  f.alproto = ALPROTO_SMTP;
4008 
4009  StreamTcpInitConfig(true);
4010  SMTPTestInitConfig();
4011 
4012  FLOWLOCK_WRLOCK(&f);
4013  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4014  STREAM_TOSERVER, request1_1, request1_1_len);
4015  if (r != 0) {
4016  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4017  FLOWLOCK_UNLOCK(&f);
4018  goto end;
4019  }
4020  FLOWLOCK_UNLOCK(&f);
4021  SMTPState *smtp_state = f.alstate;
4022  if (smtp_state == NULL) {
4023  printf("no smtp state: ");
4024  goto end;
4025  }
4026  if (smtp_state->current_line != NULL ||
4027  smtp_state->current_line_len != 0 ||
4028  smtp_state->ts_current_line_db != 1 ||
4029  smtp_state->ts_db == NULL ||
4030  smtp_state->ts_db_len != request1_1_len ||
4031  memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
4032  printf("smtp parser in inconsistent state\n");
4033  goto end;
4034  }
4035 
4036  FLOWLOCK_WRLOCK(&f);
4037  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4038  STREAM_TOSERVER, request1_2, request1_2_len);
4039  if (r != 0) {
4040  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4041  FLOWLOCK_UNLOCK(&f);
4042  goto end;
4043  }
4044  FLOWLOCK_UNLOCK(&f);
4045  if (smtp_state->ts_current_line_db != 1 ||
4046  smtp_state->ts_db == NULL ||
4047  smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
4048  memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
4049  smtp_state->current_line != smtp_state->ts_db ||
4050  smtp_state->current_line_len != smtp_state->ts_db_len) {
4051  printf("smtp parser in inconsistent state\n");
4052  goto end;
4053  }
4054 
4055  FLOWLOCK_WRLOCK(&f);
4056  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4057  STREAM_TOSERVER, request2, request2_len);
4058  if (r != 0) {
4059  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4060  FLOWLOCK_UNLOCK(&f);
4061  goto end;
4062  }
4063  FLOWLOCK_UNLOCK(&f);
4064  if (smtp_state->ts_current_line_db != 0 ||
4065  smtp_state->ts_db != NULL ||
4066  smtp_state->ts_db_len != 0 ||
4067  smtp_state->current_line == NULL ||
4068  smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
4069  memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
4070  printf("smtp parser in inconsistent state\n");
4071  goto end;
4072  }
4073 
4074  result = 1;
4075 end:
4076  if (alp_tctx != NULL)
4078  StreamTcpFreeConfig(true);
4079  FLOW_DESTROY(&f);
4080  return result;
4081 }
4082 
4083 /*
4084  * \test Test retrieving lines when frag'ed.
4085  */
4086 static int SMTPParserTest10(void)
4087 {
4088  int result = 0;
4089  Flow f;
4090  int r = 0;
4091 
4092  const char *request1_str = "";
4093  /* EHLO boo. */
4094  uint8_t request1_1[] = {
4095  0x0d,
4096  };
4097  int32_t request1_1_len = sizeof(request1_1);
4098 
4099  /* com<CR><LF> */
4100  uint8_t request1_2[] = {
4101  0x0a,
4102  };
4103  int32_t request1_2_len = sizeof(request1_2);
4104 
4105  const char *request2_str = "EHLO boo.com";
4106  /* EHLO boo.com<CR><LF> */
4107  uint8_t request2[] = {
4108  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4109  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4110  };
4111  int32_t request2_len = sizeof(request2);
4112 
4113  TcpSession ssn;
4115 
4116  memset(&f, 0, sizeof(f));
4117  memset(&ssn, 0, sizeof(ssn));
4118 
4119  FLOW_INITIALIZE(&f);
4120  f.protoctx = (void *)&ssn;
4121  f.proto = IPPROTO_TCP;
4122  f.alproto = ALPROTO_SMTP;
4123 
4124  StreamTcpInitConfig(true);
4125  SMTPTestInitConfig();
4126 
4127  FLOWLOCK_WRLOCK(&f);
4128  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4129  STREAM_TOSERVER, request1_1, request1_1_len);
4130  if (r != 0) {
4131  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4132  FLOWLOCK_UNLOCK(&f);
4133  goto end;
4134  }
4135  FLOWLOCK_UNLOCK(&f);
4136  SMTPState *smtp_state = f.alstate;
4137  if (smtp_state == NULL) {
4138  printf("no smtp state: ");
4139  goto end;
4140  }
4141  if (smtp_state->current_line != NULL ||
4142  smtp_state->current_line_len != 0 ||
4143  smtp_state->ts_current_line_db != 1 ||
4144  smtp_state->ts_db == NULL ||
4145  smtp_state->ts_db_len != request1_1_len ||
4146  memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
4147  printf("smtp parser in inconsistent state\n");
4148  goto end;
4149  }
4150 
4151  FLOWLOCK_WRLOCK(&f);
4152  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4153  STREAM_TOSERVER, request1_2, request1_2_len);
4154  if (r != 0) {
4155  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4156  FLOWLOCK_UNLOCK(&f);
4157  goto end;
4158  }
4159  FLOWLOCK_UNLOCK(&f);
4160  if (smtp_state->ts_current_line_db != 1 ||
4161  smtp_state->ts_db == NULL ||
4162  smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
4163  memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
4164  smtp_state->current_line != smtp_state->ts_db ||
4165  smtp_state->current_line_len != smtp_state->ts_db_len) {
4166  printf("smtp parser in inconsistent state\n");
4167  goto end;
4168  }
4169 
4170  FLOWLOCK_WRLOCK(&f);
4171  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4172  STREAM_TOSERVER, request2, request2_len);
4173  if (r != 0) {
4174  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4175  FLOWLOCK_UNLOCK(&f);
4176  goto end;
4177  }
4178  FLOWLOCK_UNLOCK(&f);
4179  if (smtp_state->ts_current_line_db != 0 ||
4180  smtp_state->ts_db != NULL ||
4181  smtp_state->ts_db_len != 0 ||
4182  smtp_state->current_line == NULL ||
4183  smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
4184  memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
4185  printf("smtp parser in inconsistent state\n");
4186  goto end;
4187  }
4188 
4189  result = 1;
4190 end:
4191  if (alp_tctx != NULL)
4193  StreamTcpFreeConfig(true);
4194  FLOW_DESTROY(&f);
4195  return result;
4196 }
4197 
4198 /*
4199  * \test Test retrieving lines when frag'ed.
4200  */
4201 static int SMTPParserTest11(void)
4202 {
4203  int result = 0;
4204  Flow f;
4205  int r = 0;
4206 
4207  const char *request1_str = "";
4208  /* EHLO boo. */
4209  uint8_t request1[] = {
4210  0x0a,
4211  };
4212  int32_t request1_len = sizeof(request1);
4213 
4214  const char *request2_str = "EHLO boo.com";
4215  /* EHLO boo.com<CR><LF> */
4216  uint8_t request2[] = {
4217  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4218  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4219  };
4220  int32_t request2_len = sizeof(request2);
4221 
4222  TcpSession ssn;
4224 
4225  memset(&f, 0, sizeof(f));
4226  memset(&ssn, 0, sizeof(ssn));
4227 
4228  FLOW_INITIALIZE(&f);
4229  f.protoctx = (void *)&ssn;
4230  f.proto = IPPROTO_TCP;
4231  f.alproto = ALPROTO_SMTP;
4232 
4233  StreamTcpInitConfig(true);
4234  SMTPTestInitConfig();
4235 
4236  FLOWLOCK_WRLOCK(&f);
4237  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4238  STREAM_TOSERVER, request1, request1_len);
4239  if (r != 0) {
4240  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4241  FLOWLOCK_UNLOCK(&f);
4242  goto end;
4243  }
4244  FLOWLOCK_UNLOCK(&f);
4245  SMTPState *smtp_state = f.alstate;
4246  if (smtp_state == NULL) {
4247  printf("no smtp state: ");
4248  goto end;
4249  }
4250  if (smtp_state->current_line == NULL ||
4251  smtp_state->current_line_len != 0 ||
4252  smtp_state->ts_current_line_db == 1 ||
4253  smtp_state->ts_db != NULL ||
4254  smtp_state->ts_db_len != 0 ||
4255  memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
4256  printf("smtp parser in inconsistent state\n");
4257  goto end;
4258  }
4259 
4260  FLOWLOCK_WRLOCK(&f);
4261  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4262  STREAM_TOSERVER, request2, request2_len);
4263  if (r != 0) {
4264  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4265  FLOWLOCK_UNLOCK(&f);
4266  goto end;
4267  }
4268  FLOWLOCK_UNLOCK(&f);
4269  if (smtp_state->ts_current_line_db != 0 ||
4270  smtp_state->ts_db != NULL ||
4271  smtp_state->ts_db_len != 0 ||
4272  smtp_state->current_line == NULL ||
4273  smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
4274  memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
4275  printf("smtp parser in inconsistent state\n");
4276  goto end;
4277  }
4278 
4279  result = 1;
4280 end:
4281  if (alp_tctx != NULL)
4283  StreamTcpFreeConfig(true);
4284  FLOW_DESTROY(&f);
4285  return result;
4286 }
4287 
4288 static int SMTPParserTest12(void)
4289 {
4290  int result = 0;
4291  Signature *s = NULL;
4292  ThreadVars th_v;
4293  Packet *p = NULL;
4294  Flow f;
4295  TcpSession ssn;
4296  DetectEngineThreadCtx *det_ctx = NULL;
4297  DetectEngineCtx *de_ctx = NULL;
4298  SMTPState *smtp_state = NULL;
4299  int r = 0;
4300 
4301  /* EHLO boo.com<CR><LF> */
4302  uint8_t request1[] = {
4303  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4304  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4305  };
4306  int32_t request1_len = sizeof(request1);
4307 
4308  /* 388<CR><LF>
4309  */
4310  uint8_t reply1[] = {
4311  0x31, 0x38, 0x38, 0x0d, 0x0a,
4312  };
4313  uint32_t reply1_len = sizeof(reply1);
4314 
4316 
4317  memset(&th_v, 0, sizeof(th_v));
4318  memset(&f, 0, sizeof(f));
4319  memset(&ssn, 0, sizeof(ssn));
4320 
4321  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
4322 
4323  FLOW_INITIALIZE(&f);
4324  f.protoctx = (void *)&ssn;
4325  f.proto = IPPROTO_TCP;
4326  f.alproto = ALPROTO_SMTP;
4327  p->flow = &f;
4331  f.alproto = ALPROTO_SMTP;
4332 
4333  StreamTcpInitConfig(true);
4334  SMTPTestInitConfig();
4335 
4337  if (de_ctx == NULL)
4338  goto end;
4339 
4340  de_ctx->flags |= DE_QUIET;
4341 
4342  s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any "
4343  "(msg:\"SMTP event handling\"; "
4344  "app-layer-event: smtp.invalid_reply; "
4345  "sid:1;)");
4346  if (s == NULL)
4347  goto end;
4348 
4350  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4351 
4352  FLOWLOCK_WRLOCK(&f);
4353  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4354  STREAM_TOSERVER | STREAM_START, request1,
4355  request1_len);
4356  if (r != 0) {
4357  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4358  FLOWLOCK_UNLOCK(&f);
4359  goto end;
4360  }
4361  FLOWLOCK_UNLOCK(&f);
4362 
4363  smtp_state = f.alstate;
4364  if (smtp_state == NULL) {
4365  printf("no smtp state: ");
4366  goto end;
4367  }
4368 
4369  /* do detect */
4370  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4371 
4372  if (PacketAlertCheck(p, 1)) {
4373  printf("sid 1 matched. It shouldn't match: ");
4374  goto end;
4375  }
4376 
4377  FLOWLOCK_WRLOCK(&f);
4378  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4379  STREAM_TOCLIENT | STREAM_TOCLIENT, reply1,
4380  reply1_len);
4381  if (r == 0) {
4382  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4383  FLOWLOCK_UNLOCK(&f);
4384  goto end;
4385  }
4386  FLOWLOCK_UNLOCK(&f);
4387 
4388  /* do detect */
4389  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4390 
4391  if (!PacketAlertCheck(p, 1)) {
4392  printf("sid 1 didn't match. Should have matched: ");
4393  goto end;
4394  }
4395 
4396  result = 1;
4397 
4398 end:
4401 
4402  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4404 
4405  if (alp_tctx != NULL)
4407  StreamTcpFreeConfig(true);
4408  FLOW_DESTROY(&f);
4409  UTHFreePackets(&p, 1);
4410  return result;
4411 }
4412 
4413 static int SMTPParserTest13(void)
4414 {
4415  int result = 0;
4416  Signature *s = NULL;
4417  ThreadVars th_v;
4418  Packet *p = NULL;
4419  Flow f;
4420  TcpSession ssn;
4421  DetectEngineThreadCtx *det_ctx = NULL;
4422  DetectEngineCtx *de_ctx = NULL;
4423  SMTPState *smtp_state = NULL;
4424  int r = 0;
4425 
4426  /* EHLO boo.com<CR><LF> */
4427  uint8_t request1[] = {
4428  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4429  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4430  };
4431  int32_t request1_len = sizeof(request1);
4432 
4433  /* 250<CR><LF>
4434  */
4435  uint8_t reply1[] = {
4436  0x32, 0x35, 0x30, 0x0d, 0x0a,
4437  };
4438  uint32_t reply1_len = sizeof(reply1);
4439 
4440  /* MAIL FROM:pbsf@asdfs.com<CR><LF>
4441  * RCPT TO:pbsf@asdfs.com<CR><LF>
4442  * DATA<CR><LF>
4443  * STARTTLS<CR><LF>
4444  */
4445  uint8_t request2[] = {
4446  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
4447  0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
4448  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
4449  0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
4450  0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
4451  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
4452  0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
4453  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
4454  0x0d, 0x0a
4455  };
4456  uint32_t request2_len = sizeof(request2);
4457 
4459 
4460  memset(&th_v, 0, sizeof(th_v));
4461  memset(&f, 0, sizeof(f));
4462  memset(&ssn, 0, sizeof(ssn));
4463 
4464  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
4465 
4466  FLOW_INITIALIZE(&f);
4467  f.protoctx = (void *)&ssn;
4468  f.proto = IPPROTO_TCP;
4469  f.alproto = ALPROTO_SMTP;
4470  p->flow = &f;
4474  f.alproto = ALPROTO_SMTP;
4475 
4476  StreamTcpInitConfig(true);
4477  SMTPTestInitConfig();
4478 
4480  if (de_ctx == NULL)
4481  goto end;
4482 
4483  de_ctx->flags |= DE_QUIET;
4484 
4485  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
4486  "(msg:\"SMTP event handling\"; "
4487  "app-layer-event: "
4488  "smtp.invalid_pipelined_sequence; "
4489  "sid:1;)");
4490  if (s == NULL)
4491  goto end;
4492 
4494  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4495 
4496  FLOWLOCK_WRLOCK(&f);
4497  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4498  STREAM_TOSERVER | STREAM_START, request1,
4499  request1_len);
4500  if (r != 0) {
4501  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4502  FLOWLOCK_UNLOCK(&f);
4503  goto end;
4504  }
4505  FLOWLOCK_UNLOCK(&f);
4506 
4507  smtp_state = f.alstate;
4508  if (smtp_state == NULL) {
4509  printf("no smtp state: ");
4510  goto end;
4511  }
4512 
4513  /* do detect */
4514  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4515 
4516  if (PacketAlertCheck(p, 1)) {
4517  printf("sid 1 matched. It shouldn't match: ");
4518  goto end;
4519  }
4520 
4521  FLOWLOCK_WRLOCK(&f);
4522  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4523  STREAM_TOCLIENT, reply1, reply1_len);
4524  if (r != 0) {
4525  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4526  FLOWLOCK_UNLOCK(&f);
4527  goto end;
4528  }
4529  FLOWLOCK_UNLOCK(&f);
4530 
4531  /* do detect */
4532  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4533 
4534  if (PacketAlertCheck(p, 1)) {
4535  printf("sid 1 matched. It shouldn't match: ");
4536  goto end;
4537  }
4538 
4539  FLOWLOCK_WRLOCK(&f);
4540  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4541  STREAM_TOSERVER, request2, request2_len);
4542  if (r != 0) {
4543  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4544  FLOWLOCK_UNLOCK(&f);
4545  goto end;
4546  }
4547  FLOWLOCK_UNLOCK(&f);
4548 
4549  /* do detect */
4550  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4551 
4552  if (!PacketAlertCheck(p, 1)) {
4553  printf("sid 1 didn't match. Should have matched: ");
4554  goto end;
4555  }
4556 
4557  result = 1;
4558 
4559 end:
4562 
4563  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4565 
4566  if (alp_tctx != NULL)
4568  StreamTcpFreeConfig(true);
4569  FLOW_DESTROY(&f);
4570  UTHFreePackets(&p, 1);
4571  return result;
4572 }
4573 
4574 /**
4575  * \test Test DATA command w/MIME message.
4576  */
4577 static int SMTPParserTest14(void)
4578 {
4579  int result = 0;
4580  Flow f;
4581  int r = 0;
4582 
4583  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
4584  static uint8_t welcome_reply[] = {
4585  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
4586  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
4587  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
4588  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
4589  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
4590  0x0d, 0x0a
4591  };
4592  static uint32_t welcome_reply_len = sizeof(welcome_reply);
4593 
4594  /* EHLO boo.com<CR><LF> */
4595  static uint8_t request1[] = {
4596  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4597  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
4598  };
4599  static uint32_t request1_len = sizeof(request1);
4600  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
4601  * 250-SIZE 35882577<CR><LF>
4602  * 250-8BITMIME<CR><LF>
4603  * 250-STARTTLS<CR><LF>
4604  * 250 ENHANCEDSTATUSCODES<CR><LF>
4605  */
4606  static uint8_t reply1[] = {
4607  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
4608  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
4609  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
4610  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
4611  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
4612  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
4613  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
4614  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
4615  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
4616  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
4617  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
4618  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
4619  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
4620  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
4621  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
4622  };
4623  static uint32_t reply1_len = sizeof(reply1);
4624 
4625  /* MAIL FROM:asdff@asdf.com<CR><LF> */
4626  static uint8_t request2[] = {
4627  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
4628  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
4629  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
4630  0x0d, 0x0a
4631  };
4632  static uint32_t request2_len = sizeof(request2);
4633  /* 250 2.1.0 Ok<CR><LF> */
4634  static uint8_t reply2[] = {
4635  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4636  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4637  };
4638  static uint32_t reply2_len = sizeof(reply2);
4639 
4640  /* RCPT TO:bimbs@gmail.com<CR><LF> */
4641  static uint8_t request3[] = {
4642  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
4643  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
4644  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
4645  0x0a
4646  };
4647  static uint32_t request3_len = sizeof(request3);
4648  /* 250 2.1.5 Ok<CR><LF> */
4649  static uint8_t reply3[] = {
4650  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4651  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4652  };
4653  static uint32_t reply3_len = sizeof(reply3);
4654 
4655  /* DATA<CR><LF> */
4656  static uint8_t request4[] = {
4657  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
4658  };
4659  static uint32_t request4_len = sizeof(request4);
4660  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
4661  static uint8_t reply4[] = {
4662  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
4663  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
4664  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
4665  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
4666  0x4c, 0x46, 0x3e, 0x0d, 0x0a
4667  };
4668  static uint32_t reply4_len = sizeof(reply4);
4669 
4670  /* MIME_MSG */
4671  static uint64_t filesize = 133;
4672  static uint8_t request4_msg[] = {
4673  0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
4674  0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
4675  0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4676  0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
4677  0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
4678  0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
4679  0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
4680  0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4681  0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
4682  0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
4683  0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
4684  0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
4685  0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
4686  0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
4687  0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
4688  0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
4689  0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
4690  0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
4691  0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
4692  0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
4693  0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
4694  0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
4695  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4696  0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
4697  0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
4698  0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
4699  0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
4700  0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
4701  0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
4702  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4703  0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
4704  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4705  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4706  0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
4707  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4708  0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4709  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4710  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4711  0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
4712  0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
4713  0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
4714  0x41, 0x3D, 0x3D, 0x0D,0x0A };
4715  static uint32_t request4_msg_len = sizeof(request4_msg);
4716 
4717  /* DATA COMPLETED */
4718  static uint8_t request4_end[] = {
4719  0x0d, 0x0a, 0x2e, 0x0d, 0x0a
4720  };
4721  static uint32_t request4_end_len = sizeof(request4_end);
4722  /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
4723  static uint8_t reply4_end[] = {
4724  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4725  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
4726  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
4727  0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
4728  0x46, 0x32, 0x0d, 0x0a
4729  };
4730  static uint32_t reply4_end_len = sizeof(reply4_end);
4731 
4732  /* QUIT<CR><LF> */
4733  static uint8_t request5[] = {
4734  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
4735  };
4736  static uint32_t request5_len = sizeof(request5);
4737  /* 221 2.0.0 Bye<CR><LF> */
4738  static uint8_t reply5[] = {
4739  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4740  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
4741  };
4742  static uint32_t reply5_len = sizeof(reply5);
4743 
4744  TcpSession ssn;
4746 
4747  memset(&f, 0, sizeof(f));
4748  memset(&ssn, 0, sizeof(ssn));
4749 
4750  FLOW_INITIALIZE(&f);
4751  f.protoctx = (void *)&ssn;
4752  f.proto = IPPROTO_TCP;
4753  f.alproto = ALPROTO_SMTP;
4754 
4755  StreamTcpInitConfig(true);
4756  SMTPTestInitConfig();
4757 
4758  FLOWLOCK_WRLOCK(&f);
4759  /* Welcome reply */
4760  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4761  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
4762  if (r != 0) {
4763  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4764  FLOWLOCK_UNLOCK(&f);
4765  goto end;
4766  }
4767  FLOWLOCK_UNLOCK(&f);
4768  SMTPState *smtp_state = f.alstate;
4769  if (smtp_state == NULL) {
4770  printf("no smtp state: ");
4771  goto end;
4772  }
4773  if (smtp_state->input_len != 0 ||
4774  smtp_state->cmds_cnt != 0 ||
4775  smtp_state->cmds_idx != 0 ||
4777  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4778  goto end;
4779  }
4780 
4781  FLOWLOCK_WRLOCK(&f);
4782  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4783  STREAM_TOSERVER, request1, request1_len);
4784  if (r != 0) {
4785  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4786  FLOWLOCK_UNLOCK(&f);
4787  goto end;
4788  }
4789  FLOWLOCK_UNLOCK(&f);
4790  if (smtp_state->input_len != 0 ||
4791  smtp_state->cmds_cnt != 1 ||
4792  smtp_state->cmds_idx != 0 ||
4793  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4795  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4796  goto end;
4797  }
4798 
4799  FLOWLOCK_WRLOCK(&f);
4800  /* EHLO Reply */
4801  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4802  STREAM_TOCLIENT, reply1, reply1_len);
4803  if (r != 0) {
4804  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4805  FLOWLOCK_UNLOCK(&f);
4806  goto end;
4807  }
4808 
4809  if ((smtp_state->helo_len != 7) || strncmp("boo.com", (char *)smtp_state->helo, 7)) {
4810  printf("incorrect parsing of HELO field '%s' (%d)\n", smtp_state->helo, smtp_state->helo_len);
4811  FLOWLOCK_UNLOCK(&f);
4812  goto end;
4813  }
4814 
4815  FLOWLOCK_UNLOCK(&f);
4816  if (smtp_state->input_len != 0 ||
4817  smtp_state->cmds_cnt != 0 ||
4818  smtp_state->cmds_idx != 0 ||
4820  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4821  goto end;
4822  }
4823 
4824  FLOWLOCK_WRLOCK(&f);
4825  /* MAIL FROM Request */
4826  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4827  STREAM_TOSERVER, request2, request2_len);
4828  if (r != 0) {
4829  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4830  FLOWLOCK_UNLOCK(&f);
4831  goto end;
4832  }
4833  FLOWLOCK_UNLOCK(&f);
4834  if (smtp_state->input_len != 0 ||
4835  smtp_state->cmds_cnt != 1 ||
4836  smtp_state->cmds_idx != 0 ||
4837  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4839  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4840  goto end;
4841  }
4842 
4843  FLOWLOCK_WRLOCK(&f);
4844  /* MAIL FROM Reply */
4845  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4846  STREAM_TOCLIENT, reply2, reply2_len);
4847  if (r != 0) {
4848  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4849  FLOWLOCK_UNLOCK(&f);
4850  goto end;
4851  }
4852 
4853  if ((smtp_state->curr_tx->mail_from_len != 14) ||
4854  strncmp("asdff@asdf.com", (char *)smtp_state->curr_tx->mail_from, 14)) {
4855  printf("incorrect parsing of MAIL FROM field '%s' (%d)\n",
4856  smtp_state->curr_tx->mail_from,
4857  smtp_state->curr_tx->mail_from_len);
4858  FLOWLOCK_UNLOCK(&f);
4859  goto end;
4860  }
4861 
4862  FLOWLOCK_UNLOCK(&f);
4863  if (smtp_state->input_len != 0 ||
4864  smtp_state->cmds_cnt != 0 ||
4865  smtp_state->cmds_idx != 0 ||
4867  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4868  goto end;
4869  }
4870 
4871  FLOWLOCK_WRLOCK(&f);
4872  /* RCPT TO Request */
4873  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4874  STREAM_TOSERVER, request3, request3_len);
4875  if (r != 0) {
4876  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4877  FLOWLOCK_UNLOCK(&f);
4878  goto end;
4879  }
4880  FLOWLOCK_UNLOCK(&f);
4881  if (smtp_state->input_len != 0 ||
4882  smtp_state->cmds_cnt != 1 ||
4883  smtp_state->cmds_idx != 0 ||
4884  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4886  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4887  goto end;
4888  }
4889 
4890  FLOWLOCK_WRLOCK(&f);
4891  /* RCPT TO Reply */
4892  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4893  STREAM_TOCLIENT, reply3, reply3_len);
4894  if (r != 0) {
4895  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4896  FLOWLOCK_UNLOCK(&f);
4897  goto end;
4898  }
4899  FLOWLOCK_UNLOCK(&f);
4900  if (smtp_state->input_len != 0 ||
4901  smtp_state->cmds_cnt != 0 ||
4902  smtp_state->cmds_idx != 0 ||
4904  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4905  goto end;
4906  }
4907 
4908  /* Enable mime decoding */
4913 
4914  FLOWLOCK_WRLOCK(&f);
4915  /* DATA request */
4916  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4917  STREAM_TOSERVER, request4, request4_len);
4918  if (r != 0) {
4919  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4920  FLOWLOCK_UNLOCK(&f);
4921  goto end;
4922  }
4923  FLOWLOCK_UNLOCK(&f);
4924 
4925  if (smtp_state->input_len != 0 ||
4926  smtp_state->cmds_cnt != 1 ||
4927  smtp_state->cmds_idx != 0 ||
4928  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
4930  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4931  goto end;
4932  }
4933 
4934  FLOWLOCK_WRLOCK(&f);
4935  /* Data reply */
4936  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4937  STREAM_TOCLIENT, reply4, reply4_len);
4938  if (r != 0) {
4939  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4940  FLOWLOCK_UNLOCK(&f);
4941  goto end;
4942  }
4943  FLOWLOCK_UNLOCK(&f);
4944  if (smtp_state->input_len != 0 ||
4945  smtp_state->cmds_cnt != 0 ||
4946  smtp_state->cmds_idx != 0 ||
4949  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4950  goto end;
4951  }
4952 
4953  FLOWLOCK_WRLOCK(&f);
4954  /* DATA message */
4955  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4956  STREAM_TOSERVER, request4_msg, request4_msg_len);
4957  if (r != 0) {
4958  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4959  FLOWLOCK_UNLOCK(&f);
4960  goto end;
4961  }
4962  FLOWLOCK_UNLOCK(&f);
4963 
4964  if (smtp_state->input_len != 0 ||
4965  smtp_state->cmds_cnt != 0 ||
4966  smtp_state->cmds_idx != 0 ||
4967  smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */
4970  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4971  goto end;
4972  }
4973 
4974  FLOWLOCK_WRLOCK(&f);
4975  /* DATA . request */
4976  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4977  STREAM_TOSERVER, request4_end, request4_end_len);
4978  if (r != 0) {
4979  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4980  FLOWLOCK_UNLOCK(&f);
4981  goto end;
4982  }
4983  FLOWLOCK_UNLOCK(&f);
4984 
4985  if (smtp_state->input_len != 0 ||
4986  smtp_state->cmds_cnt != 1 ||
4987  smtp_state->cmds_idx != 0 ||
4988  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
4989  smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */
4991  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4992  goto end;
4993  }
4994 
4995  SMTPState *state = (SMTPState *) f.alstate;
4996  FileContainer *files = state->files_ts;
4997  if (files != NULL && files->head != NULL) {
4998  File *file = files->head;
4999 
5000  if(strncmp((const char *)file->name, "test.exe", 8) != 0){
5001  printf("smtp-mime file name is incorrect");
5002  goto end;
5003  }
5004  if (FileTrackedSize(file) != filesize){
5005  printf("smtp-mime file size %"PRIu64" is incorrect", FileDataSize(file));
5006  goto end;
5007  }
5008  static uint8_t org_binary[] = {
5009  0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00,
5010  0x4C, 0x01, 0x01, 0x00, 0x6A, 0x2A, 0x58, 0xC3,
5011  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5012  0x04, 0x00, 0x03, 0x01, 0x0B, 0x01, 0x08, 0x00,
5013  0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
5014  0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
5015  0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
5016  0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00,
5017  0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00,
5018  0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
5019  0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00,
5020  0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5021  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5022  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5023  0x00, 0x00, 0x00, 0x00, 0x5C, 0x5C, 0x36, 0x36,
5024  0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36,
5025  0x5C, 0x7A, 0x00, 0x00, 0x38,};
5026 
5028  org_binary, sizeof(org_binary)) != 1)
5029  {
5030  printf("smtp-mime file data incorrect\n");
5031  goto end;
5032  }
5033  }
5034 
5035  FLOWLOCK_WRLOCK(&f);
5036  /* DATA . reply */
5037  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
5038  STREAM_TOCLIENT, reply4_end, reply4_end_len);
5039  if (r != 0) {
5040  printf("smtp check returned %" PRId32 ", expected 0: ", r);
5041  FLOWLOCK_UNLOCK(&f);
5042  goto end;
5043  }
5044  FLOWLOCK_UNLOCK(&f);
5045  if (smtp_state->input_len != 0 ||
5046  smtp_state->cmds_cnt != 0 ||
5047  smtp_state->cmds_idx != 0 ||
5049  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
5050  goto end;
5051  }
5052 
5053  FLOWLOCK_WRLOCK(&f);
5054  /* QUIT Request */
5055  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
5056  STREAM_TOSERVER, request5, request5_len);
5057  if (r != 0) {
5058  printf("smtp check returned %" PRId32 ", expected 0: ", r);
5059  FLOWLOCK_UNLOCK(&f);
5060  goto end;
5061  }
5062  FLOWLOCK_UNLOCK(&f);
5063  if (smtp_state->input_len != 0 ||
5064  smtp_state->cmds_cnt != 1 ||
5065  smtp_state->cmds_idx != 0 ||
5066  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
5068  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
5069  goto end;
5070  }
5071 
5072  FLOWLOCK_WRLOCK(&f);
5073  /* QUIT Reply */
5074  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
5075  STREAM_TOCLIENT, reply5, reply5_len);
5076  if (r != 0) {
5077  printf("smtp check returned %" PRId32 ", expected 0: ", r);
5078  FLOWLOCK_UNLOCK(&f);
5079  goto end;
5080  }
5081  FLOWLOCK_UNLOCK(&f);
5082  if (smtp_state->input_len != 0 ||
5083  smtp_state->cmds_cnt != 0 ||
5084  smtp_state->cmds_idx != 0 ||
5086  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
5087  goto end;
5088  }
5089 
5090  result = 1;
5091 end:
5092  if (alp_tctx != NULL)
5094  StreamTcpFreeConfig(true);
5095  FLOW_DESTROY(&f);
5096  return result;
5097 }
5098 
5099 static int SMTPProcessDataChunkTest01(void){
5100  Flow f;
5101  FLOW_INITIALIZE(&f);
5103  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5104  int ret;
5105  ret = SMTPProcessDataChunk(NULL, 0, state);
5106 
5107  return ret == 0;
5108 }
5109 
5110 
5111 static int SMTPProcessDataChunkTest02(void){
5112  char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
5113  0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
5114  0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
5115  0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
5116  0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
5117  0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
5118  0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
5119  0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
5120  0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
5121  0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
5122  0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
5123  0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
5124  0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
5125  0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
5126  0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
5127  0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
5128  0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
5129  0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
5130  0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
5131  0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
5132  0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
5133  0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
5134  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
5135  0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
5136  0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
5137  0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
5138  0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
5139  0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
5140  0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
5141  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
5142  0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
5143  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
5144  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
5145  0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
5146  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
5147  0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
5148  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
5149  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
5150  0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
5151  0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
5152  0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
5153  0x41, 0x3D, 0x3D, 0x0D, 0x0A,};
5154 
5155  Flow f;
5156  TcpSession ssn;
5157  memset(&ssn, 0, sizeof(ssn));
5158  FLOW_INITIALIZE(&f);
5159  f.protoctx = &ssn;
5161  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5162  ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
5163  state->body_begin = 1;
5164  int ret;
5165  ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
5166 
5167  return ret == 0;
5168 }
5169 
5170 
5171 
5172 static int SMTPProcessDataChunkTest03(void){
5173  char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, };
5174  char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, };
5175  char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5176  char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, };
5177  char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, };
5178  char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, };
5179  char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, };
5180  char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5181  char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, };
5182  char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, };
5183  char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, };
5184  char mimemsg12[] = {0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F, };
5185 
5186  TcpSession ssn;
5187  memset(&ssn, 0, sizeof(ssn));
5188  Flow f;
5189  FLOW_INITIALIZE(&f);
5190  f.protoctx = &ssn;
5192  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5193  ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
5194  int ret;
5195 
5196  state->body_begin = 1;
5197  ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
5198  if(ret) goto end;
5199  state->body_begin = 0;
5200  ret = SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state);
5201  if(ret) goto end;
5202  ret = SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state);
5203  if(ret) goto end;
5204  ret = SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state);
5205  if(ret) goto end;
5206  ret = SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state);
5207  if(ret) goto end;
5208  ret = SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state);
5209  if(ret) goto end;
5210  ret = SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state);
5211  if(ret) goto end;
5212  ret = SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state);
5213  if(ret) goto end;
5214  ret = SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state);
5215  if(ret) goto end;
5216  ret = SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state);
5217  if(ret) goto end;
5218  ret = SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state);
5219  if(ret) goto end;
5220  state->body_end = 1;
5221  ret = SMTPProcessDataChunk((uint8_t *)mimemsg12, sizeof(mimemsg12), state);
5222  if(ret) goto end;
5223 
5224  end:
5225  return ret == 0;
5226 }
5227 
5228 
5229 static int SMTPProcessDataChunkTest04(void){
5230  char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, };
5231  char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, };
5232  char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5233  char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, };
5234  char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, };
5235  char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, };
5236  char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, };
5237  char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5238  char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, };
5239  char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, };
5240  char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, };
5241 
5242  TcpSession ssn;
5243  memset(&ssn, 0, sizeof(ssn));
5244  Flow f;
5245  FLOW_INITIALIZE(&f);
5246  f.protoctx = &ssn;
5248  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5249  ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
5250  int ret = MIME_DEC_OK;
5251 
5252  state->body_begin = 1;
5253  if(SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state) != 0) goto end;
5254  if(SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state) != 0) goto end;
5255  if(SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state) != 0) goto end;
5256  if(SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state) != 0) goto end;
5257  if(SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state) != 0) goto end;
5258  if(SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state) != 0) goto end;
5259  if(SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state) != 0) goto end;
5260  state->body_begin = 0;
5261  state->body_end = 1;
5262  if(SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state) != 0) goto end;
5263  state->body_end = 0;
5264  if(SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state) != 0) goto end;
5265  if(SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state) != 0) goto end;
5266  if(SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state) != 0) goto end;
5267 
5268  end:
5269  return ret == 0;
5270 }
5271 
5272 static int SMTPProcessDataChunkTest05(void){
5273  char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
5274  0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
5275  0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
5276  0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
5277  0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
5278  0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
5279  0x41, 0x3D, 0x3D, 0x0D, 0x0A,};
5280 
5281  TcpSession ssn;
5282  memset(&ssn, 0, sizeof(ssn));
5283  Flow f;
5284  int ret;
5285  FLOW_INITIALIZE(&f);
5286  f.protoctx = &ssn;
5288  FAIL_IF(f.alstate == NULL);
5289  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5290  ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
5291  FAIL_IF(state == NULL);
5292  state->body_begin = 1;
5293  ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
5294  FAIL_IF(ret != 0);
5295  state->body_begin = 0;
5296  SMTPState *smtp_state = (SMTPState *)((Flow *)state->data)->alstate;
5297  FileContainer *files = smtp_state->files_ts;
5298  FAIL_IF(files == NULL);
5299  File *file = files->head;
5300  FAIL_IF(file == NULL);
5301  ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
5302  FAIL_IF(ret != 0);
5303  FAIL_IF((uint32_t)FileDataSize(file) != 106);
5304  SMTPStateFree(smtp_state);
5305  FLOW_DESTROY(&f);
5306  PASS;
5307 }
5308 
5309 #endif /* UNITTESTS */
5310 
5312 {
5313 #ifdef UNITTESTS
5314  UtRegisterTest("SMTPParserTest01", SMTPParserTest01);
5315  UtRegisterTest("SMTPParserTest02", SMTPParserTest02);
5316  UtRegisterTest("SMTPParserTest03", SMTPParserTest03);
5317  UtRegisterTest("SMTPParserTest04", SMTPParserTest04);
5318  UtRegisterTest("SMTPParserTest05", SMTPParserTest05);
5319  UtRegisterTest("SMTPParserTest06", SMTPParserTest06);
5320  UtRegisterTest("SMTPParserTest07", SMTPParserTest07);
5321  UtRegisterTest("SMTPParserTest08", SMTPParserTest08);
5322  UtRegisterTest("SMTPParserTest09", SMTPParserTest09);
5323  UtRegisterTest("SMTPParserTest10", SMTPParserTest10);
5324  UtRegisterTest("SMTPParserTest11", SMTPParserTest11);
5325  UtRegisterTest("SMTPParserTest12", SMTPParserTest12);
5326  UtRegisterTest("SMTPParserTest13", SMTPParserTest13);
5327  UtRegisterTest("SMTPParserTest14", SMTPParserTest14);
5328  UtRegisterTest("SMTPProcessDataChunkTest01", SMTPProcessDataChunkTest01);
5329  UtRegisterTest("SMTPProcessDataChunkTest02", SMTPProcessDataChunkTest02);
5330  UtRegisterTest("SMTPProcessDataChunkTest03", SMTPProcessDataChunkTest03);
5331  UtRegisterTest("SMTPProcessDataChunkTest04", SMTPProcessDataChunkTest04);
5332  UtRegisterTest("SMTPProcessDataChunkTest05", SMTPProcessDataChunkTest05);
5333 #endif /* UNITTESTS */
5334 
5335  return;
5336 }
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
SMTP_DECODER_EVENT_INVALID_REPLY
@ SMTP_DECODER_EVENT_INVALID_REPLY
Definition: app-layer-smtp.h:34
SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG
@ SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG
Definition: app-layer-smtp.h:53
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:474
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
StreamingBufferConfig_::buf_size
uint32_t buf_size
Definition: util-streaming-buffer.h:70
PKT_HAS_FLOW
#define PKT_HAS_FLOW
Definition: decode.h:1129
AppLayerParserRegisterLocalStorageFunc
void AppLayerParserRegisterLocalStorageFunc(uint8_t ipproto, AppProto alproto, void *(*LocalStorageAlloc)(void), void(*LocalStorageFree)(void *))
Definition: app-layer-parser.c:410
SMTP_PARSER_STATE_FIRST_REPLY_SEEN
#define SMTP_PARSER_STATE_FIRST_REPLY_SEEN
Definition: app-layer-smtp.c:84
TAILQ_INIT
#define TAILQ_INIT(head)
Definition: queue.h:370
ANOM_LONG_BOUNDARY
#define ANOM_LONG_BOUNDARY
Definition: util-decode-mime.h:61
flow-util.h
SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE
@ SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE
Definition: app-layer-smtp.h:40
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
SMTP_DECODER_EVENT_TLS_REJECTED
@ SMTP_DECODER_EVENT_TLS_REJECTED
Definition: app-layer-smtp.h:41
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_REPLY_LINE_LEN_EXCEEDED
@ SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED
Definition: app-layer-smtp.h:37
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:300
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:1977
STREAMING_BUFFER_CONFIG_INITIALIZER
#define STREAMING_BUFFER_CONFIG_INITIALIZER
Definition: util-streaming-buffer.h:77
Packet_::flags
uint32_t flags
Definition: decode.h:451
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:435
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:464
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:757
AppLayerParserRegisterStateProgressCompletionStatus
void AppLayerParserRegisterStateProgressCompletionStatus(AppProto alproto, const int ts, const int tc)
Definition: app-layer-parser.c:526
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:485
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:2070
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:277
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:565
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:40
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:447
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_DATA_COMMAND_REJECTED
@ SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED
Definition: app-layer-smtp.h:42
SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME
@ SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME
Definition: app-layer-smtp.h:51
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_DECODER_EVENT_MIME_PARSE_FAILED
@ SMTP_DECODER_EVENT_MIME_PARSE_FAILED
Definition: app-layer-smtp.h:45
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
StreamTcpInitConfig
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition: stream-tcp.c:365
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_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:153
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:1001
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:424
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
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:397
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_MIME_INVALID_QP
@ SMTP_DECODER_EVENT_MIME_INVALID_QP
Definition: app-layer-smtp.h:48
SMTP_DECODER_EVENT_DUPLICATE_FIELDS
@ SMTP_DECODER_EVENT_DUPLICATE_FIELDS
Definition: app-layer-smtp.h:57
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
AppLayerDecoderEvents_::cnt
uint8_t cnt
Definition: app-layer-events.h:38
smtp_config
SMTPConfig smt