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