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