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