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