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