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