suricata
app-layer-smtp.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2025 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 "decode.h"
27 
28 #include "stream-tcp.h"
29 
30 #include "app-layer.h"
31 #include "app-layer-detect-proto.h"
32 #include "app-layer-protos.h"
33 #include "app-layer-parser.h"
34 #include "app-layer-frames.h"
35 #include "app-layer-events.h"
36 #include "app-layer-smtp.h"
37 
38 #include "util-enum.h"
39 #include "util-mpm.h"
40 #include "util-debug.h"
41 #include "util-byte.h"
42 #include "util-unittest.h"
43 #include "util-unittest-helper.h"
44 #include "util-memcmp.h"
45 #include "flow-util.h"
46 
47 #include "detect-engine.h"
48 #include "detect-engine-state.h"
49 #include "detect-engine-build.h"
50 #include "detect-parse.h"
51 
52 #include "conf.h"
53 
54 #include "util-mem.h"
55 #include "util-misc.h"
56 #include "util-validate.h"
57 
58 /* content-limit default value */
59 #define FILEDATA_CONTENT_LIMIT 100000
60 /* content-inspect-min-size default value */
61 #define FILEDATA_CONTENT_INSPECT_MIN_SIZE 32768
62 /* content-inspect-window default value */
63 #define FILEDATA_CONTENT_INSPECT_WINDOW 4096
64 
65 /* raw extraction default value */
66 #define SMTP_RAW_EXTRACTION_DEFAULT_VALUE false
67 
68 #define SMTP_COMMAND_BUFFER_STEPS 5
69 
70 /* we are in process of parsing a fresh command. Just a placeholder. If we
71  * are not in STATE_COMMAND_DATA_MODE, we have to be in this mode */
72 // unused #define SMTP_PARSER_STATE_COMMAND_MODE 0x00
73 /* we are in mode of parsing a command's data. Used when we are parsing tls
74  * or accepting the rfc 2822 mail after DATA command */
75 #define SMTP_PARSER_STATE_COMMAND_DATA_MODE 0x01
76 /* Used to indicate that the parser has seen the first reply */
77 #define SMTP_PARSER_STATE_FIRST_REPLY_SEEN 0x04
78 /* Used to indicate that the parser is parsing a multiline reply */
79 #define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY 0x08
80 /* Used to indicate that the server supports pipelining */
81 #define SMTP_PARSER_STATE_PIPELINING_SERVER 0x10
82 
83 /* Various SMTP commands
84  * We currently have var-ified just STARTTLS and DATA, since we need to them
85  * for state transitions. The rest are just indicate as OTHER_CMD. Other
86  * commands would be introduced as and when needed */
87 #define SMTP_COMMAND_STARTTLS 1
88 #define SMTP_COMMAND_DATA 2
89 #define SMTP_COMMAND_BDAT 3
90 /* not an actual command per se, but the mode where we accept the mail after
91  * DATA has it's own reply code for completion, from the server. We give this
92  * stage a pseudo command of it's own, so that we can add this to the command
93  * buffer to match with the reply */
94 #define SMTP_COMMAND_DATA_MODE 4
95 /* All other commands are represented by this var */
96 #define SMTP_COMMAND_OTHER_CMD 5
97 #define SMTP_COMMAND_RSET 6
98 #define SMTP_COMMAND_QUIT 7
99 /* Pseudo command used to match the final BDAT reply to its transaction. */
100 #define SMTP_COMMAND_BDAT_LAST 8
101 
102 #define SMTP_DEFAULT_MAX_TX 256
103 
104 /* command buffer tx id for commands with no owning transaction */
105 #define SMTP_NO_TX_ID UINT64_MAX
106 
107 typedef struct SMTPInput_ {
108  /* current input that is being parsed */
109  const uint8_t *buf;
110  int32_t len;
111 
112  /* original length of an input */
113  int32_t orig_len;
114 
115  /* Consumed bytes till current line */
116  int32_t consumed;
118 
119 typedef struct SMTPLine_ {
120  /** current line extracted by the parser from the call to SMTPGetline() */
121  const uint8_t *buf;
122  /** length of the line in current_line. Doesn't include the delimiter */
123  int32_t len;
124  uint8_t delim_len;
125  bool lf_found;
127 
129  { "INVALID_REPLY", SMTP_DECODER_EVENT_INVALID_REPLY },
130  { "UNABLE_TO_MATCH_REPLY_WITH_REQUEST", SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST },
131  { "MAX_COMMAND_LINE_LEN_EXCEEDED", SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED },
132  { "MAX_REPLY_LINE_LEN_EXCEEDED", SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED },
133  { "INVALID_PIPELINED_SEQUENCE", SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE },
134  { "BDAT_CHUNK_LEN_EXCEEDED", SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED },
135  { "INVALID_BDAT", SMTP_DECODER_EVENT_INVALID_BDAT },
136  { "NO_SERVER_WELCOME_MESSAGE", SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE },
137  { "TLS_REJECTED", SMTP_DECODER_EVENT_TLS_REJECTED },
138  { "DATA_COMMAND_REJECTED", SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED },
139  { "FAILED_PROTOCOL_CHANGE", SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE },
140 
141  /* MIME Events */
142  { "MIME_PARSE_FAILED", SMTP_DECODER_EVENT_MIME_PARSE_FAILED },
143  { "MIME_INVALID_BASE64", SMTP_DECODER_EVENT_MIME_INVALID_BASE64 },
144  { "MIME_INVALID_QP", SMTP_DECODER_EVENT_MIME_INVALID_QP },
145  { "MIME_LONG_LINE", SMTP_DECODER_EVENT_MIME_LONG_LINE },
146  { "MIME_LONG_ENC_LINE", SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE },
147  { "MIME_LONG_HEADER_NAME", SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME },
148  { "MIME_LONG_HEADER_VALUE", SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE },
149  { "MIME_LONG_BOUNDARY", SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG },
150  { "MIME_LONG_FILENAME", SMTP_DECODER_EVENT_MIME_LONG_FILENAME },
151 
152  /* Invalid behavior or content */
153  { "DUPLICATE_FIELDS", SMTP_DECODER_EVENT_DUPLICATE_FIELDS },
154  { "UNPARSABLE_CONTENT", SMTP_DECODER_EVENT_UNPARSABLE_CONTENT },
155  { "TRUNCATED_LINE", SMTP_DECODER_EVENT_TRUNCATED_LINE },
156  { NULL, -1 },
157 };
158 
163 };
164 
166  {
167  "command_line",
169  },
170  {
171  "data",
173  },
174  {
175  "response_line",
177  },
178  { NULL, -1 },
179 };
180 
181 static int SMTPGetFrameIdByName(const char *frame_name)
182 {
183  int id = SCMapEnumNameToValue(frame_name, smtp_frame_table);
184  if (id < 0) {
185  return -1;
186  }
187  return id;
188 }
189 
190 static const char *SMTPGetFrameNameById(const uint8_t frame_id)
191 {
192  const char *name = SCMapEnumValueToName(frame_id, smtp_frame_table);
193  return name;
194 }
195 
196 static SCEnumCharMap smtp_state_client_table[] = {
197  { "request_started", SMTP_REQUEST_STARTED },
198  { "request_data", SMTP_REQUEST_DATA },
199  { "request_complete", SMTP_REQUEST_COMPLETE },
200  { NULL, -1 },
201 };
202 
203 static SCEnumCharMap smtp_state_server_table[] = {
204  { "response_started", SMTP_RESPONSE_STARTED },
205  { "response_data", SMTP_RESPONSE_DATA },
206  { "response_complete", SMTP_RESPONSE_COMPLETE },
207  { NULL, -1 },
208 };
209 
210 static int SMTPStateGetStateIdByName(const char *name, const uint8_t direction)
211 {
212  SCEnumCharMap *map =
213  direction == STREAM_TOSERVER ? smtp_state_client_table : smtp_state_server_table;
214  int id = SCMapEnumNameToValue(name, map);
215  if (id < 0) {
216  return -1;
217  }
218  return id;
219 }
220 
221 static const char *SMTPStateGetStateNameById(const int id, const uint8_t direction)
222 {
223  SCEnumCharMap *map =
224  direction == STREAM_TOSERVER ? smtp_state_client_table : smtp_state_server_table;
225  return SCMapEnumValueToName(id, map);
226 }
227 
228 static inline void SMTPSetProgressTS(SMTPTransaction *tx, uint8_t progress)
229 {
230  if (tx != NULL && tx->progress_ts < progress) {
231  tx->progress_ts = progress;
232  }
233 }
234 
235 static inline void SMTPSetProgressTC(SMTPTransaction *tx, uint8_t progress)
236 {
237  if (tx != NULL && tx->progress_tc < progress) {
238  tx->progress_tc = progress;
239  tx->tx_data.updated_tc = true;
240  }
241 }
242 
243 static inline void SMTPTransactionCompleteTS(SMTPTransaction *tx)
244 {
245  DEBUG_VALIDATE_BUG_ON(tx == NULL);
246  if (tx) {
247  SMTPSetProgressTS(tx, SMTP_REQUEST_COMPLETE);
248  SCLogDebug("marked tx as ts complete");
249  }
250 }
251 
252 static inline void SMTPTransactionCompleteTC(SMTPTransaction *tx)
253 {
254  DEBUG_VALIDATE_BUG_ON(tx == NULL);
255  if (tx) {
256  SMTPSetProgressTC(tx, SMTP_RESPONSE_COMPLETE);
257  SCLogDebug("marked tx as tc complete");
258  }
259 }
260 
261 static bool SMTPTransactionRequestIsComplete(const SMTPTransaction *tx)
262 {
263  return tx && tx->progress_ts == SMTP_REQUEST_COMPLETE;
264 }
265 
266 typedef struct SMTPThreadCtx_ {
270 
271 #define SMTP_MPM mpm_default_matcher
272 
273 static MpmCtx *smtp_mpm_ctx = NULL;
274 
275 /* smtp reply codes. If an entry is made here, please make a simultaneous
276  * entry in smtp_reply_map */
277 enum SMTPCode {
286 
289 
290  SMTP_REPLY_401, // Unauthorized
291  SMTP_REPLY_402, // Command not implemented
293  SMTP_REPLY_435, // Your account has not yet been verified
297  SMTP_REPLY_454, // Temporary authentication failure
299 
305  SMTP_REPLY_511, // Bad email address
306  SMTP_REPLY_521, // Server does not accept mail
307  SMTP_REPLY_522, // Recipient has exceeded mailbox limit
308  SMTP_REPLY_525, // User Account Disabled
309  SMTP_REPLY_530, // Authentication required
310  SMTP_REPLY_534, // Authentication mechanism is too weak
311  SMTP_REPLY_535, // Authentication credentials invalid
312  SMTP_REPLY_541, // No response from host
313  SMTP_REPLY_543, // Routing server failure. No available route
320 };
321 
323  { "211", SMTP_REPLY_211 },
324  { "214", SMTP_REPLY_214 },
325  { "220", SMTP_REPLY_220 },
326  { "221", SMTP_REPLY_221 },
327  { "235", SMTP_REPLY_235 },
328  { "250", SMTP_REPLY_250 },
329  { "251", SMTP_REPLY_251 },
330  { "252", SMTP_REPLY_252 },
331 
332  { "334", SMTP_REPLY_334 },
333  { "354", SMTP_REPLY_354 },
334 
335  { "401", SMTP_REPLY_401 },
336  { "402", SMTP_REPLY_402 },
337  { "421", SMTP_REPLY_421 },
338  { "435", SMTP_REPLY_435 },
339  { "450", SMTP_REPLY_450 },
340  { "451", SMTP_REPLY_451 },
341  { "452", SMTP_REPLY_452 },
342  { "454", SMTP_REPLY_454 },
343  // { "4.7.0", SMTP_REPLY_454 }, // rfc4954
344  { "455", SMTP_REPLY_455 },
345 
346  { "500", SMTP_REPLY_500 },
347  { "501", SMTP_REPLY_501 },
348  { "502", SMTP_REPLY_502 },
349  { "503", SMTP_REPLY_503 },
350  { "504", SMTP_REPLY_504 },
351  { "511", SMTP_REPLY_511 },
352  { "521", SMTP_REPLY_521 },
353  { "522", SMTP_REPLY_522 },
354  { "525", SMTP_REPLY_525 },
355  { "530", SMTP_REPLY_530 },
356  { "534", SMTP_REPLY_534 },
357  { "535", SMTP_REPLY_535 },
358  { "541", SMTP_REPLY_541 },
359  { "543", SMTP_REPLY_543 },
360  { "550", SMTP_REPLY_550 },
361  { "551", SMTP_REPLY_551 },
362  { "552", SMTP_REPLY_552 },
363  { "553", SMTP_REPLY_553 },
364  { "554", SMTP_REPLY_554 },
365  { "555", SMTP_REPLY_555 },
366  { NULL, -1 },
367 };
368 
369 /* Create SMTP config structure */
371  .decode_mime = true,
372  .content_limit = FILEDATA_CONTENT_LIMIT,
373  .content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE,
374  .content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW,
375  .raw_extraction = SMTP_RAW_EXTRACTION_DEFAULT_VALUE,
377 };
378 
379 static SMTPString *SMTPStringAlloc(void);
380 
381 #define SCHEME_SUFFIX_LEN 3
382 
383 /**
384  * \brief Configure SMTP Mime Decoder by parsing out mime section of YAML
385  * config file
386  *
387  * \return none
388  */
389 static void SMTPConfigure(void) {
390 
391  SCEnter();
392  intmax_t imval;
393  uint32_t content_limit = 0;
394  uint32_t content_inspect_min_size = 0;
395  uint32_t content_inspect_window = 0;
396 
397  SCConfNode *config = SCConfGetNode("app-layer.protocols.smtp.mime");
398  if (config != NULL) {
399  SCConfNode *extract_urls_schemes = NULL;
400 
401  int val;
402  int ret = SCConfGetChildValueBool(config, "decode-mime", &val);
403  if (ret) {
404  smtp_config.decode_mime = val;
405  }
406 
407  ret = SCConfGetChildValueBool(config, "decode-base64", &val);
408  if (ret) {
409  SCMimeSmtpConfigDecodeBase64(val);
410  }
411 
412  ret = SCConfGetChildValueBool(config, "decode-quoted-printable", &val);
413  if (ret) {
414  SCMimeSmtpConfigDecodeQuoted(val);
415  }
416 
417  ret = SCConfGetChildValueInt(config, "header-value-depth", &imval);
418  if (ret) {
419  if (imval < 0 || imval > UINT32_MAX) {
420  FatalError("Invalid value for header-value-depth");
421  }
422  SCMimeSmtpConfigHeaderValueDepth((uint32_t)imval);
423  }
424 
425  ret = SCConfGetChildValueBool(config, "extract-urls", &val);
426  if (ret) {
427  SCMimeSmtpConfigExtractUrls(val);
428  }
429 
430  /* Parse extract-urls-schemes from mime config, add '://' suffix to found schemes,
431  * and provide a default value of 'http' for the schemes to be extracted
432  * if no schemes are found in the config */
433  extract_urls_schemes = SCConfNodeLookupChild(config, "extract-urls-schemes");
434  if (extract_urls_schemes) {
435  SCConfNode *scheme = NULL;
436 
437  TAILQ_FOREACH (scheme, &extract_urls_schemes->head, next) {
438  size_t scheme_len = strlen(scheme->val);
439  if (scheme_len > UINT8_MAX - SCHEME_SUFFIX_LEN) {
440  FatalError("extract-urls-schemes entry '%s' is too long", scheme->val);
441  }
442  if (scheme->val[scheme_len - 1] != '/') {
443  scheme_len += SCHEME_SUFFIX_LEN;
444  char tmp[256];
445  int r = snprintf(tmp, sizeof(tmp), "%s://", scheme->val);
446  if (r != (int)scheme_len) {
447  FatalError("snprintf failure for SMTP url extraction scheme.");
448  }
449  char *new_val = SCStrdup(tmp);
450  if (unlikely(new_val == NULL)) {
451  FatalError("extract-urls-schemes entry SCStrdup failure.");
452  }
453  SCFree(scheme->val);
454  scheme->val = new_val;
455  }
456  int r = SCMimeSmtpConfigExtractUrlsSchemeAdd(scheme->val);
457  if (r < 0) {
458  FatalError("Failed to add smtp extract url scheme");
459  }
460  }
461  } else {
462  /* Add default extract url scheme 'http' since
463  * extract-urls-schemes wasn't found in the config */
464  SCMimeSmtpConfigExtractUrlsSchemeAdd("http://");
465  }
466 
467  ret = SCConfGetChildValueBool(config, "log-url-scheme", &val);
468  if (ret) {
469  SCMimeSmtpConfigLogUrlScheme(val);
470  }
471 
472  // default (if value is absent) is auto : do not set anything
473  const char *strval;
474  if (SCConfGetChildValue(config, "body-md5", &strval) == 1) {
475  if (SCConfValIsFalse(strval)) {
476  SCMimeSmtpConfigBodyMd5(false);
477  } else if (SCConfValIsTrue(strval)) {
478  SCMimeSmtpConfigBodyMd5(true);
479  } else if (strcmp(strval, "auto") != 0) {
480  SCLogWarning("Unknown value for body-md5: %s", strval);
481  }
482  }
483  }
484 
485  SCConfNode *t = SCConfGetNode("app-layer.protocols.smtp.inspected-tracker");
486  SCConfNode *p = NULL;
487 
488  if (t != NULL) {
489  TAILQ_FOREACH(p, &t->head, next) {
490  if (strcasecmp("content-limit", p->name) == 0) {
491  if (ParseSizeStringU32(p->val, &content_limit) < 0) {
492  SCLogWarning("parsing content-limit %s failed", p->val);
493  content_limit = FILEDATA_CONTENT_LIMIT;
494  }
495  smtp_config.content_limit = content_limit;
496  }
497 
498  if (strcasecmp("content-inspect-min-size", p->name) == 0) {
499  if (ParseSizeStringU32(p->val, &content_inspect_min_size) < 0) {
500  SCLogWarning("parsing content-inspect-min-size %s failed", p->val);
501  content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE;
502  }
503  smtp_config.content_inspect_min_size = content_inspect_min_size;
504  }
505 
506  if (strcasecmp("content-inspect-window", p->name) == 0) {
507  if (ParseSizeStringU32(p->val, &content_inspect_window) < 0) {
508  SCLogWarning("parsing content-inspect-window %s failed", p->val);
509  content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW;
510  }
511  smtp_config.content_inspect_window = content_inspect_window;
512  }
513  }
514  }
515 
516  smtp_config.sbcfg.buf_size = content_limit ? content_limit : 256;
517 
518  if (SCConfGetBool("app-layer.protocols.smtp.raw-extraction",
519  (int *)&smtp_config.raw_extraction) != 1) {
521  }
523  SCLogError("\"decode-mime\" and \"raw-extraction\" "
524  "options can't be enabled at the same time, "
525  "disabling raw extraction");
527  }
528 
529  uint64_t value = SMTP_DEFAULT_MAX_TX;
531  const char *str = NULL;
532  if (SCConfGetNonNull("app-layer.protocols.smtp.max-tx", &str) == 1) {
533  if (ParseSizeStringU64(str, &value) < 0) {
534  SCLogWarning("max-tx value cannot be deduced: %s,"
535  " keeping default",
536  str);
537  }
538  smtp_config.max_tx = value;
539  }
540 
541  SCReturn;
542 }
543 
544 static void SMTPSetEvent(SMTPState *s, uint8_t e)
545 {
546  SCLogDebug("setting event %u", e);
547 
548  if (s->curr_tx != NULL) {
550  // s->events++;
551  return;
552  }
553  SCLogDebug("couldn't set event %u", e);
554 }
555 
556 static SMTPTransaction *SMTPTransactionCreate(SMTPState *state)
557 {
558  if (state->tx_cnt > smtp_config.max_tx) {
559  return NULL;
560  }
561  SMTPTransaction *tx = SCCalloc(1, sizeof(*tx));
562  if (tx == NULL) {
563  return NULL;
564  }
565 
566  TAILQ_INIT(&tx->rcpt_to_list);
567  tx->tx_data.file_tx = STREAM_TOSERVER; // can xfer files
568  return tx;
569 }
570 
571 static SMTPTransaction *SMTPStateGetTxById(SMTPState *state, uint64_t tx_id)
572 {
573  SMTPTransaction *tx = NULL;
574  TAILQ_FOREACH (tx, &state->tx_list, next) {
575  if (tx->tx_id == tx_id) {
576  return tx;
577  }
578  if (tx->tx_id > tx_id) {
579  break;
580  }
581  }
582  return NULL;
583 }
584 
585 static SMTPTransaction *SMTPGetReplyTx(SMTPState *state)
586 {
587  if (state->cmds_idx >= state->cmds_cnt) {
588  return state->curr_tx;
589  }
590 
591  /* a command with no owning tx, or whose tx is gone, must not resolve
592  * to another tx */
593  if (state->cmds_tx_ids[state->cmds_idx] == SMTP_NO_TX_ID) {
594  return NULL;
595  }
596  return SMTPStateGetTxById(state, state->cmds_tx_ids[state->cmds_idx]);
597 }
598 
599 static void FlagDetectStateNewFile(SMTPTransaction *tx)
600 {
601  if (tx && tx->tx_data.de_state) {
602  SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set");
604  } else if (tx == NULL) {
605  SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW NOT set, no TX");
606  } else if (tx->tx_data.de_state == NULL) {
607  SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW NOT set, no TX DESTATE");
608  }
609 }
610 
611 static void SMTPNewFile(SMTPTransaction *tx, File *file)
612 {
613  DEBUG_VALIDATE_BUG_ON(tx == NULL);
614  DEBUG_VALIDATE_BUG_ON(file == NULL);
615 #ifdef UNITTESTS
616  if (RunmodeIsUnittests()) {
617  if (tx == NULL || file == NULL) {
618  return;
619  }
620  }
621 #endif
622  FlagDetectStateNewFile(tx);
623  tx->tx_data.files_opened++;
624 
625  /* set inspect sizes used in file pruning logic.
626  * TODO consider moving this to the file.data code that
627  * would actually have use for this. */
630 }
631 
632 /**
633  * \internal
634  * \brief Get the next line from input. It doesn't do any length validation.
635  *
636  * \param state The smtp state.
637  *
638  * \retval 0 On success.
639  * \retval -1 Either when we don't have any new lines to supply anymore or
640  * on failure.
641  */
642 static AppLayerResult SMTPGetLine(Flow *f, StreamSlice *slice, SMTPState *state, SMTPInput *input,
643  SMTPLine *line, uint16_t direction)
644 {
645  SCEnter();
646 
647  /* we have run out of input */
648  if (input->len <= 0)
649  return APP_LAYER_ERROR;
650 
651  const uint8_t type = direction == 0 ? SMTP_FRAME_COMMAND_LINE : SMTP_FRAME_RESPONSE_LINE;
652  Frame *frame = AppLayerFrameGetLastOpenByType(f, direction, type);
653  if (frame == NULL) {
654  if (direction == 0 &&
655  !(state->current_command == SMTP_COMMAND_DATA &&
658  f, slice, input->buf + input->consumed, -1, 0, SMTP_FRAME_COMMAND_LINE);
659  /* can't set tx id before (possibly) creating it */
660 
661  } else if (direction == 1) {
663  f, slice, input->buf + input->consumed, -1, 1, SMTP_FRAME_RESPONSE_LINE);
664  SMTPTransaction *reply_tx = SMTPGetReplyTx(state);
665  if (frame != NULL && reply_tx != NULL) {
666  AppLayerFrameSetTxId(frame, reply_tx->tx_id);
667  }
668  }
669  }
670  SCLogDebug("frame %p", frame);
671 
672  const uint8_t *lf_idx = memchr(input->buf + input->consumed, 0x0a, input->len);
673  bool discard_till_lf = (direction == 0) ? state->discard_till_lf_ts : state->discard_till_lf_tc;
674 
675  if (lf_idx == NULL) {
676  if (!discard_till_lf && input->len >= SMTP_LINE_BUFFER_LIMIT) {
677  line->buf = input->buf;
678  line->len = SMTP_LINE_BUFFER_LIMIT;
679  line->delim_len = 0;
681  }
682  SCReturnStruct(APP_LAYER_INCOMPLETE(input->consumed, input->len + 1));
683  } else {
684  /* There could be one chunk of command data that has LF but post the line limit
685  * e.g. input_len = 5077
686  * lf_idx = 5010
687  * max_line_len = 4096 */
688  uint32_t o_consumed = input->consumed;
689  input->consumed = (uint32_t)(lf_idx - input->buf + 1);
690  line->len = input->consumed - o_consumed;
691  line->lf_found = true;
692  DEBUG_VALIDATE_BUG_ON(line->len < 0);
693  if (line->len < 0)
695  input->len -= line->len;
696  DEBUG_VALIDATE_BUG_ON((input->consumed + input->len) != input->orig_len);
697  line->buf = input->buf + o_consumed;
698 
699  if (frame != NULL) {
700  frame->len = (int64_t)line->len;
701  }
702 
703  if (line->len >= SMTP_LINE_BUFFER_LIMIT) {
704  line->len = SMTP_LINE_BUFFER_LIMIT;
705  line->delim_len = 0;
707  }
708  if (discard_till_lf) {
709  // Whatever came in with first LF should also get discarded
710  if (direction == 0) {
711  state->discard_till_lf_ts = false;
712  } else {
713  state->discard_till_lf_tc = false;
714  }
715  line->len = 0;
716  line->delim_len = 0;
718  }
719  if (input->consumed >= 2 && input->buf[input->consumed - 2] == 0x0D) {
720  line->delim_len = 2;
721  line->len -= 2;
722  } else {
723  line->delim_len = 1;
724  line->len -= 1;
725  }
727  }
728 }
729 
730 static int SMTPInsertCommandIntoCommandBuffer(
731  SMTPState *state, uint8_t command, const SMTPTransaction *tx)
732 {
733  SCEnter();
734  void *ptmp;
735 
736  if (state->cmds_cnt >= state->cmds_buffer_len) {
737  int increment = SMTP_COMMAND_BUFFER_STEPS;
738  if ((int)(state->cmds_buffer_len + SMTP_COMMAND_BUFFER_STEPS) > (int)USHRT_MAX) {
739  increment = USHRT_MAX - state->cmds_buffer_len;
740  }
741 
742  ptmp = SCRealloc(state->cmds,
743  sizeof(uint8_t) * (state->cmds_buffer_len + increment));
744  if (ptmp == NULL) {
745  SCFree(state->cmds);
746  SCFree(state->cmds_tx_ids);
747  state->cmds = NULL;
748  state->cmds_tx_ids = NULL;
749  SCLogDebug("SCRealloc failure");
750  return -1;
751  }
752  state->cmds = ptmp;
753 
754  ptmp = SCRealloc(
755  state->cmds_tx_ids, sizeof(uint64_t) * (state->cmds_buffer_len + increment));
756  if (ptmp == NULL) {
757  SCFree(state->cmds);
758  SCFree(state->cmds_tx_ids);
759  state->cmds = NULL;
760  state->cmds_tx_ids = NULL;
761  SCLogDebug("SCRealloc failure");
762  return -1;
763  }
764  state->cmds_tx_ids = ptmp;
765 
766  state->cmds_buffer_len += increment;
767  }
768  if (state->cmds_cnt >= 1 &&
769  ((state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_STARTTLS) ||
770  (state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_DATA))) {
771  /* decoder event */
773  /* we have to have EHLO, DATA, VRFY, EXPN, TURN, QUIT, NOOP,
774  * STARTTLS as the last command in pipelined mode */
775  }
776 
777  /** \todo decoder event */
778  if ((int)(state->cmds_cnt + 1) > (int)USHRT_MAX) {
779  SCLogDebug("command buffer overflow");
780  return -1;
781  }
782 
783  state->cmds[state->cmds_cnt] = command;
784  state->cmds_tx_ids[state->cmds_cnt] = tx != NULL ? tx->tx_id : SMTP_NO_TX_ID;
785  state->cmds_cnt++;
786 
787  return 0;
788 }
789 
790 static int SMTPProcessCommandBDAT(SMTPState *state, SMTPTransaction *tx, const SMTPLine *line)
791 {
792  SCEnter();
793 
794  state->bdat_chunk_idx += (line->len + line->delim_len);
795  if (state->bdat_chunk_idx > state->bdat_chunk_len) {
797  /* decoder event */
798  SMTPSetEvent(state, SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED);
799  SCReturnInt(-1);
800  } else if (state->bdat_chunk_idx == state->bdat_chunk_len) {
802  if (state->current_command == SMTP_COMMAND_BDAT_LAST) {
803  SMTPTransactionCompleteTS(tx);
804  }
805  }
806 
807  SCReturnInt(0);
808 }
809 
810 static void SetMimeEvents(SMTPState *state, uint32_t events)
811 {
812  if (events == 0) {
813  return;
814  }
815 
816  if (events & MIME_ANOM_INVALID_BASE64) {
817  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_BASE64);
818  }
819  if (events & MIME_ANOM_INVALID_QP) {
820  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_QP);
821  }
822  if (events & MIME_ANOM_LONG_LINE) {
823  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_LINE);
824  }
825  if (events & MIME_ANOM_LONG_ENC_LINE) {
826  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE);
827  }
828  if (events & MIME_ANOM_LONG_HEADER_NAME) {
829  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME);
830  }
831  if (events & MIME_ANOM_LONG_HEADER_VALUE) {
832  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE);
833  }
834  if (events & MIME_ANOM_LONG_BOUNDARY) {
835  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG);
836  }
837  if (events & MIME_ANOM_LONG_FILENAME) {
838  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_FILENAME);
839  }
840 }
841 
842 static inline void SMTPTransactionComplete(SMTPTransaction *tx)
843 {
844  DEBUG_VALIDATE_BUG_ON(tx == NULL);
845  if (tx) {
846  SMTPSetProgressTS(tx, SMTP_REQUEST_COMPLETE);
847  SMTPSetProgressTC(tx, SMTP_RESPONSE_COMPLETE);
848  }
849 }
850 
851 /**
852  * \retval 0 ok
853  * \retval -1 error
854  */
855 static int SMTPProcessCommandDATA(
856  SMTPState *state, SMTPTransaction *tx, Flow *f, const SMTPLine *line)
857 {
858  SCEnter();
859  DEBUG_VALIDATE_BUG_ON(tx == NULL);
860 
861  SCTxDataUpdateFileFlags(&tx->tx_data, state->state_data.file_flags);
863  /* looks like are still waiting for a confirmation from the server */
864  return 0;
865  }
866 
867  if (line->len == 1 && line->buf[0] == '.') {
869  /* kinda like a hack. The mail sent in DATA mode, would be
870  * acknowledged with a reply. We insert a dummy command to
871  * the command buffer to be used by the reply handler to match
872  * the reply received */
873  SMTPInsertCommandIntoCommandBuffer(state, SMTP_COMMAND_DATA_MODE, tx);
875  /* we use this as the signal that message data is complete. */
876  FileCloseFile(&tx->files_ts, &smtp_config.sbcfg, NULL, 0, 0);
877  } else if (smtp_config.decode_mime && tx->mime_state != NULL) {
878  /* Complete parsing task */
879  SCSmtpMimeComplete(tx->mime_state);
880  if (tx->files_ts.tail && tx->files_ts.tail->state == FILE_STATE_OPENED) {
881  FileCloseFile(&tx->files_ts, &smtp_config.sbcfg, NULL, 0,
882  FileFlowToFlags(f, STREAM_TOSERVER));
883  }
884  }
885  SMTPTransactionCompleteTS(tx);
886  } else if (smtp_config.raw_extraction) {
887  // message not over, store the line. This is a substitution of
888  // ProcessDataChunk
889  FileAppendData(&tx->files_ts, &smtp_config.sbcfg, line->buf, line->len + line->delim_len);
890  }
891 
892  /* If DATA, then parse out a MIME message */
893  if (state->current_command == SMTP_COMMAND_DATA &&
895 
896  if (smtp_config.decode_mime && tx->mime_state != NULL) {
897  uint32_t events;
898  uint16_t flags = FileFlowToFlags(f, STREAM_TOSERVER);
899  const uint8_t *filename = NULL;
900  uint16_t filename_len = 0;
901  uint32_t depth;
902 
903  /* we depend on detection engine for file pruning */
905  MimeSmtpParserResult ret = SCSmtpMimeParseLine(
906  line->buf, line->len, line->delim_len, &events, tx->mime_state);
907  SetMimeEvents(state, events);
908  switch (ret) {
909  case MimeSmtpFileOpen:
910  // get filename owned by mime state
911  SCMimeSmtpGetFilename(state->curr_tx->mime_state, &filename, &filename_len);
912 
913  if (filename_len == 0) {
914  // not an attachment
915  break;
916  }
917  depth = (uint32_t)(smtp_config.content_inspect_min_size +
918  (state->toserver_data_count -
919  state->toserver_last_data_stamp));
920  SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %" PRIu32,
921  depth);
922  StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER, depth);
923 
924  if (filename_len > SC_FILENAME_MAX) {
925  filename_len = SC_FILENAME_MAX;
926  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_FILENAME);
927  }
929  state->file_track_id++, filename, filename_len, NULL, 0,
930  flags) != 0) {
931  SCLogDebug("FileOpenFile() failed");
932  } else {
933  SMTPNewFile(state->curr_tx, tx->files_ts.tail);
934  }
935  break;
936  case MimeSmtpFileChunk:
937  // rust already run FileAppendData
938  if (tx->files_ts.tail && tx->files_ts.tail->content_inspected == 0 &&
940  depth = (uint32_t)(smtp_config.content_inspect_min_size +
941  (state->toserver_data_count -
942  state->toserver_last_data_stamp));
943  SCAppLayerParserTriggerRawStreamInspection(f, STREAM_TOSERVER);
944  SCLogDebug(
945  "StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u", depth);
946  StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER, depth);
947  /* after the start of the body inspection, disable the depth logic */
948  } else if (tx->files_ts.tail && tx->files_ts.tail->content_inspected > 0) {
949  StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER, 0);
950  /* expand the limit as long as we get file data, as the file data is bigger
951  * on the wire due to base64 */
952  } else {
953  depth = (uint32_t)(smtp_config.content_inspect_min_size +
954  (state->toserver_data_count -
955  state->toserver_last_data_stamp));
956  SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %" PRIu32,
957  depth);
958  StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER, depth);
959  }
960  break;
961  case MimeSmtpFileClose:
962  if (tx->files_ts.tail && tx->files_ts.tail->state == FILE_STATE_OPENED) {
963  if (FileCloseFile(&tx->files_ts, &smtp_config.sbcfg, NULL, 0, flags) != 0) {
964  SCLogDebug("FileCloseFile() failed: %d", ret);
965  }
966  } else {
967  SCLogDebug("File already closed");
968  }
969  depth = (uint32_t)(state->toserver_data_count -
970  state->toserver_last_data_stamp);
971  SCAppLayerParserTriggerRawStreamInspection(f, STREAM_TOSERVER);
972  SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u", depth);
973  StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER, depth);
974  }
975  }
976  }
977 
978  return 0;
979 }
980 
981 static inline bool IsReplyToCommand(const SMTPState *state, const uint8_t cmd)
982 {
983  return (state->cmds_idx < state->cmds_cnt && state->cmds[state->cmds_idx] == cmd);
984 }
985 
986 static int SMTPProcessReply(
987  SMTPState *state, Flow *f, SMTPThreadCtx *td, SMTPInput *input, const SMTPLine *line)
988 {
989  SCEnter();
990 
991  /* Line with just LF */
992  if (line->len == 0 && input->consumed == 1 && line->delim_len == 1) {
993  return 0; // to continue processing further
994  }
995 
996  SMTPTransaction *reply_tx = SMTPGetReplyTx(state);
997  if (reply_tx != NULL) {
998  reply_tx->tx_data.updated_tc = true;
999  }
1000  /* the reply code has to contain at least 3 bytes, to hold the 3 digit
1001  * reply code */
1002  if (line->len < 3) {
1003  /* decoder event */
1004  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
1005  return -1;
1006  }
1007 
1008  if (line->len >= 4) {
1010  if (line->buf[3] != '-') {
1012  }
1013  } else {
1014  if (line->buf[3] == '-') {
1016  }
1017  }
1018  } else {
1021  }
1022  }
1023 
1024  /* I don't like this pmq reset here. We'll devise a method later, that
1025  * should make the use of the mpm very efficient */
1026  PmqReset(td->pmq);
1027  int mpm_cnt = mpm_table[SMTP_MPM].Search(
1028  smtp_mpm_ctx, td->smtp_mpm_thread_ctx, td->pmq, line->buf, 3);
1029  if (mpm_cnt == 0) {
1030  /* set decoder event - reply code invalid */
1031  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
1032  SCLogDebug("invalid reply code %02x %02x %02x", line->buf[0], line->buf[1], line->buf[2]);
1033  SCReturnInt(-1);
1034  }
1035  enum SMTPCode reply_code = smtp_reply_map[td->pmq->rule_id_array[0]].enum_value;
1036  SCLogDebug("REPLY: reply_code %u / %s", reply_code,
1037  smtp_reply_map[reply_code].enum_name);
1038 
1039  if (state->cmds_idx == state->cmds_cnt) {
1041  /* the first server reply can be a multiline message. Let's
1042  * flag the fact that we have seen the first reply only at the end
1043  * of a multiline reply
1044  */
1047  if (reply_code == SMTP_REPLY_220)
1048  SCReturnInt(0);
1049  else {
1050  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
1051  SCReturnInt(0);
1052  }
1053  } else {
1054  /* decoder event - unable to match reply with request */
1055  SCLogDebug("unable to match reply with request");
1056  SCReturnInt(0);
1057  }
1058  }
1059 
1060  if (state->cmds_cnt == 0) {
1061  /* reply but not a command we have stored, fall through */
1062  } else if (IsReplyToCommand(state, SMTP_COMMAND_STARTTLS)) {
1063  if (reply_code == SMTP_REPLY_220) {
1064  /* we are entering STARTTLS data mode */
1067  SMTPSetEvent(state, SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE);
1068  }
1069  if (reply_tx) {
1070  SMTPTransactionComplete(reply_tx);
1071  }
1072  } else {
1073  /* decoder event */
1074  SMTPSetEvent(state, SMTP_DECODER_EVENT_TLS_REJECTED);
1075  }
1076  } else if (IsReplyToCommand(state, SMTP_COMMAND_DATA)) {
1077  if (reply_code == SMTP_REPLY_354) {
1078  SMTPSetProgressTC(reply_tx, SMTP_RESPONSE_DATA);
1079  /* Next comes the mail for the DATA command in toserver direction */
1081  } else {
1082  /* decoder event */
1084  // reset data mode if we had entered it prematurely
1086  }
1087  SMTPSetEvent(state, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED);
1088  }
1089  } else if (IsReplyToCommand(state, SMTP_COMMAND_BDAT)) {
1091  state->current_command == SMTP_COMMAND_BDAT &&
1092  state->cmds_idx + 1 == state->cmds_cnt) {
1093  // The server replied before receiving the entire chunk.
1095  }
1096  SMTPSetProgressTC(reply_tx, SMTP_RESPONSE_DATA);
1097  } else if (IsReplyToCommand(state, SMTP_COMMAND_BDAT_LAST)) {
1100  state->cmds_idx + 1 == state->cmds_cnt) {
1101  // The server replied before receiving the entire chunk.
1103  }
1104  if (reply_tx && !(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) {
1105  SMTPTransactionCompleteTC(reply_tx);
1106  }
1107  } else if (IsReplyToCommand(state, SMTP_COMMAND_DATA_MODE)) {
1108  if (reply_tx && !(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) {
1109  SMTPTransactionCompleteTC(reply_tx);
1110  }
1111  } else if (IsReplyToCommand(state, SMTP_COMMAND_RSET)) {
1112  if (reply_code == SMTP_REPLY_250 && reply_tx &&
1114  SMTPTransactionComplete(reply_tx);
1115  }
1116  } else if (IsReplyToCommand(state, SMTP_COMMAND_QUIT)) {
1117  if (reply_code == SMTP_REPLY_221 && reply_tx &&
1119  SMTPTransactionComplete(reply_tx);
1120  }
1121  } else {
1122  /* we don't care for any other command for now */
1123  }
1124 
1125  /* if it is a multi-line reply, we need to move the index only once for all
1126  * the line of the reply. We unset the multiline flag on the last
1127  * line of the multiline reply, following which we increment the index */
1129  state->cmds_idx++;
1130  } else if (state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1131  /* we check if the server is indicating pipelining support */
1132  if (reply_code == SMTP_REPLY_250 && line->len == 14 &&
1133  SCMemcmpLowercase("pipelining", line->buf + 4, 10) == 0) {
1135  }
1136  }
1137 
1138  /* if we have matched all the buffered commands, reset the cnt and index */
1139  if (state->cmds_idx == state->cmds_cnt) {
1140  state->cmds_cnt = 0;
1141  state->cmds_idx = 0;
1142  }
1143  SCAppLayerParserTriggerRawStreamInspection(f, STREAM_TOCLIENT);
1144 
1145  return 0;
1146 }
1147 
1148 static int SMTPParseCommandBDAT(SMTPState *state, const SMTPLine *line, bool *last)
1149 {
1150  SCEnter();
1151 
1152  *last = false;
1153 
1154  int i = 4;
1155  while (i < line->len) {
1156  if (line->buf[i] != ' ') {
1157  break;
1158  }
1159  i++;
1160  }
1161  if (i == 4) {
1162  /* decoder event */
1163  return -1;
1164  }
1165  if (i == line->len) {
1166  /* decoder event */
1167  return -1;
1168  }
1169  // copy in temporary null-terminated buffer for conversion
1170  char strbuf[24];
1171  int len = 23;
1172  if (line->len - i < len) {
1173  len = line->len - i;
1174  }
1175  memcpy(strbuf, line->buf + i, len);
1176  strbuf[len] = '\0';
1177  int parsed = ByteExtractStringUint32(&state->bdat_chunk_len, 10, 0, strbuf);
1178  if (parsed < 0) {
1179  /* decoder event */
1180  return -1;
1181  }
1182  state->bdat_chunk_idx = 0;
1183 
1184  i += parsed;
1185  if (i < line->len && line->buf[i] != ' ') {
1186  return -1;
1187  }
1188  while (i < line->len && line->buf[i] == ' ') {
1189  i++;
1190  }
1191  if (line->len - i == 4 && SCMemcmpLowercase("last", line->buf + i, 4) == 0) {
1192  *last = true;
1193  } else if (i != line->len) {
1194  return -1;
1195  }
1196 
1197  return 0;
1198 }
1199 
1200 static int SMTPParseCommandWithParam(SMTPState *state, const SMTPLine *line, uint8_t prefix_len,
1201  uint8_t **target, uint16_t *target_len)
1202 {
1203  int i = prefix_len + 1;
1204 
1205  while (i < line->len) {
1206  if (line->buf[i] != ' ') {
1207  break;
1208  }
1209  i++;
1210  }
1211 
1212  /* rfc1870: with the size extension the mail from can be followed by an option.
1213  We use the space separator to detect it. */
1214  int spc_i = i;
1215  while (spc_i < line->len) {
1216  if (line->buf[spc_i] == ' ') {
1217  break;
1218  }
1219  spc_i++;
1220  }
1221 
1222  *target = SCMalloc(spc_i - i + 1);
1223  if (*target == NULL)
1224  return -1;
1225  memcpy(*target, line->buf + i, spc_i - i);
1226  (*target)[spc_i - i] = '\0';
1227  if (spc_i - i > UINT16_MAX) {
1228  *target_len = UINT16_MAX;
1230  } else {
1231  *target_len = (uint16_t)(spc_i - i);
1232  }
1233 
1234  return 0;
1235 }
1236 
1237 static int SMTPParseCommandHELO(SMTPState *state, const SMTPLine *line)
1238 {
1239  if (state->helo) {
1240  SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1241  return 0;
1242  }
1243  return SMTPParseCommandWithParam(state, line, 4, &state->helo, &state->helo_len);
1244 }
1245 
1246 static int SMTPParseCommandMAILFROM(SMTPState *state, const SMTPLine *line)
1247 {
1248  if (state->curr_tx->mail_from) {
1249  SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1250  return 0;
1251  }
1252  return SMTPParseCommandWithParam(
1253  state, line, 9, &state->curr_tx->mail_from, &state->curr_tx->mail_from_len);
1254 }
1255 
1256 static int SMTPParseCommandRCPTTO(SMTPState *state, const SMTPLine *line)
1257 {
1258  uint8_t *rcptto;
1259  uint16_t rcptto_len;
1260 
1261  if (SMTPParseCommandWithParam(state, line, 7, &rcptto, &rcptto_len) == 0) {
1262  SMTPString *rcptto_str = SMTPStringAlloc();
1263  if (rcptto_str) {
1264  rcptto_str->str = rcptto;
1265  rcptto_str->len = rcptto_len;
1266  TAILQ_INSERT_TAIL(&state->curr_tx->rcpt_to_list, rcptto_str, next);
1267  } else {
1268  SCFree(rcptto);
1269  return -1;
1270  }
1271  } else {
1272  return -1;
1273  }
1274  return 0;
1275 }
1276 
1277 /* consider 'rset' and 'quit' to be part of the existing state */
1278 static int NoNewTx(SMTPState *state, const SMTPLine *line)
1279 {
1281  if (line->len >= 4 && SCMemcmpLowercase("rset", line->buf, 4) == 0) {
1282  return 1;
1283  } else if (line->len >= 4 && SCMemcmpLowercase("quit", line->buf, 4) == 0) {
1284  return 1;
1285  }
1286  }
1287  return 0;
1288 }
1289 
1290 /* XXX have a better name */
1291 #define rawmsgname "rawmsg"
1293 /*
1294  * @brief Process an SMTP Request
1295  *
1296  * Parse and decide the current command and set appropriate variables on the state
1297  * accordingly. Create transactions if needed or update the current transaction
1298  * with the appropriate data/params. Pass the control to the respective command
1299  * parser in the end.
1300  *
1301  * @param state Pointer to current SMTPState
1302  * @param f Pointer to the current Flow
1303  * @param pstate Pointer to the current AppLayerParserState
1304  * @param input Pointer to the current input data to SMTP parser
1305  * @param line Pointer to the current line being parsed by the SMTP parser
1306  * @return 0 for success
1307  * -1 for errors and inconsistent states
1308  * -2 if MIME state could not be allocated
1309  * */
1310 static int SMTPProcessRequest(
1311  SMTPState *state, Flow *f, SMTPInput *input, const SMTPLine *line, const StreamSlice *slice)
1312 {
1313  SCEnter();
1314  SMTPTransaction *tx = state->curr_tx;
1315 
1317  if (frame) {
1318  frame->len = (int64_t)line->len;
1319  } else {
1320  if (!(state->current_command == SMTP_COMMAND_DATA &&
1322  frame = AppLayerFrameNewByPointer(
1323  f, slice, line->buf, line->len, 0, SMTP_FRAME_COMMAND_LINE);
1324  }
1325  }
1326 
1327  /* If current input is to be discarded because it completes a long line,
1328  * line's length and delimiter len are reset to 0. Skip processing this line.
1329  * This line is only to get us out of the state where we should discard any
1330  * data till LF. */
1331  if (line->len == 0 && line->delim_len == 0) {
1332  return 0;
1333  }
1334  const bool no_new_tx = NoNewTx(state, line);
1335  if ((state->curr_tx == NULL && (state->tx_cnt == 0 || !no_new_tx)) ||
1336  (SMTPTransactionRequestIsComplete(state->curr_tx) && !no_new_tx)) {
1337  tx = SMTPTransactionCreate(state);
1338  if (tx == NULL)
1339  return -1;
1340  state->curr_tx = tx;
1341  TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
1342  tx->tx_id = state->tx_cnt++;
1343 
1344  /* keep track of the start of the tx */
1346  StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER,
1348  }
1349  if (frame != NULL && state->curr_tx) {
1350  AppLayerFrameSetTxId(frame, state->curr_tx->tx_id);
1351  }
1352  if (tx != NULL) {
1353  tx->tx_data.updated_ts = true;
1354  }
1355 
1356  state->toserver_data_count += (line->len + line->delim_len);
1357 
1359  SMTPSetEvent(state, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE);
1360  }
1361 
1362  /* there are 2 commands that can push it into this COMMAND_DATA mode -
1363  * STARTTLS and DATA */
1365  int r = 0;
1366  SCAppLayerParserTriggerRawStreamInspection(f, STREAM_TOSERVER);
1367 
1368  if (tx == NULL) {
1369  DEBUG_VALIDATE_BUG_ON(!no_new_tx);
1370  const bool is_rset = SCMemcmpLowercase("rset", line->buf, 4) == 0;
1371  if (is_rset)
1372  state->bdat_chunk_idx = 0;
1374  } else if (line->len >= 8 && SCMemcmpLowercase("starttls", line->buf, 8) == 0) {
1376  } else if (line->len >= 4 && SCMemcmpLowercase("data", line->buf, 4) == 0) {
1378  SMTPSetProgressTS(tx, SMTP_REQUEST_DATA);
1379  if (state->curr_tx->is_data) {
1380  // We did not receive a confirmation from server
1381  // And now client sends a next DATA
1382  SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT);
1383  SCReturnInt(0);
1384  } else if (smtp_config.raw_extraction) {
1386  (uint8_t *)rawmsgname, strlen(rawmsgname), NULL, 0,
1387  FILE_NOMD5 | FILE_NOMAGIC) == 0) {
1388  SMTPNewFile(tx, tx->files_ts.tail);
1389  }
1390  } else if (smtp_config.decode_mime) {
1392  tx->mime_state = SCMimeSmtpStateInit(&tx->files_ts, &smtp_config.sbcfg);
1393  if (tx->mime_state == NULL) {
1394  SCLogDebug("MimeDecInitParser() failed to "
1395  "allocate data");
1396  return -1;
1397  }
1398  }
1399  state->curr_tx->is_data = true;
1400 
1401  Frame *data_frame = AppLayerFrameNewByPointer(
1402  f, slice, input->buf + input->consumed, -1, 0, SMTP_FRAME_DATA);
1403  if (data_frame == NULL) {
1404  SCLogDebug("data_frame %p - no data frame set up", data_frame);
1405  } else {
1406  AppLayerFrameSetTxId(data_frame, state->curr_tx->tx_id);
1407  }
1408 
1409  /* Enter immediately data mode without waiting for server reply */
1412  }
1413  } else if (line->len >= 4 && SCMemcmpLowercase("bdat", line->buf, 4) == 0) {
1414  bool last = false;
1415  r = SMTPParseCommandBDAT(state, line, &last);
1416  if (r == -1) {
1417  /* Invalid BDAT syntax is recoverable: the server rejects the
1418  * command and the session continues. */
1419  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_BDAT);
1421  r = 0;
1422  } else {
1424  SMTPSetProgressTS(tx, SMTP_REQUEST_DATA);
1425  if (state->bdat_chunk_len > 0) {
1427  } else if (last) {
1428  SMTPTransactionCompleteTS(tx);
1429  }
1430  }
1431  } else if (line->len >= 4 && ((SCMemcmpLowercase("helo", line->buf, 4) == 0) ||
1432  SCMemcmpLowercase("ehlo", line->buf, 4) == 0)) {
1433  r = SMTPParseCommandHELO(state, line);
1434  if (r == -1) {
1435  SCReturnInt(-1);
1436  }
1437  if (state->curr_tx->mail_from != NULL || !TAILQ_EMPTY(&state->curr_tx->rcpt_to_list) ||
1439  /* Mid-session HELO/EHLO resets the state as if a RSET
1440  * had been issued (RFC 5321 4.1.4). The progress check
1441  * catches a transaction with no envelope but an attempted
1442  * DATA or BDAT, such as a rejected envelope-less DATA. */
1443  state->bdat_chunk_idx = 0;
1445  } else {
1447  }
1448  } else if (line->len >= 9 && SCMemcmpLowercase("mail from", line->buf, 9) == 0) {
1449  r = SMTPParseCommandMAILFROM(state, line);
1450  if (r == -1) {
1451  SCReturnInt(-1);
1452  }
1454  } else if (line->len >= 7 && SCMemcmpLowercase("rcpt to", line->buf, 7) == 0) {
1455  r = SMTPParseCommandRCPTTO(state, line);
1456  if (r == -1) {
1457  SCReturnInt(-1);
1458  }
1460  } else if (line->len >= 4 && SCMemcmpLowercase("rset", line->buf, 4) == 0) {
1461  // Resets chunk index in case of connection reuse
1462  state->bdat_chunk_idx = 0;
1464  } else if (line->len >= 4 && SCMemcmpLowercase("quit", line->buf, 4) == 0) {
1466  } else {
1468  }
1469 
1470  /* Every command is inserted into a command buffer, to be matched
1471  * against reply(ies) sent by the server */
1472  if (SMTPInsertCommandIntoCommandBuffer(state, state->current_command, tx) == -1) {
1473  SCReturnInt(-1);
1474  }
1475 
1476  SCReturnInt(r);
1477  }
1478 
1479  switch (state->current_command) {
1480  case SMTP_COMMAND_DATA:
1481  return SMTPProcessCommandDATA(state, tx, f, line);
1482 
1483  case SMTP_COMMAND_BDAT:
1485  return SMTPProcessCommandBDAT(state, tx, line);
1486 
1487  default:
1488  /* we have nothing to do with any other command at this instant.
1489  * Just let it go through */
1490  SCReturnInt(0);
1491  }
1492 }
1493 
1494 static inline void ResetLine(SMTPLine *line)
1495 {
1496  if (line != NULL) {
1497  line->len = 0;
1498  line->delim_len = 0;
1499  line->buf = NULL;
1500  }
1501 }
1502 
1503 static int SMTPPreProcessCommandBDAT(
1504  SMTPState *state, Flow *f, StreamSlice *slice, SMTPInput *input, SMTPLine *line)
1505 {
1506  if (state->bdat_chunk_idx >= state->bdat_chunk_len) {
1507  /* The BDAT chunk is already complete; data mode was set by another
1508  * command, such as a pipelined DATA reply. Leave data mode and let
1509  * the line parser handle the input as a new command. */
1511  return 1;
1512  }
1513  uint32_t remaining = state->bdat_chunk_len - state->bdat_chunk_idx;
1514  uint32_t consumed = MIN((uint32_t)input->len, remaining);
1515  line->buf = input->buf + input->consumed;
1516  line->len = consumed;
1517  input->consumed += consumed;
1518  input->len -= consumed;
1519  int ret = SMTPProcessRequest(state, f, input, line, slice);
1520  ResetLine(line);
1521  return ret;
1522 }
1523 
1524 /*
1525  * @brief Pre-process command data.
1526  *
1527  * If the command being processed is DATA, its data must be handled by this
1528  * function so the line limit used by GetLine is not applied. GetLine caps lines
1529  * at SMTP_LINE_BUFFER_LIMIT, which could truncate file data or parts of an
1530  * e-mail if a line were too long.
1531  *
1532  * BDAT data is octet-counted and must be consumed only up to the declared chunk
1533  * boundary.
1534  *
1535  * @param state Pointer to the current SMTPState
1536  * @param f Pointer to the current Flow
1537  * @param pstate Pointer to the current AppLayerParserState
1538  * @param input Pointer to the current input data to SMTP parser
1539  * @param line Pointer to the current line being parsed by the SMTP parser
1540  * @return 0 for success
1541  * 1 for handing control over to GetLine
1542  * -1 for errors and inconsistent states
1543  * */
1544 static int SMTPPreProcessCommands(
1545  SMTPState *state, Flow *f, StreamSlice *slice, SMTPInput *input, SMTPLine *line)
1546 {
1548  DEBUG_VALIDATE_BUG_ON(line->len != 0);
1549  DEBUG_VALIDATE_BUG_ON(line->delim_len != 0);
1550 
1551  if (state->current_command == SMTP_COMMAND_BDAT ||
1553  return SMTPPreProcessCommandBDAT(state, f, slice, input, line);
1554  }
1555 
1556  /* fall back to strict line parsing for mime header parsing */
1557  if (state->curr_tx && state->curr_tx->mime_state &&
1558  SCMimeSmtpGetState(state->curr_tx->mime_state) < MimeSmtpBody)
1559  return 1;
1560 
1561  bool line_complete = false;
1562  const int32_t input_len = input->len;
1563  const int32_t offset = input->consumed;
1564  for (int32_t i = 0; i < input_len; i++) {
1565  if (input->buf[offset + i] == 0x0d) {
1566  if (i < input_len - 1 && input->buf[offset + i + 1] == 0x0a) {
1567  i++;
1568  line->delim_len++;
1569  }
1570  /* Line is just ending in CR */
1571  line->delim_len++;
1572  line_complete = true;
1573  } else if (input->buf[offset + i] == 0x0a) {
1574  /* Line is just ending in LF */
1575  line->delim_len++;
1576  line_complete = true;
1577  }
1578  /* Either line is complete or fragmented */
1579  if (line_complete || (i == input_len - 1)) {
1580  DEBUG_VALIDATE_BUG_ON(input->consumed + input->len != input->orig_len);
1581  DEBUG_VALIDATE_BUG_ON(input->len == 0 && input_len != 0);
1582  /* state->input_len reflects data from start of the line in progress. */
1583  if ((input->len == 1 && input->buf[input->consumed] == '-') ||
1584  (input->len > 1 && input->buf[input->consumed] == '-' &&
1585  input->buf[input->consumed + 1] == '-')) {
1586  SCLogDebug("Possible boundary, yield to GetLine");
1587  return 1;
1588  }
1589  /* total_consumed should be input consumed so far + i + 1 */
1590  int32_t total_consumed = offset + i + 1;
1591  int32_t current_line_consumed = total_consumed - input->consumed;
1592  DEBUG_VALIDATE_BUG_ON(current_line_consumed < line->delim_len);
1593  line->buf = input->buf + input->consumed;
1594  line->len = current_line_consumed - line->delim_len;
1595  DEBUG_VALIDATE_BUG_ON(line->len < 0);
1596  if (line->len < 0) {
1597  return -1;
1598  }
1599 
1600  input->consumed = total_consumed;
1601  input->len -= current_line_consumed;
1602  DEBUG_VALIDATE_BUG_ON(input->consumed + input->len != input->orig_len);
1603  if (SMTPProcessRequest(state, f, input, line, slice) == -1) {
1604  return -1;
1605  }
1606  line_complete = false;
1607  line->buf = NULL;
1608  line->len = 0;
1609  line->delim_len = 0;
1610 
1611  /* bail if `SMTPProcessRequest` ended the data mode */
1612  if ((state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE) == 0) {
1614  if (data_frame) {
1615  data_frame->len = (slice->offset + input->consumed) - data_frame->offset;
1616  }
1617  break;
1618  }
1619  }
1620  }
1621  return 0;
1622 }
1623 
1624 static AppLayerResult SMTPParse(uint8_t direction, Flow *f, SMTPState *state,
1625  AppLayerParserState *pstate, StreamSlice stream_slice, SMTPThreadCtx *thread_data)
1626 {
1627  SCEnter();
1628 
1629  const uint8_t *input_buf = StreamSliceGetData(&stream_slice);
1630  uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
1631 
1632  if (input_buf == NULL &&
1633  ((direction == 0 && SCAppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) ||
1634  (direction == 1 &&
1635  SCAppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC)))) {
1637  } else if (input_buf == NULL || input_len == 0) {
1639  }
1640 
1641  SMTPInput input = { .buf = input_buf, .len = input_len, .orig_len = input_len, .consumed = 0 };
1642  SMTPLine line = { NULL, 0, 0, false };
1643 
1644  /* toserver */
1645  if (direction == 0) {
1646  if (((state->current_command == SMTP_COMMAND_DATA) ||
1647  (state->current_command == SMTP_COMMAND_BDAT) ||
1648  (state->current_command == SMTP_COMMAND_BDAT_LAST)) &&
1650  int ret = SMTPPreProcessCommands(state, f, &stream_slice, &input, &line);
1651  DEBUG_VALIDATE_BUG_ON(ret != 0 && ret != -1 && ret != 1);
1652  if (ret == 0 && input.consumed == input.orig_len) {
1654  } else if (ret < 0) {
1656  }
1657  }
1658  AppLayerResult res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1659  while (res.status == 0) {
1660  int retval = SMTPProcessRequest(state, f, &input, &line, &stream_slice);
1661  if (retval != 0)
1663  if (line.delim_len == 0 && line.len == SMTP_LINE_BUFFER_LIMIT) {
1664  if (!line.lf_found) {
1665  state->discard_till_lf_ts = true;
1666  }
1667  input.consumed = input.len + 1; // For the newly found LF
1668  SMTPSetEvent(state, SMTP_DECODER_EVENT_TRUNCATED_LINE);
1669  break;
1670  }
1671  /* If request was successfully parsed, reset line as it has already been used
1672  * wherever it had to be */
1673  ResetLine(&line);
1674 
1675  /* If command data mode was entered in the middle of input parsing, first pass it to
1676  * SMTPPreProcessCommands so input limits are not applied to DATA bodies and BDAT data
1677  * is not consumed past its chunk boundary. SMTPPreProcessCommands should either
1678  * consume all remaining input or stop at a MIME or BDAT chunk boundary, after which
1679  * control is passed to SMTPGetLine. */
1680  if ((input.len > 0) &&
1681  ((state->current_command == SMTP_COMMAND_DATA) ||
1682  (state->current_command == SMTP_COMMAND_BDAT) ||
1683  (state->current_command == SMTP_COMMAND_BDAT_LAST)) &&
1685  int ret = SMTPPreProcessCommands(state, f, &stream_slice, &input, &line);
1686  DEBUG_VALIDATE_BUG_ON(ret != 0 && ret != -1 && ret != 1);
1687  if (ret == 0 && input.consumed == input.orig_len) {
1689  } else if (ret < 0) {
1691  }
1692  }
1693  res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1694  }
1695  if (res.status == 1)
1696  return res;
1697  /* toclient */
1698  } else {
1699  AppLayerResult res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1700  while (res.status == 0) {
1701  if (SMTPProcessReply(state, f, thread_data, &input, &line) != 0)
1703  if (line.delim_len == 0 && line.len == SMTP_LINE_BUFFER_LIMIT) {
1704  if (!line.lf_found) {
1705  state->discard_till_lf_tc = true;
1706  }
1707  input.consumed = input.len + 1; // For the newly found LF
1708  SMTPSetEvent(state, SMTP_DECODER_EVENT_TRUNCATED_LINE);
1709  break;
1710  }
1711  res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1712  }
1713  if (res.status == 1)
1714  return res;
1715  }
1716 
1718 }
1719 
1720 static AppLayerResult SMTPParseClientRecord(Flow *f, void *alstate, AppLayerParserState *pstate,
1721  StreamSlice stream_slice, void *local_data)
1722 {
1723  SCEnter();
1724 
1725  /* first arg 0 is toserver */
1726  return SMTPParse(0, f, alstate, pstate, stream_slice, local_data);
1727 }
1728 
1729 static AppLayerResult SMTPParseServerRecord(Flow *f, void *alstate, AppLayerParserState *pstate,
1730  StreamSlice stream_slice, void *local_data)
1731 {
1732  SCEnter();
1733 
1734  /* first arg 1 is toclient */
1735  return SMTPParse(1, f, alstate, pstate, stream_slice, local_data);
1736 }
1737 
1738 /**
1739  * \internal
1740  * \brief Function to allocate SMTP state memory.
1741  */
1742 void *SMTPStateAlloc(void *orig_state, AppProto proto_orig)
1743 {
1744  SMTPState *smtp_state = SCCalloc(1, sizeof(SMTPState));
1745  if (unlikely(smtp_state == NULL))
1746  return NULL;
1747 
1748  smtp_state->cmds = SCMalloc(sizeof(uint8_t) *
1750  if (smtp_state->cmds == NULL) {
1751  SCFree(smtp_state);
1752  return NULL;
1753  }
1754  smtp_state->cmds_tx_ids = SCMalloc(sizeof(uint64_t) * SMTP_COMMAND_BUFFER_STEPS);
1755  if (smtp_state->cmds_tx_ids == NULL) {
1756  SCFree(smtp_state->cmds);
1757  SCFree(smtp_state);
1758  return NULL;
1759  }
1761 
1762  TAILQ_INIT(&smtp_state->tx_list);
1763 
1764  return smtp_state;
1765 }
1766 
1767 static SMTPString *SMTPStringAlloc(void)
1768 {
1769  SMTPString *smtp_string = SCCalloc(1, sizeof(SMTPString));
1770  if (unlikely(smtp_string == NULL))
1771  return NULL;
1772 
1773  return smtp_string;
1774 }
1775 
1776 
1777 static void SMTPStringFree(SMTPString *str)
1778 {
1779  if (str->str) {
1780  SCFree(str->str);
1781  }
1782  SCFree(str);
1783 }
1784 
1785 static void *SMTPLocalStorageAlloc(void)
1786 {
1787  /* needed by the mpm */
1788  SMTPThreadCtx *td = SCCalloc(1, sizeof(*td));
1789  if (td == NULL) {
1790  exit(EXIT_FAILURE);
1791  }
1792 
1793  td->pmq = SCCalloc(1, sizeof(*td->pmq));
1794  if (td->pmq == NULL) {
1795  exit(EXIT_FAILURE);
1796  }
1797  PmqSetup(td->pmq);
1798 
1799  td->smtp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx));
1800  if (unlikely(td->smtp_mpm_thread_ctx == NULL)) {
1801  exit(EXIT_FAILURE);
1802  }
1803  MpmInitThreadCtx(td->smtp_mpm_thread_ctx, smtp_mpm_ctx, SMTP_MPM);
1804  return td;
1805 }
1806 
1807 static void SMTPLocalStorageFree(void *ptr)
1808 {
1809  SMTPThreadCtx *td = ptr;
1810  if (td != NULL) {
1811  if (td->pmq != NULL) {
1812  PmqFree(td->pmq);
1813  SCFree(td->pmq);
1814  }
1815 
1816  if (td->smtp_mpm_thread_ctx != NULL) {
1819  }
1820 
1821  SCFree(td);
1822  }
1823 }
1824 
1825 static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state)
1826 {
1827  if (tx->mime_state != NULL) {
1828  SCMimeSmtpStateFree(tx->mime_state);
1829  }
1830 
1832 
1833  if (tx->mail_from)
1834  SCFree(tx->mail_from);
1835 
1836  SMTPString *str = NULL;
1837  while ((str = TAILQ_FIRST(&tx->rcpt_to_list))) {
1838  TAILQ_REMOVE(&tx->rcpt_to_list, str, next);
1839  SMTPStringFree(str);
1840  }
1842 
1843  SCFree(tx);
1844 }
1845 
1846 /**
1847  * \internal
1848  * \brief Function to free SMTP state memory.
1849  */
1850 static void SMTPStateFree(void *p)
1851 {
1852  SMTPState *smtp_state = (SMTPState *)p;
1853 
1854  if (smtp_state->cmds != NULL) {
1855  SCFree(smtp_state->cmds);
1856  }
1857  if (smtp_state->cmds_tx_ids != NULL) {
1858  SCFree(smtp_state->cmds_tx_ids);
1859  }
1860 
1861  if (smtp_state->helo) {
1862  SCFree(smtp_state->helo);
1863  }
1864 
1865  SMTPTransaction *tx = NULL;
1866  while ((tx = TAILQ_FIRST(&smtp_state->tx_list))) {
1867  TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1868  SMTPTransactionFree(tx, smtp_state);
1869  }
1870 
1871  SCFree(smtp_state);
1872 }
1873 
1874 static void SMTPSetMpmState(void)
1875 {
1876  smtp_mpm_ctx = SCCalloc(1, sizeof(MpmCtx));
1877  if (unlikely(smtp_mpm_ctx == NULL)) {
1878  exit(EXIT_FAILURE);
1879  }
1880  MpmInitCtx(smtp_mpm_ctx, SMTP_MPM);
1881 
1882  uint32_t i = 0;
1883  for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) {
1884  SCEnumCharMap *map = &smtp_reply_map[i];
1885  /* The third argument is 3, because reply code is always 3 bytes. */
1886  SCMpmAddPatternCI(smtp_mpm_ctx, (uint8_t *)map->enum_name, 3, 0 /* defunct */,
1887  0 /* defunct */, i /* pattern id */, i /* rule id */, 0 /* no flags */);
1888  }
1889 
1890  mpm_table[SMTP_MPM].Prepare(NULL, smtp_mpm_ctx);
1891 }
1892 
1893 static void SMTPFreeMpmState(void)
1894 {
1895  if (smtp_mpm_ctx != NULL) {
1896  mpm_table[SMTP_MPM].DestroyCtx(smtp_mpm_ctx);
1897  SCFree(smtp_mpm_ctx);
1898  smtp_mpm_ctx = NULL;
1899  }
1900 }
1901 
1902 static int SMTPStateGetEventInfo(
1903  const char *event_name, uint8_t *event_id, AppLayerEventType *event_type)
1904 {
1905  if (SCAppLayerGetEventIdByName(event_name, smtp_decoder_event_table, event_id) == 0) {
1906  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
1907  return 0;
1908  }
1909  return -1;
1910 }
1911 
1912 static int SMTPStateGetEventInfoById(
1913  uint8_t event_id, const char **event_name, AppLayerEventType *event_type)
1914 {
1915  *event_name = SCMapEnumValueToName(event_id, smtp_decoder_event_table);
1916  if (*event_name == NULL) {
1917  SCLogError("event \"%d\" not present in "
1918  "smtp's enum map table.",
1919  event_id);
1920  /* yes this is fatal */
1921  return -1;
1922  }
1923 
1924  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
1925 
1926  return 0;
1927 }
1928 
1929 // This probing parser checks the port after ambiguous patterns
1930 // that may be used by other protocols such as FTP
1931 static AppProto SMTPClientProbingParserCheckPort(
1932  const Flow *f, uint8_t direction, const uint8_t *input, uint32_t len, uint8_t *rdir)
1933 {
1934  if (AppLayerProtoDetectHasProbingParsers(IPPROTO_TCP, f->dp, ALPROTO_FTP)) {
1935  return ALPROTO_FAILED;
1936  }
1937  return ALPROTO_SMTP;
1938 }
1939 
1940 static AppProto SMTPServerProbingParser(
1941  const Flow *f, uint8_t direction, const uint8_t *input, uint32_t len, uint8_t *rdir)
1942 {
1943  // another check for minimum length
1944  if (len < 5) {
1945  return ALPROTO_UNKNOWN;
1946  }
1947  // begins by 220
1948  if (input[0] != '2' || input[1] != '2' || input[2] != '0') {
1949  return ALPROTO_FAILED;
1950  }
1951  // followed by space or hypen
1952  if (input[3] != ' ' && input[3] != '-') {
1953  return ALPROTO_FAILED;
1954  }
1955  // If client side is SMTP, do not validate domain
1956  // so that server banner can be parsed first.
1957  if (f->alproto_ts == ALPROTO_SMTP) {
1958  if (memchr(input + 4, '\n', len - 4) != NULL) {
1959  return ALPROTO_SMTP;
1960  }
1961  return ALPROTO_UNKNOWN;
1962  }
1964  if (f->todstbytecnt > 4 && (f->alproto_ts == ALPROTO_UNKNOWN || f->alproto_ts == ALPROTO_TLS)) {
1965  // Only validates SMTP if client side is unknown
1966  // despite having received bytes.
1967  r = ALPROTO_SMTP;
1968  }
1969  uint32_t offset = SCValidateDomain(input + 4, len - 4);
1970  if (offset == 0) {
1971  return ALPROTO_FAILED;
1972  }
1973  if (r != ALPROTO_UNKNOWN && memchr(input + 4, '\n', len - 4) != NULL) {
1974  return r;
1975  }
1976  // This should not go forever because of engine limiting probing parsers.
1977  return ALPROTO_UNKNOWN;
1978 }
1979 
1980 static int SMTPRegisterPatternsForProtocolDetection(void)
1981 {
1983  IPPROTO_TCP, ALPROTO_SMTP, "EHLO", 4, 0, STREAM_TOSERVER) < 0) {
1984  return -1;
1985  }
1987  IPPROTO_TCP, ALPROTO_SMTP, "HELO", 4, 0, STREAM_TOSERVER) < 0) {
1988  return -1;
1989  }
1990  if (SCAppLayerProtoDetectPMRegisterPatternCIwPP(IPPROTO_TCP, ALPROTO_SMTP, "QUIT", 4, 0,
1991  STREAM_TOSERVER, SMTPClientProbingParserCheckPort, 4, 4) < 0) {
1992  return -1;
1993  }
1994 
1996  "tcp", IPPROTO_TCP, "smtp", ALPROTO_SMTP, 0, 5, NULL, SMTPServerProbingParser)) {
1997  // STREAM_TOSERVER means here use 25 as flow destination port
1998  SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "25,465", ALPROTO_SMTP, 0, 5, STREAM_TOSERVER,
1999  NULL, SMTPServerProbingParser);
2000  }
2001 
2002  return 0;
2003 }
2004 
2005 static void SMTPStateTransactionFree (void *state, uint64_t tx_id)
2006 {
2007  SMTPState *smtp_state = state;
2008  SMTPTransaction *tx = NULL;
2009  TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
2010  if (tx_id < tx->tx_id)
2011  break;
2012  else if (tx_id > tx->tx_id)
2013  continue;
2014 
2015  if (tx == smtp_state->curr_tx)
2016  smtp_state->curr_tx = NULL;
2017  TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
2018  SMTPTransactionFree(tx, state);
2019  break;
2020  }
2021 
2022 
2023 }
2024 
2025 /** \retval cnt highest tx id */
2026 static uint64_t SMTPStateGetTxCnt(void *state)
2027 {
2028  uint64_t cnt = 0;
2029  SMTPState *smtp_state = state;
2030  if (smtp_state) {
2031  cnt = smtp_state->tx_cnt;
2032  }
2033  SCLogDebug("returning %"PRIu64, cnt);
2034  return cnt;
2035 }
2036 
2037 static void *SMTPStateGetTx(void *state, uint64_t id)
2038 {
2039  SMTPState *smtp_state = state;
2040  if (smtp_state) {
2041  SMTPTransaction *tx = NULL;
2042 
2043  if (smtp_state->curr_tx == NULL)
2044  return NULL;
2045  if (smtp_state->curr_tx->tx_id == id)
2046  return smtp_state->curr_tx;
2047 
2048  TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
2049  if (tx->tx_id == id)
2050  return tx;
2051  }
2052  }
2053  return NULL;
2054 }
2055 
2056 static int SMTPStateGetAlstateProgress(void *vtx, uint8_t direction)
2057 {
2058  SMTPTransaction *tx = vtx;
2059  if (direction & STREAM_TOSERVER) {
2060  return tx->progress_ts;
2061  }
2062  return tx->progress_tc;
2063 }
2064 
2065 static AppLayerGetFileState SMTPGetTxFiles(void *txv, uint8_t direction)
2066 {
2067  AppLayerGetFileState files = { .fc = NULL, .cfg = &smtp_config.sbcfg };
2068  SMTPTransaction *tx = (SMTPTransaction *)txv;
2069 
2070  if (direction & STREAM_TOSERVER) {
2071  files.fc = &tx->files_ts;
2072  }
2073  return files;
2074 }
2075 
2076 static AppLayerTxData *SMTPGetTxData(void *vtx)
2077 {
2078  SMTPTransaction *tx = (SMTPTransaction *)vtx;
2079  return &tx->tx_data;
2080 }
2081 
2082 static AppLayerStateData *SMTPGetStateData(void *vstate)
2083 {
2084  SMTPState *state = (SMTPState *)vstate;
2085  return &state->state_data;
2086 }
2087 
2088 /** \brief SMTP tx iterator, specialized for its linked list
2089  *
2090  * \retval txptr or NULL if no more txs in list
2091  */
2092 static AppLayerGetTxIterTuple SMTPGetTxIterator(const uint8_t ipproto, const AppProto alproto,
2093  void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state)
2094 {
2095  SMTPState *smtp_state = (SMTPState *)alstate;
2096  AppLayerGetTxIterTuple no_tuple = { NULL, 0, false };
2097  if (smtp_state) {
2098  SMTPTransaction *tx_ptr;
2099  if (state->un.ptr == NULL) {
2100  tx_ptr = TAILQ_FIRST(&smtp_state->tx_list);
2101  } else {
2102  tx_ptr = (SMTPTransaction *)state->un.ptr;
2103  }
2104  if (tx_ptr) {
2105  while (tx_ptr->tx_id < min_tx_id) {
2106  tx_ptr = TAILQ_NEXT(tx_ptr, next);
2107  if (!tx_ptr) {
2108  return no_tuple;
2109  }
2110  }
2111  if (tx_ptr->tx_id >= max_tx_id) {
2112  return no_tuple;
2113  }
2114  state->un.ptr = TAILQ_NEXT(tx_ptr, next);
2115  AppLayerGetTxIterTuple tuple = {
2116  .tx_ptr = tx_ptr,
2117  .tx_id = tx_ptr->tx_id,
2118  .has_next = (state->un.ptr != NULL),
2119  };
2120  return tuple;
2121  }
2122  }
2123  return no_tuple;
2124 }
2125 
2126 /**
2127  * \brief Register the SMTP Protocol parser.
2128  */
2130 {
2131  const char *proto_name = "smtp";
2132 
2133  if (SCAppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
2135  if (SMTPRegisterPatternsForProtocolDetection() < 0 )
2136  return;
2137  } else {
2138  SCLogInfo("Protocol detection and parser disabled for %s protocol.",
2139  proto_name);
2140  return;
2141  }
2142 
2143  if (SCAppLayerParserConfParserEnabled("tcp", proto_name)) {
2144  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree);
2145 
2146  AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOSERVER,
2147  SMTPParseClientRecord);
2148  AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOCLIENT,
2149  SMTPParseServerRecord);
2150 
2151  AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo);
2152  AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfoById);
2153 
2154  AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc,
2155  SMTPLocalStorageFree);
2156 
2157  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTransactionFree);
2158  AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxFiles);
2159  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress);
2160  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt);
2161  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx);
2162  AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxIterator);
2163  AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxData);
2164  AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetStateData);
2168  IPPROTO_TCP, ALPROTO_SMTP, SMTPGetFrameIdByName, SMTPGetFrameNameById);
2170  IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetStateIdByName, SMTPStateGetStateNameById);
2171  } else {
2172  SCLogInfo("Parser disabled for %s protocol. Protocol detection still on.", proto_name);
2173  }
2174 
2175  SMTPSetMpmState();
2176 
2177  SMTPConfigure();
2178 
2179 #ifdef UNITTESTS
2181 #endif
2182 }
2183 
2184 /**
2185  * \brief Free memory allocated for global SMTP parser state.
2186  */
2188 {
2189  SMTPFreeMpmState();
2190 }
2191 
2192 /***************************************Unittests******************************/
2193 
2194 #ifdef UNITTESTS
2195 #include "detect-engine-alert.h"
2196 
2197 static void SMTPTestInitConfig(void)
2198 {
2202 
2204 
2206 }
2207 
2208 /*
2209  * \test Test STARTTLS.
2210  */
2211 static int SMTPParserTest01(void)
2212 {
2213  int result = 0;
2214  Flow f;
2215  int r = 0;
2216 
2217  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
2218  uint8_t welcome_reply[] = {
2219  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
2220  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
2221  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
2222  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
2223  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
2224  0x0d, 0x0a
2225  };
2226  uint32_t welcome_reply_len = sizeof(welcome_reply);
2227 
2228  /* EHLO [192.168.0.158]<CR><LF> */
2229  uint8_t request1[] = {
2230  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39,
2231  0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e,
2232  0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a
2233  };
2234  uint32_t request1_len = sizeof(request1);
2235  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
2236  * 250-SIZE 35882577<CR><LF>
2237  * 250-8BITMIME<CR><LF>
2238  * 250-STARTTLS<CR><LF>
2239  * 250 ENHANCEDSTATUSCODES<CR><LF>
2240  */
2241  uint8_t reply1[] = {
2242  0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67,
2243  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
2244  0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75,
2245  0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
2246  0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e,
2247  0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e,
2248  0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30,
2249  0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35,
2250  0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a,
2251  0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54,
2252  0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35,
2253  0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54,
2254  0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20,
2255  0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44,
2256  0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f,
2257  0x44, 0x45, 0x53, 0x0d, 0x0a
2258  };
2259  uint32_t reply1_len = sizeof(reply1);
2260 
2261  /* STARTTLS<CR><LF> */
2262  uint8_t request2[] = {
2263  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
2264  0x0d, 0x0a
2265  };
2266  uint32_t request2_len = sizeof(request2);
2267  /* 220 2.0.0 Ready to start TLS<CR><LF> */
2268  uint8_t reply2[] = {
2269  0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2270  0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20,
2271  0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74,
2272  0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a
2273  };
2274  uint32_t reply2_len = sizeof(reply2);
2275 
2276  TcpSession ssn;
2278 
2279  memset(&f, 0, sizeof(f));
2280  memset(&ssn, 0, sizeof(ssn));
2281 
2282  FLOW_INITIALIZE(&f);
2283  f.protoctx = (void *)&ssn;
2284  f.proto = IPPROTO_TCP;
2285  f.alproto = ALPROTO_SMTP;
2286 
2287  StreamTcpInitConfig(true);
2288  SMTPTestInitConfig();
2289 
2290  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2291  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2292  if (r != 0) {
2293  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2294  goto end;
2295  }
2296  SMTPState *smtp_state = f.alstate;
2297  if (smtp_state == NULL) {
2298  printf("no smtp state: ");
2299  goto end;
2300  }
2301  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2303  printf("smtp parser in inconsistent state\n");
2304  goto end;
2305  }
2306 
2307  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2308  STREAM_TOSERVER, request1, request1_len);
2309  if (r != 0) {
2310  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2311  goto end;
2312  }
2313  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2314  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2316  printf("smtp parser in inconsistent state\n");
2317  goto end;
2318  }
2319 
2320  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2321  STREAM_TOCLIENT, reply1, reply1_len);
2322  if (r != 0) {
2323  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2324  goto end;
2325  }
2326  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2328  printf("smtp parser in inconsistent state\n");
2329  goto end;
2330  }
2331 
2332  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2333  STREAM_TOSERVER, request2, request2_len);
2334  if (r != 0) {
2335  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2336  goto end;
2337  }
2338  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2339  smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
2341  printf("smtp parser in inconsistent state\n");
2342  goto end;
2343  }
2344 
2345  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2346  STREAM_TOCLIENT, reply2, reply2_len);
2347  if (r != 0) {
2348  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2349  goto end;
2350  }
2351  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2352  smtp_state->parser_state !=
2354  printf("smtp parser in inconsistent state\n");
2355  goto end;
2356  }
2357 
2358  if (!FlowChangeProto(&f)) {
2359  goto end;
2360  }
2361 
2362  result = 1;
2363 end:
2364  FLOW_DESTROY(&f);
2365  if (alp_tctx != NULL)
2367  StreamTcpFreeConfig(true);
2368  return result;
2369 }
2370 
2371 /**
2372  * \test Test multiple DATA commands(full mail transactions).
2373  */
2374 static int SMTPParserTest02(void)
2375 {
2376  int result = 0;
2377  Flow f;
2378  int r = 0;
2379 
2380  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
2381  uint8_t welcome_reply[] = {
2382  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
2383  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
2384  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
2385  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
2386  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
2387  0x0d, 0x0a
2388  };
2389  uint32_t welcome_reply_len = sizeof(welcome_reply);
2390 
2391  /* EHLO boo.com<CR><LF> */
2392  uint8_t request1[] = {
2393  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2394  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2395  };
2396  uint32_t request1_len = sizeof(request1);
2397  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
2398  * 250-SIZE 35882577<CR><LF>
2399  * 250-8BITMIME<CR><LF>
2400  * 250-STARTTLS<CR><LF>
2401  * 250 ENHANCEDSTATUSCODES<CR><LF>
2402  */
2403  uint8_t reply1[] = {
2404  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2405  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2406  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2407  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2408  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2409  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2410  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2411  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2412  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2413  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2414  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2415  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2416  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2417  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2418  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2419  };
2420  uint32_t reply1_len = sizeof(reply1);
2421 
2422  /* MAIL FROM:asdff@asdf.com<CR><LF> */
2423  uint8_t request2[] = {
2424  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2425  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
2426  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2427  0x0d, 0x0a
2428  };
2429  uint32_t request2_len = sizeof(request2);
2430  /* 250 2.1.0 Ok<CR><LF> */
2431  uint8_t reply2[] = {
2432  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2433  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2434  };
2435  uint32_t reply2_len = sizeof(reply2);
2436 
2437  /* RCPT TO:bimbs@gmail.com<CR><LF> */
2438  uint8_t request3[] = {
2439  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2440  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2441  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2442  0x0a
2443  };
2444  uint32_t request3_len = sizeof(request3);
2445  /* 250 2.1.5 Ok<CR><LF> */
2446  uint8_t reply3[] = {
2447  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2448  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2449  };
2450  uint32_t reply3_len = sizeof(reply3);
2451 
2452  /* DATA<CR><LF> */
2453  uint8_t request4[] = {
2454  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2455  };
2456  uint32_t request4_len = sizeof(request4);
2457  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2458  uint8_t reply4[] = {
2459  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2460  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2461  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2462  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2463  0x4c, 0x46, 0x3e, 0x0d, 0x0a
2464  };
2465  uint32_t reply4_len = sizeof(reply4);
2466 
2467  /* FROM:asdff@asdf.com<CR><LF> */
2468  uint8_t request5_1[] = {
2469  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2470  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2471  0x63, 0x6f, 0x6d, 0x0d, 0x0a
2472  };
2473  uint32_t request5_1_len = sizeof(request5_1);
2474  /* TO:bimbs@gmail.com<CR><LF> */
2475  uint8_t request5_2[] = {
2476  0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2477  0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2478  0x6f, 0x6d, 0x0d, 0x0a
2479  };
2480  uint32_t request5_2_len = sizeof(request5_2);
2481  /* <CR><LF> */
2482  uint8_t request5_3[] = {
2483  0x0d, 0x0a
2484  };
2485  uint32_t request5_3_len = sizeof(request5_3);
2486  /* this is test mail1<CR><LF> */
2487  uint8_t request5_4[] = {
2488  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2489  0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2490  0x6c, 0x31, 0x0d, 0x0a
2491  };
2492  uint32_t request5_4_len = sizeof(request5_4);
2493  /* .<CR><LF> */
2494  uint8_t request5_5[] = {
2495  0x2e, 0x0d, 0x0a
2496  };
2497  uint32_t request5_5_len = sizeof(request5_5);
2498  /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
2499  uint8_t reply5[] = {
2500  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2501  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2502  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2503  0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
2504  0x46, 0x32, 0x0d, 0x0a
2505  };
2506  uint32_t reply5_len = sizeof(reply5);
2507 
2508  /* MAIL FROM:asdfg@asdf.com<CR><LF> */
2509  uint8_t request6[] = {
2510  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2511  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40,
2512  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2513  0x0d, 0x0a
2514  };
2515  uint32_t request6_len = sizeof(request6);
2516  /* 250 2.1.0 Ok<CR><LF> */
2517  uint8_t reply6[] = {
2518  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2519  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2520  };
2521  uint32_t reply6_len = sizeof(reply6);
2522 
2523  /* RCPT TO:bimbs@gmail.com<CR><LF> */
2524  uint8_t request7[] = {
2525  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2526  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2527  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2528  0x0a
2529  };
2530  uint32_t request7_len = sizeof(request7);
2531  /* 250 2.1.5 Ok<CR><LF> */
2532  uint8_t reply7[] = {
2533  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2534  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2535  };
2536  uint32_t reply7_len = sizeof(reply7);
2537 
2538  /* DATA<CR><LF> */
2539  uint8_t request8[] = {
2540  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2541  };
2542  uint32_t request8_len = sizeof(request8);
2543  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2544  uint8_t reply8[] = {
2545  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2546  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2547  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2548  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2549  0x4c, 0x46, 0x3e, 0x0d, 0x0a
2550  };
2551  uint32_t reply8_len = sizeof(reply8);
2552 
2553  /* FROM:asdfg@gmail.com<CR><LF> */
2554  uint8_t request9_1[] = {
2555  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2556  0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
2557  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2558  };
2559  uint32_t request9_1_len = sizeof(request9_1);
2560  /* TO:bimbs@gmail.com<CR><LF> */
2561  uint8_t request9_2[] = {
2562  0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2563  0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2564  0x6f, 0x6d, 0x0d, 0x0a
2565  };
2566  uint32_t request9_2_len = sizeof(request9_2);
2567  /* <CR><LF> */
2568  uint8_t request9_3[] = {
2569  0x0d, 0x0a
2570  };
2571  uint32_t request9_3_len = sizeof(request9_3);
2572  /* this is test mail2<CR><LF> */
2573  uint8_t request9_4[] = {
2574  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2575  0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2576  0x6c, 0x32, 0x0d, 0x0a
2577  };
2578  uint32_t request9_4_len = sizeof(request9_4);
2579  /* .<CR><LF> */
2580  uint8_t request9_5[] = {
2581  0x2e, 0x0d, 0x0a
2582  };
2583  uint32_t request9_5_len = sizeof(request9_5);
2584  /* 250 2.0.0 Ok: queued as 28CFF20BF2<CR><LF> */
2585  uint8_t reply9[] = {
2586  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2587  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2588  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2589  0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42,
2590  0x46, 0x32, 0x0d, 0x0a
2591  };
2592  uint32_t reply9_len = sizeof(reply9);
2593 
2594  /* QUIT<CR><LF> */
2595  uint8_t request10[] = {
2596  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
2597  };
2598  uint32_t request10_len = sizeof(request10);
2599  /* 221 2.0.0 Bye<CR><LF> */
2600  uint8_t reply10[] = {
2601  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2602  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
2603  };
2604  uint32_t reply10_len = sizeof(reply10);
2605 
2606  TcpSession ssn;
2608 
2609  memset(&f, 0, sizeof(f));
2610  memset(&ssn, 0, sizeof(ssn));
2611 
2612  FLOW_INITIALIZE(&f);
2613  f.protoctx = (void *)&ssn;
2614  f.proto = IPPROTO_TCP;
2615  f.alproto = ALPROTO_SMTP;
2616 
2617  StreamTcpInitConfig(true);
2618  SMTPTestInitConfig();
2619 
2620  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2621  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2622  if (r != 0) {
2623  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2624  goto end;
2625  }
2626  SMTPState *smtp_state = f.alstate;
2627  if (smtp_state == NULL) {
2628  printf("no smtp state: ");
2629  goto end;
2630  }
2631  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2633  printf("smtp parser in inconsistent state\n");
2634  goto end;
2635  }
2636 
2637  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2638  STREAM_TOSERVER, request1, request1_len);
2639  if (r != 0) {
2640  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2641  goto end;
2642  }
2643  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2644  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2646  printf("smtp parser in inconsistent state\n");
2647  goto end;
2648  }
2649 
2650  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2651  STREAM_TOCLIENT, reply1, reply1_len);
2652  if (r != 0) {
2653  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2654  goto end;
2655  }
2656  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2658  printf("smtp parser in inconsistent state\n");
2659  goto end;
2660  }
2661 
2662  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2663  STREAM_TOSERVER, request2, request2_len);
2664  if (r != 0) {
2665  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2666  goto end;
2667  }
2668  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2669  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2671  printf("smtp parser in inconsistent state\n");
2672  goto end;
2673  }
2674 
2675  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2676  STREAM_TOCLIENT, reply2, reply2_len);
2677  if (r != 0) {
2678  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2679  goto end;
2680  }
2681  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2683  printf("smtp parser in inconsistent state\n");
2684  goto end;
2685  }
2686 
2687  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2688  STREAM_TOSERVER, request3, request3_len);
2689  if (r != 0) {
2690  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2691  goto end;
2692  }
2693  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2694  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2696  printf("smtp parser in inconsistent state\n");
2697  goto end;
2698  }
2699 
2700  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2701  STREAM_TOCLIENT, reply3, reply3_len);
2702  if (r != 0) {
2703  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2704  goto end;
2705  }
2706  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2708  printf("smtp parser in inconsistent state\n");
2709  goto end;
2710  }
2711 
2712  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2713  STREAM_TOSERVER, request4, request4_len);
2714  if (r != 0) {
2715  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2716  goto end;
2717  }
2718  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2719  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2721  printf("smtp parser in inconsistent state\n");
2722  goto end;
2723  }
2724 
2725  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2726  STREAM_TOCLIENT, reply4, reply4_len);
2727  if (r != 0) {
2728  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2729  goto end;
2730  }
2731  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2732  smtp_state->parser_state !=
2734  printf("smtp parser in inconsistent state\n");
2735  goto end;
2736  }
2737 
2738  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2739  STREAM_TOSERVER, request5_1, request5_1_len);
2740  if (r != 0) {
2741  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2742  goto end;
2743  }
2744  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2745  smtp_state->parser_state !=
2747 
2748  printf("smtp parser in inconsistent state\n");
2749  goto end;
2750  }
2751 
2752  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2753  STREAM_TOSERVER, request5_2, request5_2_len);
2754  if (r != 0) {
2755  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2756  goto end;
2757  }
2758  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2759  smtp_state->parser_state !=
2761 
2762  printf("smtp parser in inconsistent state\n");
2763  goto end;
2764  }
2765 
2766  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2767  STREAM_TOSERVER, request5_3, request5_3_len);
2768  if (r != 0) {
2769  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2770  goto end;
2771  }
2772  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2773  smtp_state->parser_state !=
2775 
2776  printf("smtp parser in inconsistent state\n");
2777  goto end;
2778  }
2779 
2780  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2781  STREAM_TOSERVER, request5_4, request5_4_len);
2782  if (r != 0) {
2783  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2784  goto end;
2785  }
2786  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2787  smtp_state->parser_state !=
2789 
2790  printf("smtp parser in inconsistent state\n");
2791  goto end;
2792  }
2793 
2794  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2795  STREAM_TOSERVER, request5_5, request5_5_len);
2796  if (r != 0) {
2797  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2798  goto end;
2799  }
2800  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2801  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2803  printf("smtp parser in inconsistent state\n");
2804  goto end;
2805  }
2806 
2807  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2808  STREAM_TOCLIENT, reply5, reply5_len);
2809  if (r != 0) {
2810  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2811  goto end;
2812  }
2813  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2815  printf("smtp parser in inconsistent state\n");
2816  goto end;
2817  }
2818 
2819  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2820  STREAM_TOSERVER, request6, request6_len);
2821  if (r != 0) {
2822  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2823  goto end;
2824  }
2825  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2826  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2828  printf("smtp parser in inconsistent state\n");
2829  goto end;
2830  }
2831 
2832  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2833  STREAM_TOCLIENT, reply6, reply6_len);
2834  if (r != 0) {
2835  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2836  goto end;
2837  }
2838  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2840  printf("smtp parser in inconsistent state\n");
2841  goto end;
2842  }
2843 
2844  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2845  STREAM_TOSERVER, request7, request7_len);
2846  if (r != 0) {
2847  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2848  goto end;
2849  }
2850  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2851  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2853  printf("smtp parser in inconsistent state\n");
2854  goto end;
2855  }
2856 
2857  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2858  STREAM_TOCLIENT, reply7, reply7_len);
2859  if (r != 0) {
2860  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2861  goto end;
2862  }
2863  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2865  printf("smtp parser in inconsistent state\n");
2866  goto end;
2867  }
2868 
2869  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2870  STREAM_TOSERVER, request8, request8_len);
2871  if (r != 0) {
2872  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2873  goto end;
2874  }
2875  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2876  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2878  printf("smtp parser in inconsistent state\n");
2879  goto end;
2880  }
2881 
2882  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2883  STREAM_TOCLIENT, reply8, reply8_len);
2884  if (r != 0) {
2885  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2886  goto end;
2887  }
2888  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2889  smtp_state->parser_state !=
2891  printf("smtp parser in inconsistent state\n");
2892  goto end;
2893  }
2894 
2895  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2896  STREAM_TOSERVER, request9_1, request9_1_len);
2897  if (r != 0) {
2898  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2899  goto end;
2900  }
2901  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2902  smtp_state->parser_state !=
2904 
2905  printf("smtp parser in inconsistent state\n");
2906  goto end;
2907  }
2908 
2909  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2910  STREAM_TOSERVER, request9_2, request9_2_len);
2911  if (r != 0) {
2912  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2913  goto end;
2914  }
2915  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2916  smtp_state->parser_state !=
2918 
2919  printf("smtp parser in inconsistent state\n");
2920  goto end;
2921  }
2922 
2923  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2924  STREAM_TOSERVER, request9_3, request9_3_len);
2925  if (r != 0) {
2926  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2927  goto end;
2928  }
2929  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2930  smtp_state->parser_state !=
2932 
2933  printf("smtp parser in inconsistent state\n");
2934  goto end;
2935  }
2936 
2937  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2938  STREAM_TOSERVER, request9_4, request9_4_len);
2939  if (r != 0) {
2940  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2941  goto end;
2942  }
2943  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2944  smtp_state->parser_state !=
2946 
2947  printf("smtp parser in inconsistent state\n");
2948  goto end;
2949  }
2950 
2951  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2952  STREAM_TOSERVER, request9_5, request9_5_len);
2953  if (r != 0) {
2954  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2955  goto end;
2956  }
2957  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2958  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2960  printf("smtp parser in inconsistent state\n");
2961  goto end;
2962  }
2963 
2964  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2965  STREAM_TOCLIENT, reply9, reply9_len);
2966  if (r != 0) {
2967  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2968  goto end;
2969  }
2970  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2972  printf("smtp parser in inconsistent state\n");
2973  goto end;
2974  }
2975 
2976  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2977  STREAM_TOSERVER, request10, request10_len);
2978  if (r != 0) {
2979  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2980  goto end;
2981  }
2982  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2983  smtp_state->cmds[0] != SMTP_COMMAND_QUIT ||
2985  printf("smtp parser in inconsistent state\n");
2986  goto end;
2987  }
2988 
2989  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2990  STREAM_TOCLIENT, reply10, reply10_len);
2991  if (r != 0) {
2992  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2993  goto end;
2994  }
2995  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2997  printf("smtp parser in inconsistent state\n");
2998  goto end;
2999  }
3000 
3001  result = 1;
3002 end:
3003  if (alp_tctx != NULL)
3005  StreamTcpFreeConfig(true);
3006  FLOW_DESTROY(&f);
3007  return result;
3008 }
3009 
3010 /**
3011  * \test Testing parsing pipelined commands.
3012  */
3013 static int SMTPParserTest03(void)
3014 {
3015  int result = 0;
3016  Flow f;
3017  int r = 0;
3018 
3019  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
3020  uint8_t welcome_reply[] = {
3021  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3022  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3023  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3024  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3025  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3026  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3027  };
3028  uint32_t welcome_reply_len = sizeof(welcome_reply);
3029 
3030  /* EHLO boo.com<CR><LF> */
3031  uint8_t request1[] = {
3032  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3033  0x2e, 0x63, 0x6f, 0x6d, 0x0a
3034  };
3035  uint32_t request1_len = sizeof(request1);
3036  /* 250-poona_slack_vm1.localdomain<CR><LF>
3037  * 250-PIPELINING<CR><LF>
3038  * 250-SIZE 10240000<CR><LF>
3039  * 250-VRFY<CR><LF>
3040  * 250-ETRN<CR><LF>
3041  * 250-ENHANCEDSTATUSCODES<CR><LF>
3042  * 250-8BITMIME<CR><LF>
3043  * 250 DSN<CR><LF>
3044  */
3045  uint8_t reply1[] = {
3046  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
3047  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3048  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3049  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
3050  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
3051  0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
3052  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
3053  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
3054  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3055  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
3056  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
3057  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
3058  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
3059  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
3060  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
3061  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
3062  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
3063  };
3064  uint32_t reply1_len = sizeof(reply1);
3065 
3066  /* MAIL FROM:pbsf@asdfs.com<CR><LF>
3067  * RCPT TO:pbsf@asdfs.com<CR><LF>
3068  * DATA<CR><LF>
3069  * Immediate data
3070  */
3071  uint8_t request2[] = {
3072  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3073  0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
3074  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
3075  0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
3076  0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
3077  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
3078  0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
3079  0x49, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74,
3080  0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0d, 0x0a,
3081  };
3082  uint32_t request2_len = sizeof(request2);
3083  /* 250 2.1.0 Ok<CR><LF>
3084  * 250 2.1.5 Ok<CR><LF>
3085  * 354 End data with <CR><LF>.<CR><LF>|<CR><LF>|
3086  */
3087  uint8_t reply2[] = {
3088  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3089  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35,
3090  0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20,
3091  0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20,
3092  0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61,
3093  0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43,
3094  0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c,
3095  0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d,
3096  0x0a
3097  };
3098  uint32_t reply2_len = sizeof(reply2);
3099 
3100  TcpSession ssn;
3102 
3103  memset(&f, 0, sizeof(f));
3104  memset(&ssn, 0, sizeof(ssn));
3105 
3106  FLOW_INITIALIZE(&f);
3107  f.protoctx = (void *)&ssn;
3108  f.proto = IPPROTO_TCP;
3109  f.alproto = ALPROTO_SMTP;
3110 
3111  StreamTcpInitConfig(true);
3112  SMTPTestInitConfig();
3113 
3114  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3115  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3116  if (r != 0) {
3117  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3118  goto end;
3119  }
3120  SMTPState *smtp_state = f.alstate;
3121  if (smtp_state == NULL) {
3122  printf("no smtp state: ");
3123  goto end;
3124  }
3125  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3127  printf("smtp parser in inconsistent state\n");
3128  goto end;
3129  }
3130 
3131  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3132  STREAM_TOSERVER, request1, request1_len);
3133  if (r != 0) {
3134  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3135  goto end;
3136  }
3137  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3138  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3140  printf("smtp parser in inconsistent state\n");
3141  goto end;
3142  }
3143 
3144  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3145  STREAM_TOCLIENT, reply1, reply1_len);
3146  if (r != 0) {
3147  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3148  goto end;
3149  }
3150  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3151  smtp_state->parser_state !=
3153  printf("smtp parser in inconsistent state\n");
3154  goto end;
3155  }
3156 
3157  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3158  STREAM_TOSERVER, request2, request2_len);
3159  if (r != 0) {
3160  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3161  goto end;
3162  }
3163  if (smtp_state->cmds_cnt != 3 || smtp_state->cmds_idx != 0 ||
3164  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3165  smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD ||
3166  smtp_state->cmds[2] != SMTP_COMMAND_DATA ||
3167  smtp_state->parser_state !=
3170  printf("smtp parser in inconsistent state\n");
3171  goto end;
3172  }
3173 
3174  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3175  STREAM_TOCLIENT, reply2, reply2_len);
3176  if (r != 0) {
3177  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3178  goto end;
3179  }
3180  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3181  smtp_state->parser_state !=
3184  printf("smtp parser in inconsistent state\n");
3185  goto end;
3186  }
3187 
3188  result = 1;
3189 end:
3190  if (alp_tctx != NULL)
3192  StreamTcpFreeConfig(true);
3193  FLOW_DESTROY(&f);
3194  return result;
3195 }
3196 
3197 /*
3198  * \test Test smtp with just <LF> delimiter instead of <CR><LF>.
3199  */
3200 static int SMTPParserTest04(void)
3201 {
3202  int result = 0;
3203  Flow f;
3204  int r = 0;
3205 
3206  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
3207  uint8_t welcome_reply[] = {
3208  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3209  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3210  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3211  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3212  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3213  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3214  };
3215  uint32_t welcome_reply_len = sizeof(welcome_reply);
3216 
3217  /* EHLO boo.com<CR><LF> */
3218  uint8_t request1[] = {
3219  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3220  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3221  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3222  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3223  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3224  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3225  };
3226  uint32_t request1_len = sizeof(request1);
3227 
3228  TcpSession ssn;
3230 
3231  memset(&f, 0, sizeof(f));
3232  memset(&ssn, 0, sizeof(ssn));
3233 
3234  FLOW_INITIALIZE(&f);
3235  f.protoctx = (void *)&ssn;
3236  f.proto = IPPROTO_TCP;
3237  f.alproto = ALPROTO_SMTP;
3238 
3239  StreamTcpInitConfig(true);
3240  SMTPTestInitConfig();
3241 
3242  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3243  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3244  if (r != 0) {
3245  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3246  goto end;
3247  }
3248  SMTPState *smtp_state = f.alstate;
3249  if (smtp_state == NULL) {
3250  printf("no smtp state: ");
3251  goto end;
3252  }
3253  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3255  printf("smtp parser in inconsistent state\n");
3256  goto end;
3257  }
3258 
3259  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3260  STREAM_TOSERVER, request1, request1_len);
3261  if (r != 0) {
3262  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3263  goto end;
3264  }
3265  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3266  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3268  printf("smtp parser in inconsistent state\n");
3269  goto end;
3270  }
3271 
3272  result = 1;
3273 end:
3274  if (alp_tctx != NULL)
3276  StreamTcpFreeConfig(true);
3277  FLOW_DESTROY(&f);
3278  return result;
3279 }
3280 
3281 /*
3282  * \test Test STARTTLS fail.
3283  */
3284 static int SMTPParserTest05(void)
3285 {
3286  int result = 0;
3287  Flow f;
3288  int r = 0;
3289 
3290  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
3291  uint8_t welcome_reply[] = {
3292  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3293  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3294  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3295  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3296  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3297  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3298  };
3299  uint32_t welcome_reply_len = sizeof(welcome_reply);
3300 
3301  /* EHLO boo.com<CR><LF> */
3302  uint8_t request1[] = {
3303  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3304  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
3305  };
3306  uint32_t request1_len = sizeof(request1);
3307  /* 250-poona_slack_vm1.localdomain<CR><LF>
3308  * 250-PIPELINING<CR><LF>
3309  * 250-SIZE 10240000<CR><LF>
3310  * 250-VRFY<CR><LF>
3311  * 250-ETRN<CR><LF>
3312  * 250-ENHANCEDSTATUSCODES<CR><LF>
3313  * 250-8BITMIME<CR><LF>
3314  * 250 DSN<CR><LF>
3315  */
3316  uint8_t reply1[] = {
3317  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
3318  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3319  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3320  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
3321  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
3322  0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
3323  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
3324  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
3325  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3326  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
3327  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
3328  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
3329  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
3330  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
3331  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
3332  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
3333  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
3334  };
3335  uint32_t reply1_len = sizeof(reply1);
3336 
3337  /* STARTTLS<CR><LF> */
3338  uint8_t request2[] = {
3339  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
3340  0x0d, 0x0a
3341  };
3342  uint32_t request2_len = sizeof(request2);
3343  /* 502 5.5.2 Error: command not recognized<CR><LF> */
3344  uint8_t reply2[] = {
3345  0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e,
3346  0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a,
3347  0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
3348  0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63,
3349  0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d,
3350  0x0a
3351  };
3352  uint32_t reply2_len = sizeof(reply2);
3353 
3354  /* QUIT<CR><LF> */
3355  uint8_t request3[] = {
3356  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
3357 
3358  };
3359  uint32_t request3_len = sizeof(request3);
3360  /* 221 2.0.0 Bye<CR><LF> */
3361  uint8_t reply3[] = {
3362  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
3363  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
3364  };
3365  uint32_t reply3_len = sizeof(reply3);
3366 
3367  TcpSession ssn;
3369 
3370  memset(&f, 0, sizeof(f));
3371  memset(&ssn, 0, sizeof(ssn));
3372 
3373  FLOW_INITIALIZE(&f);
3374  f.protoctx = (void *)&ssn;
3375  f.proto = IPPROTO_TCP;
3376  f.alproto = ALPROTO_SMTP;
3377 
3378  StreamTcpInitConfig(true);
3379  SMTPTestInitConfig();
3380 
3381  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3382  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3383  if (r != 0) {
3384  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3385  goto end;
3386  }
3387  SMTPState *smtp_state = f.alstate;
3388  if (smtp_state == NULL) {
3389  printf("no smtp state: ");
3390  goto end;
3391  }
3392  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3394  printf("smtp parser in inconsistent state\n");
3395  goto end;
3396  }
3397 
3398  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3399  STREAM_TOSERVER, request1, request1_len);
3400  if (r != 0) {
3401  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3402  goto end;
3403  }
3404  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3405  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3407  printf("smtp parser in inconsistent state\n");
3408  goto end;
3409  }
3410 
3411  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3412  STREAM_TOCLIENT, reply1, reply1_len);
3413  if (r != 0) {
3414  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3415  goto end;
3416  }
3417  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3418  smtp_state->parser_state !=
3420  printf("smtp parser in inconsistent state\n");
3421  goto end;
3422  }
3423 
3424  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3425  STREAM_TOSERVER, request2, request2_len);
3426  if (r != 0) {
3427  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3428  goto end;
3429  }
3430  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3431  smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
3432  smtp_state->parser_state !=
3434  printf("smtp parser in inconsistent state\n");
3435  goto end;
3436  }
3437 
3438  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3439  STREAM_TOCLIENT, reply2, reply2_len);
3440  if (r != 0) {
3441  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3442  goto end;
3443  }
3444  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3445  smtp_state->parser_state !=
3447  printf("smtp parser in inconsistent state\n");
3448  goto end;
3449  }
3450 
3451  if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
3453  (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
3454  (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
3455  goto end;
3456  }
3457 
3458  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3459  STREAM_TOSERVER, request3, request3_len);
3460  if (r != 0) {
3461  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3462  goto end;
3463  }
3464  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3465  smtp_state->cmds[0] != SMTP_COMMAND_QUIT ||
3466  smtp_state->parser_state !=
3468  printf("smtp parser in inconsistent state\n");
3469  goto end;
3470  }
3471 
3472  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3473  STREAM_TOCLIENT, reply3, reply3_len);
3474  if (r != 0) {
3475  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3476  goto end;
3477  }
3478  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3479  smtp_state->parser_state !=
3481  printf("smtp parser in inconsistent state\n");
3482  goto end;
3483  }
3484 
3485  result = 1;
3486 end:
3487  if (alp_tctx != NULL)
3489  StreamTcpFreeConfig(true);
3490  FLOW_DESTROY(&f);
3491  return result;
3492 }
3493 
3494 /**
3495  * \test Test multiple DATA commands(full mail transactions).
3496  */
3497 static int SMTPParserTest06(void)
3498 {
3499  int result = 0;
3500  Flow f;
3501  int r = 0;
3502 
3503  uint8_t welcome_reply[] = {
3504  0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30,
3505  0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3506  0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3507  0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3508  0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e,
3509  0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69,
3510  0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f,
3511  0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c,
3512  0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b,
3513  0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20,
3514  0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f,
3515  0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63,
3516  0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20,
3517  0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
3518  0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69,
3519  0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f,
3520  0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73,
3521  0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e,
3522  0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f,
3523  0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68,
3524  0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72,
3525  0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73,
3526  0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e,
3527  0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f,
3528  0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74,
3529  0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c,
3530  0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
3531  0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20,
3532  0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70,
3533  0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63,
3534  0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
3535  0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
3536  0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f,
3537  0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61,
3538  0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69,
3539  0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62,
3540  0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35,
3541  0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d,
3542  0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a
3543  };
3544  uint32_t welcome_reply_len = sizeof(welcome_reply);
3545 
3546  uint8_t request1[] = {
3547  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43,
3548  0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63,
3549  0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69,
3550  0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d,
3551  0x0a
3552  };
3553  uint32_t request1_len = sizeof(request1);
3554 
3555  uint8_t reply1[] = {
3556  0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30,
3557  0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3558  0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3559  0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3560  0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31,
3561  0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c,
3562  0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31,
3563  0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39,
3564  0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53,
3565  0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39,
3566  0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35,
3567  0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69,
3568  0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3569  0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49,
3570  0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3571  0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47,
3572  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3573  0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3574  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3575  0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3576  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b,
3577  0x0d, 0x0a
3578  };
3579  uint32_t reply1_len = sizeof(reply1);
3580 
3581  /* MAIL FROM:asdff@asdf.com<CR><LF> */
3582  uint8_t request2[] = {
3583  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3584  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
3585  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
3586  0x0d, 0x0a
3587  };
3588  uint32_t request2_len = sizeof(request2);
3589  /* 250 2.1.0 Ok<CR><LF> */
3590  uint8_t reply2[] = {
3591  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3592  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3593  };
3594  uint32_t reply2_len = sizeof(reply2);
3595 
3596  /* RCPT TO:bimbs@gmail.com<CR><LF> */
3597  uint8_t request3[] = {
3598  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
3599  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
3600  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3601  0x0a
3602  };
3603  uint32_t request3_len = sizeof(request3);
3604  /* 250 2.1.5 Ok<CR><LF> */
3605  uint8_t reply3[] = {
3606  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3607  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3608  };
3609  uint32_t reply3_len = sizeof(reply3);
3610 
3611  /* BDAT 51<CR><LF> */
3612  uint8_t request4[] = {
3613  0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d,
3614  0x0a,
3615  };
3616  uint32_t request4_len = sizeof(request4);
3617 
3618  uint8_t request5[] = {
3619  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3620  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3621  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3622  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a,
3623  };
3624  uint32_t request5_len = sizeof(request5);
3625 
3626  uint8_t request6[] = {
3627  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3628  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3629  0x66, 0x0d, 0x0a,
3630  };
3631  uint32_t request6_len = sizeof(request6);
3632 
3633  TcpSession ssn;
3635 
3636  memset(&f, 0, sizeof(f));
3637  memset(&ssn, 0, sizeof(ssn));
3638 
3639  FLOW_INITIALIZE(&f);
3640  f.protoctx = (void *)&ssn;
3641  f.proto = IPPROTO_TCP;
3642  f.alproto = ALPROTO_SMTP;
3643 
3644  StreamTcpInitConfig(true);
3645  SMTPTestInitConfig();
3646 
3647  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3648  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3649  if (r != 0) {
3650  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3651  goto end;
3652  }
3653  SMTPState *smtp_state = f.alstate;
3654  if (smtp_state == NULL) {
3655  printf("no smtp state: ");
3656  goto end;
3657  }
3658  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3660  printf("smtp parser in inconsistent state\n");
3661  goto end;
3662  }
3663 
3664  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3665  STREAM_TOSERVER, request1, request1_len);
3666  if (r != 0) {
3667  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3668  goto end;
3669  }
3670  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3671  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3673  printf("smtp parser in inconsistent state\n");
3674  goto end;
3675  }
3676 
3677  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3678  STREAM_TOCLIENT, reply1, reply1_len);
3679  if (r != 0) {
3680  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3681  goto end;
3682  }
3683  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3685  printf("smtp parser in inconsistent state\n");
3686  goto end;
3687  }
3688 
3689  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3690  STREAM_TOSERVER, request2, request2_len);
3691  if (r != 0) {
3692  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3693  goto end;
3694  }
3695  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3696  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3698  printf("smtp parser in inconsistent state\n");
3699  goto end;
3700  }
3701 
3702  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3703  STREAM_TOCLIENT, reply2, reply2_len);
3704  if (r != 0) {
3705  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3706  goto end;
3707  }
3708  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3710  printf("smtp parser in inconsistent state\n");
3711  goto end;
3712  }
3713 
3714  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3715  STREAM_TOSERVER, request3, request3_len);
3716  if (r != 0) {
3717  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3718  goto end;
3719  }
3720  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3721  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3723  printf("smtp parser in inconsistent state\n");
3724  goto end;
3725  }
3726 
3727  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3728  STREAM_TOCLIENT, reply3, reply3_len);
3729  if (r != 0) {
3730  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3731  goto end;
3732  }
3733  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3735  printf("smtp parser in inconsistent state\n");
3736  goto end;
3737  }
3738 
3739  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3740  STREAM_TOSERVER, request4, request4_len);
3741  if (r != 0) {
3742  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3743  goto end;
3744  }
3745  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3746  smtp_state->cmds[0] != SMTP_COMMAND_BDAT ||
3747  smtp_state->parser_state !=
3749  smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 0) {
3750  printf("smtp parser in inconsistent state\n");
3751  goto end;
3752  }
3753 
3754  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3755  STREAM_TOSERVER, request5, request5_len);
3756  if (r != 0) {
3757  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3758  goto end;
3759  }
3760  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3761  smtp_state->parser_state !=
3763  smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 32) {
3764  printf("smtp parser in inconsistent state\n");
3765  goto end;
3766  }
3767 
3768  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3769  STREAM_TOSERVER, request6, request6_len);
3770  if (r != 0) {
3771  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3772  goto end;
3773  }
3774  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3776  smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 51) {
3777  printf("smtp parser in inconsistent state\n");
3778  goto end;
3779  }
3780 
3781  result = 1;
3782 end:
3783  if (alp_tctx != NULL)
3785  StreamTcpFreeConfig(true);
3786  FLOW_DESTROY(&f);
3787  return result;
3788 }
3789 
3790 static int SMTPParserTest12(void)
3791 {
3792  int result = 0;
3793  Signature *s = NULL;
3794  ThreadVars th_v;
3795  Packet *p = NULL;
3796  Flow f;
3797  TcpSession ssn;
3798  DetectEngineThreadCtx *det_ctx = NULL;
3799  DetectEngineCtx *de_ctx = NULL;
3800  SMTPState *smtp_state = NULL;
3801  int r = 0;
3802 
3803  /* EHLO boo.com<CR><LF> */
3804  uint8_t request1[] = {
3805  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3806  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3807  };
3808  int32_t request1_len = sizeof(request1);
3809 
3810  /* 388<CR><LF>
3811  */
3812  uint8_t reply1[] = {
3813  0x31, 0x38, 0x38, 0x0d, 0x0a,
3814  };
3815  uint32_t reply1_len = sizeof(reply1);
3816 
3818 
3819  memset(&th_v, 0, sizeof(th_v));
3821  memset(&f, 0, sizeof(f));
3822  memset(&ssn, 0, sizeof(ssn));
3823 
3824  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
3825 
3826  FLOW_INITIALIZE(&f);
3827  f.protoctx = (void *)&ssn;
3828  f.proto = IPPROTO_TCP;
3829  f.alproto = ALPROTO_SMTP;
3830  p->flow = &f;
3834  f.alproto = ALPROTO_SMTP;
3835 
3836  StreamTcpInitConfig(true);
3837  SMTPTestInitConfig();
3838 
3840  if (de_ctx == NULL)
3841  goto end;
3842 
3843  de_ctx->flags |= DE_QUIET;
3844 
3845  s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any "
3846  "(msg:\"SMTP event handling\"; "
3847  "app-layer-event: smtp.invalid_reply; "
3848  "sid:1;)");
3849  if (s == NULL)
3850  goto end;
3851 
3853  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
3854 
3855  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3856  STREAM_TOSERVER | STREAM_START, request1,
3857  request1_len);
3858  if (r != 0) {
3859  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3860  goto end;
3861  }
3862 
3863  smtp_state = f.alstate;
3864  if (smtp_state == NULL) {
3865  printf("no smtp state: ");
3866  goto end;
3867  }
3868 
3869  /* do detect */
3870  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3871 
3872  if (PacketAlertCheck(p, 1)) {
3873  printf("sid 1 matched. It shouldn't match: ");
3874  goto end;
3875  }
3876 
3877  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3878  STREAM_TOCLIENT | STREAM_TOCLIENT, reply1,
3879  reply1_len);
3880  if (r == 0) {
3881  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3882  goto end;
3883  }
3884 
3885  /* do detect */
3886  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3887 
3888  if (!PacketAlertCheck(p, 1)) {
3889  printf("sid 1 didn't match. Should have matched: ");
3890  goto end;
3891  }
3892 
3893  result = 1;
3894 
3895 end:
3896  UTHFreePackets(&p, 1);
3897  FLOW_DESTROY(&f);
3898  if (alp_tctx != NULL)
3900  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
3902  StreamTcpFreeConfig(true);
3904  return result;
3905 }
3906 
3907 static int SMTPParserTest13(void)
3908 {
3909  int result = 0;
3910  Signature *s = NULL;
3911  ThreadVars th_v;
3912  Packet *p = NULL;
3913  Flow f;
3914  TcpSession ssn;
3915  DetectEngineThreadCtx *det_ctx = NULL;
3916  DetectEngineCtx *de_ctx = NULL;
3917  SMTPState *smtp_state = NULL;
3918  int r = 0;
3919 
3920  /* EHLO boo.com<CR><LF> */
3921  uint8_t request1[] = {
3922  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3923  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3924  };
3925  int32_t request1_len = sizeof(request1);
3926 
3927  /* 250<CR><LF>
3928  */
3929  uint8_t reply1[] = {
3930  0x32, 0x35, 0x30, 0x0d, 0x0a,
3931  };
3932  uint32_t reply1_len = sizeof(reply1);
3933 
3934  /* MAIL FROM:pbsf@asdfs.com<CR><LF>
3935  * RCPT TO:pbsf@asdfs.com<CR><LF>
3936  * DATA<CR><LF>
3937  * STARTTLS<CR><LF>
3938  */
3939  uint8_t request2[] = {
3940  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3941  0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
3942  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
3943  0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
3944  0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
3945  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
3946  0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
3947  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
3948  0x0d, 0x0a
3949  };
3950  uint32_t request2_len = sizeof(request2);
3951 
3953 
3954  memset(&th_v, 0, sizeof(th_v));
3956  memset(&f, 0, sizeof(f));
3957  memset(&ssn, 0, sizeof(ssn));
3958 
3959  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
3960 
3961  FLOW_INITIALIZE(&f);
3962  f.protoctx = (void *)&ssn;
3963  f.proto = IPPROTO_TCP;
3964  f.alproto = ALPROTO_SMTP;
3965  p->flow = &f;
3969  f.alproto = ALPROTO_SMTP;
3970 
3971  StreamTcpInitConfig(true);
3972  SMTPTestInitConfig();
3973 
3975  if (de_ctx == NULL)
3976  goto end;
3977 
3978  de_ctx->flags |= DE_QUIET;
3979 
3980  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
3981  "(msg:\"SMTP event handling\"; "
3982  "app-layer-event: "
3983  "smtp.invalid_pipelined_sequence; "
3984  "sid:1;)");
3985  if (s == NULL)
3986  goto end;
3987 
3989  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
3990 
3991  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3992  STREAM_TOSERVER | STREAM_START, request1,
3993  request1_len);
3994  if (r != 0) {
3995  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3996  goto end;
3997  }
3998 
3999  smtp_state = f.alstate;
4000  if (smtp_state == NULL) {
4001  printf("no smtp state: ");
4002  goto end;
4003  }
4004 
4005  /* do detect */
4006  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4007 
4008  if (PacketAlertCheck(p, 1)) {
4009  printf("sid 1 matched. It shouldn't match: ");
4010  goto end;
4011  }
4012 
4013  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4014  STREAM_TOCLIENT, reply1, reply1_len);
4015  if (r != 0) {
4016  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4017  goto end;
4018  }
4019 
4020  /* do detect */
4021  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4022 
4023  if (PacketAlertCheck(p, 1)) {
4024  printf("sid 1 matched. It shouldn't match: ");
4025  goto end;
4026  }
4027 
4028  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4029  STREAM_TOSERVER, request2, request2_len);
4030  if (r != 0) {
4031  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4032  goto end;
4033  }
4034 
4035  /* do detect */
4036  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4037 
4038  if (!PacketAlertCheck(p, 1)) {
4039  printf("sid 1 didn't match. Should have matched: ");
4040  goto end;
4041  }
4042 
4043  result = 1;
4044 end:
4045  UTHFreePackets(&p, 1);
4046  FLOW_DESTROY(&f);
4047  if (alp_tctx != NULL)
4049  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4051  StreamTcpFreeConfig(true);
4053  return result;
4054 }
4055 
4056 /**
4057  * \test Test DATA command w/MIME message.
4058  */
4059 static int SMTPParserTest14(void)
4060 {
4061  int result = 0;
4062  Flow f;
4063  int r = 0;
4064 
4065  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
4066  static uint8_t welcome_reply[] = {
4067  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
4068  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
4069  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
4070  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
4071  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
4072  0x0d, 0x0a
4073  };
4074  static uint32_t welcome_reply_len = sizeof(welcome_reply);
4075 
4076  /* EHLO boo.com<CR><LF> */
4077  static uint8_t request1[] = {
4078  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4079  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
4080  };
4081  static uint32_t request1_len = sizeof(request1);
4082  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
4083  * 250-SIZE 35882577<CR><LF>
4084  * 250-8BITMIME<CR><LF>
4085  * 250-STARTTLS<CR><LF>
4086  * 250 ENHANCEDSTATUSCODES<CR><LF>
4087  */
4088  static uint8_t reply1[] = {
4089  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
4090  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
4091  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
4092  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
4093  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
4094  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
4095  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
4096  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
4097  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
4098  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
4099  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
4100  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
4101  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
4102  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
4103  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
4104  };
4105  static uint32_t reply1_len = sizeof(reply1);
4106 
4107  /* MAIL FROM:asdff@asdf.com<CR><LF> */
4108  static uint8_t request2[] = {
4109  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
4110  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
4111  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
4112  0x0d, 0x0a
4113  };
4114  static uint32_t request2_len = sizeof(request2);
4115  /* 250 2.1.0 Ok<CR><LF> */
4116  static uint8_t reply2[] = {
4117  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4118  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4119  };
4120  static uint32_t reply2_len = sizeof(reply2);
4121 
4122  /* RCPT TO:bimbs@gmail.com<CR><LF> */
4123  static uint8_t request3[] = {
4124  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
4125  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
4126  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
4127  0x0a
4128  };
4129  static uint32_t request3_len = sizeof(request3);
4130  /* 250 2.1.5 Ok<CR><LF> */
4131  static uint8_t reply3[] = {
4132  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4133  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4134  };
4135  static uint32_t reply3_len = sizeof(reply3);
4136 
4137  /* DATA<CR><LF> */
4138  static uint8_t request4[] = {
4139  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
4140  };
4141  static uint32_t request4_len = sizeof(request4);
4142  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
4143  static uint8_t reply4[] = {
4144  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
4145  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
4146  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
4147  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
4148  0x4c, 0x46, 0x3e, 0x0d, 0x0a
4149  };
4150  static uint32_t reply4_len = sizeof(reply4);
4151 
4152  /* MIME_MSG */
4153  static uint64_t filesize = 133;
4154  static uint8_t request4_msg[] = {
4155  0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
4156  0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
4157  0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4158  0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
4159  0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
4160  0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
4161  0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
4162  0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4163  0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
4164  0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
4165  0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
4166  0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
4167  0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
4168  0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
4169  0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
4170  0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
4171  0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
4172  0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
4173  0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
4174  0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
4175  0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
4176  0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
4177  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4178  0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
4179  0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
4180  0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
4181  0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
4182  0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
4183  0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
4184  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4185  0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
4186  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4187  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4188  0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
4189  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4190  0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4191  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4192  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4193  0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
4194  0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
4195  0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
4196  0x41, 0x3D, 0x3D, 0x0D,0x0A };
4197  static uint32_t request4_msg_len = sizeof(request4_msg);
4198 
4199  /* DATA COMPLETED */
4200  static uint8_t request4_end[] = {
4201  0x0d, 0x0a, 0x2e, 0x0d, 0x0a
4202  };
4203  static uint32_t request4_end_len = sizeof(request4_end);
4204  /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
4205  static uint8_t reply4_end[] = {
4206  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4207  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
4208  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
4209  0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
4210  0x46, 0x32, 0x0d, 0x0a
4211  };
4212  static uint32_t reply4_end_len = sizeof(reply4_end);
4213 
4214  /* QUIT<CR><LF> */
4215  static uint8_t request5[] = {
4216  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
4217  };
4218  static uint32_t request5_len = sizeof(request5);
4219  /* 221 2.0.0 Bye<CR><LF> */
4220  static uint8_t reply5[] = {
4221  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4222  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
4223  };
4224  static uint32_t reply5_len = sizeof(reply5);
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 
4237  StreamTcpInitConfig(true);
4238  SMTPTestInitConfig();
4239 
4240  /* Welcome reply */
4241  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4242  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
4243  if (r != 0) {
4244  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4245  goto end;
4246  }
4247  SMTPState *smtp_state = f.alstate;
4248  if (smtp_state == NULL) {
4249  printf("no smtp state: ");
4250  goto end;
4251  }
4252  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4254  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4255  goto end;
4256  }
4257 
4258  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4259  STREAM_TOSERVER, request1, request1_len);
4260  if (r != 0) {
4261  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4262  goto end;
4263  }
4264  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4265  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4267  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4268  goto end;
4269  }
4270 
4271  /* EHLO Reply */
4272  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4273  STREAM_TOCLIENT, reply1, reply1_len);
4274  if (r != 0) {
4275  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4276  goto end;
4277  }
4278 
4279  if ((smtp_state->helo_len != 7) || strncmp("boo.com", (char *)smtp_state->helo, 7)) {
4280  printf("incorrect parsing of HELO field '%s' (%d)\n", smtp_state->helo, smtp_state->helo_len);
4281  goto end;
4282  }
4283 
4284  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4286  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4287  goto end;
4288  }
4289 
4290  /* MAIL FROM Request */
4291  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4292  STREAM_TOSERVER, request2, request2_len);
4293  if (r != 0) {
4294  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4295  goto end;
4296  }
4297  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4298  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4300  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4301  goto end;
4302  }
4303 
4304  /* MAIL FROM Reply */
4305  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4306  STREAM_TOCLIENT, reply2, reply2_len);
4307  if (r != 0) {
4308  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4309  goto end;
4310  }
4311 
4312  if ((smtp_state->curr_tx->mail_from_len != 14) ||
4313  strncmp("asdff@asdf.com", (char *)smtp_state->curr_tx->mail_from, 14)) {
4314  printf("incorrect parsing of MAIL FROM field '%s' (%d)\n",
4315  smtp_state->curr_tx->mail_from,
4316  smtp_state->curr_tx->mail_from_len);
4317  goto end;
4318  }
4319 
4320  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4322  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4323  goto end;
4324  }
4325 
4326  /* RCPT TO Request */
4327  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4328  STREAM_TOSERVER, request3, request3_len);
4329  if (r != 0) {
4330  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4331  goto end;
4332  }
4333  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4334  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4336  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4337  goto end;
4338  }
4339 
4340  /* RCPT TO Reply */
4341  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4342  STREAM_TOCLIENT, reply3, reply3_len);
4343  if (r != 0) {
4344  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4345  goto end;
4346  }
4347  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4349  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4350  goto end;
4351  }
4352 
4353  /* Enable mime decoding */
4354  smtp_config.decode_mime = true;
4355  SCMimeSmtpConfigDecodeBase64(1);
4356  SCMimeSmtpConfigDecodeQuoted(1);
4357 
4358  /* DATA request */
4359  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4360  STREAM_TOSERVER, request4, request4_len);
4361  if (r != 0) {
4362  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4363  goto end;
4364  }
4365 
4366  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4367  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
4369  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4370  goto end;
4371  }
4372 
4373  /* Data reply */
4374  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4375  STREAM_TOCLIENT, reply4, reply4_len);
4376  if (r != 0) {
4377  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4378  goto end;
4379  }
4380  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4381  smtp_state->parser_state !=
4383  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4384  goto end;
4385  }
4386 
4387  /* DATA message */
4388  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4389  STREAM_TOSERVER, request4_msg, request4_msg_len);
4390  if (r != 0) {
4391  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4392  goto end;
4393  }
4394 
4395  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4396  smtp_state->curr_tx->mime_state == NULL ||
4397  smtp_state->parser_state !=
4399  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4400  goto end;
4401  }
4402 
4403  /* DATA . request */
4404  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4405  STREAM_TOSERVER, request4_end, request4_end_len);
4406  if (r != 0) {
4407  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4408  goto end;
4409  }
4410 
4411  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4412  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
4413  smtp_state->curr_tx->mime_state == NULL ||
4415  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4416  goto end;
4417  }
4418 
4419  SMTPState *state = (SMTPState *) f.alstate;
4420  FAIL_IF_NULL(state);
4421  FAIL_IF_NULL(state->curr_tx);
4422 
4423  FileContainer *files = &state->curr_tx->files_ts;
4424  if (files != NULL && files->head != NULL) {
4425  File *file = files->head;
4426 
4427  if(strncmp((const char *)file->name, "test.exe", 8) != 0){
4428  printf("smtp-mime file name is incorrect");
4429  goto end;
4430  }
4431  if (FileTrackedSize(file) != filesize){
4432  printf("smtp-mime file size %"PRIu64" is incorrect", FileDataSize(file));
4433  goto end;
4434  }
4435  static uint8_t org_binary[] = {
4436  0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00,
4437  0x4C, 0x01, 0x01, 0x00, 0x6A, 0x2A, 0x58, 0xC3,
4438  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4439  0x04, 0x00, 0x03, 0x01, 0x0B, 0x01, 0x08, 0x00,
4440  0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
4441  0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4442  0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4443  0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00,
4444  0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00,
4445  0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
4446  0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00,
4447  0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4448  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4449  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4450  0x00, 0x00, 0x00, 0x00, 0x5C, 0x5C, 0x36, 0x36,
4451  0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36,
4452  0x5C, 0x7A, 0x00, 0x00, 0x38,};
4453 
4455  org_binary, sizeof(org_binary)) != 1)
4456  {
4457  printf("smtp-mime file data incorrect\n");
4458  goto end;
4459  }
4460  }
4461 
4462  /* DATA . reply */
4463  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4464  STREAM_TOCLIENT, reply4_end, reply4_end_len);
4465  if (r != 0) {
4466  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4467  goto end;
4468  }
4469  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4471  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4472  goto end;
4473  }
4474 
4475  /* QUIT Request */
4476  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4477  STREAM_TOSERVER, request5, request5_len);
4478  if (r != 0) {
4479  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4480  goto end;
4481  }
4482  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4483  smtp_state->cmds[0] != SMTP_COMMAND_QUIT ||
4485  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4486  goto end;
4487  }
4488 
4489  /* QUIT Reply */
4490  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4491  STREAM_TOCLIENT, reply5, reply5_len);
4492  if (r != 0) {
4493  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4494  goto end;
4495  }
4496  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4498  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4499  goto end;
4500  }
4501 
4502  result = 1;
4503 end:
4504  FLOW_DESTROY(&f);
4505  if (alp_tctx != NULL)
4507  StreamTcpFreeConfig(true);
4508  return result;
4509 }
4510 
4511 #endif /* UNITTESTS */
4512 
4514 {
4515 #ifdef UNITTESTS
4516  UtRegisterTest("SMTPParserTest01", SMTPParserTest01);
4517  UtRegisterTest("SMTPParserTest02", SMTPParserTest02);
4518  UtRegisterTest("SMTPParserTest03", SMTPParserTest03);
4519  UtRegisterTest("SMTPParserTest04", SMTPParserTest04);
4520  UtRegisterTest("SMTPParserTest05", SMTPParserTest05);
4521  UtRegisterTest("SMTPParserTest06", SMTPParserTest06);
4522  UtRegisterTest("SMTPParserTest12", SMTPParserTest12);
4523  UtRegisterTest("SMTPParserTest13", SMTPParserTest13);
4524  UtRegisterTest("SMTPParserTest14", SMTPParserTest14);
4525 #endif /* UNITTESTS */
4526 }
PmqReset
void PmqReset(PrefilterRuleStore *pmq)
Reset a Pmq for reusage. Meant to be called after a single search.
Definition: util-prefilter.c:102
util-byte.h
StreamSlice
Definition: app-layer-parser.h:120
SMTPConfig::content_limit
uint32_t content_limit
Definition: app-layer-smtp.h:122
SMTPState_
Definition: app-layer-smtp.h:132
AppLayerParserRegisterGetStateProgressFunc
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, int(*StateGetProgress)(void *alstate, uint8_t direction))
Definition: app-layer-parser.c:536
FileContainer_
Definition: util-file.h:37
len
uint8_t len
Definition: app-layer-dnp3.h:2
SCAppLayerParserStateIssetFlag
uint16_t SCAppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint16_t flag)
Definition: app-layer-parser.c:2105
SCConfValIsTrue
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:578
detect-engine.h
SMTP_DECODER_EVENT_TLS_REJECTED
@ SMTP_DECODER_EVENT_TLS_REJECTED
Definition: app-layer-smtp.h:44
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED
@ SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED
Definition: app-layer-smtp.h:38
SMTPCode
SMTPCode
Definition: app-layer-smtp.c:277
DetectEngineStateDirection_::flags
uint8_t flags
Definition: detect-engine-state.h:91
AppLayerGetTxIterState::ptr
void * ptr
Definition: app-layer-parser.h:144
SMTPState_::cmds_cnt
uint16_t cmds_cnt
Definition: app-layer-smtp.h:162
Flow_::flags
uint64_t flags
Definition: flow.h:404
SMTP_REPLY_534
@ SMTP_REPLY_534
Definition: app-layer-smtp.c:310
StreamingBufferConfig_::buf_size
uint32_t buf_size
Definition: util-streaming-buffer.h:66
PKT_HAS_FLOW
#define PKT_HAS_FLOW
Definition: decode.h:1311
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
AppLayerParserRegisterLocalStorageFunc
void AppLayerParserRegisterLocalStorageFunc(uint8_t ipproto, AppProto alproto, void *(*LocalStorageAlloc)(void), void(*LocalStorageFree)(void *))
Definition: app-layer-parser.c:496
SMTP_REPLY_525
@ SMTP_REPLY_525
Definition: app-layer-smtp.c:308
SMTP_PARSER_STATE_FIRST_REPLY_SEEN
#define SMTP_PARSER_STATE_FIRST_REPLY_SEEN
Definition: app-layer-smtp.c:77
SMTP_DECODER_EVENT_MIME_LONG_LINE
@ SMTP_DECODER_EVENT_MIME_LONG_LINE
Definition: app-layer-smtp.h:53
TAILQ_INIT
#define TAILQ_INIT(head)
Definition: queue.h:262
flow-util.h
SMTP_RESPONSE_STARTED
@ SMTP_RESPONSE_STARTED
Definition: app-layer-smtp.h:81
SMTPInput_::buf
const uint8_t * buf
Definition: app-layer-smtp.c:109
SMTP_COMMAND_DATA
#define SMTP_COMMAND_DATA
Definition: app-layer-smtp.c:88
SMTP_REPLY_535
@ SMTP_REPLY_535
Definition: app-layer-smtp.c:311
MpmThreadCtx_
Definition: util-mpm.h:62
stream-tcp.h
SMTP_REPLY_401
@ SMTP_REPLY_401
Definition: app-layer-smtp.c:290
SMTPState_::bdat_chunk_idx
uint32_t bdat_chunk_idx
Definition: app-layer-smtp.h:151
SMTPTransaction_::progress_ts
uint8_t progress_ts
Definition: app-layer-smtp.h:93
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
ALPROTO_TLS
@ ALPROTO_TLS
Definition: app-layer-protos.h:39
File_::size
uint64_t size
Definition: util-file.h:169
PrefilterRuleStore_
structure for storing potential rule matches
Definition: util-prefilter.h:34
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
ParseSizeStringU64
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:191
SMTPLine
struct SMTPLine_ SMTPLine
SCAppLayerTxDataCleanup
void SCAppLayerTxDataCleanup(AppLayerTxData *txd)
Definition: app-layer-parser.c:823
SMTPLine_::buf
const uint8_t * buf
Definition: app-layer-smtp.c:121
SMTPConfig
Structure for containing configuration options.
Definition: app-layer-smtp.h:119
SMTP_REPLY_421
@ SMTP_REPLY_421
Definition: app-layer-smtp.c:292
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
AppLayerTxData::de_state
DetectEngineState * de_state
Definition: app-layer-parser.h:217
SMTPState_::discard_till_lf_tc
bool discard_till_lf_tc
Definition: app-layer-smtp.h:142
name
const char * name
Definition: detect-engine-proto.c:48
Flow_::proto
uint8_t proto
Definition: flow.h:377
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:87
PacketAlertCheck
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
Definition: detect-engine-alert.c:144
StreamTcpReassemblySetMinInspectDepth
void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
Definition: stream-tcp-reassemble.c:2171
SCAppLayerProtoDetectPMRegisterPatternCI
int SCAppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction)
Registers a case-insensitive pattern for protocol detection.
Definition: app-layer-detect-proto.c:1673
STREAMING_BUFFER_CONFIG_INITIALIZER
#define STREAMING_BUFFER_CONFIG_INITIALIZER
Definition: util-streaming-buffer.h:74
SMTPConfig::decode_mime
bool decode_mime
Definition: app-layer-smtp.h:121
Packet_::flags
uint32_t flags
Definition: decode.h:562
type
uint8_t type
Definition: decode-sctp.h:0
AppLayerStateData
Definition: app-layer-parser.h:149
FILE_STATE_OPENED
@ FILE_STATE_OPENED
Definition: util-file.h:137
Frame::offset
uint64_t offset
Definition: app-layer-frames.h:49
Frame
Definition: app-layer-frames.h:43
Flow_
Flow data structure.
Definition: flow.h:355
SMTP_REPLY_454
@ SMTP_REPLY_454
Definition: app-layer-smtp.c:297
SCHEME_SUFFIX_LEN
#define SCHEME_SUFFIX_LEN
Definition: app-layer-smtp.c:381
SMTP_REPLY_503
@ SMTP_REPLY_503
Definition: app-layer-smtp.c:303
File_::state
FileState state
Definition: util-file.h:149
SMTP_REPLY_553
@ SMTP_REPLY_553
Definition: app-layer-smtp.c:317
SMTP_REPLY_500
@ SMTP_REPLY_500
Definition: app-layer-smtp.c:300
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:987
th_v
ThreadVars * th_v
Definition: fuzz_iprep.c:20
AppLayerParserRegisterStateProgressCompletionStatus
void AppLayerParserRegisterStateProgressCompletionStatus(AppProto alproto, const int ts, const int tc)
Definition: app-layer-parser.c:584
SMTPState_::toserver_last_data_stamp
uint64_t toserver_last_data_stamp
Definition: app-layer-smtp.h:138
SMTPThreadCtx
struct SMTPThreadCtx_ SMTPThreadCtx
AppLayerParserRegisterTxFreeFunc
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))
Definition: app-layer-parser.c:546
FLOW_NOPAYLOAD_INSPECTION
#define FLOW_NOPAYLOAD_INSPECTION
Definition: flow.h:67
SMTPTransaction_::progress_tc
uint8_t progress_tc
Definition: app-layer-smtp.h:95
TAILQ_EMPTY
#define TAILQ_EMPTY(head)
Definition: queue.h:248
SCEnumCharMap_::enum_value
int enum_value
Definition: util-enum.h:29
AppLayerFrameSetTxId
void AppLayerFrameSetTxId(Frame *r, uint64_t tx_id)
Definition: app-layer-frames.c:682
SMTPState_::tx_cnt
uint64_t tx_cnt
Definition: app-layer-smtp.h:136
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2878
SMTP_REPLY_522
@ SMTP_REPLY_522
Definition: app-layer-smtp.c:307
SCConfGetChildValueBool
int SCConfGetChildValueBool(const SCConfNode *base, const char *name, int *val)
Definition: conf.c:542
SMTP_REPLY_521
@ SMTP_REPLY_521
Definition: app-layer-smtp.c:306
DetectEngineState_::dir_state
DetectEngineStateDirection dir_state[2]
Definition: detect-engine-state.h:96
SMTP_FRAME_RESPONSE_LINE
@ SMTP_FRAME_RESPONSE_LINE
Definition: app-layer-smtp.c:162
AppLayerParserThreadCtxFree
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
Definition: app-layer-parser.c:356
SMTPState_::cmds_idx
uint16_t cmds_idx
Definition: app-layer-smtp.h:165
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:232
SMTP_FRAME_DATA
@ SMTP_FRAME_DATA
Definition: app-layer-smtp.c:161
FileContainer_::tail
File * tail
Definition: util-file.h:39
MIN
#define MIN(x, y)
Definition: suricata-common.h:416
SCConfGetBool
int SCConfGetBool(const char *name, int *val)
Retrieve a configuration value as a boolean.
Definition: conf.c:524
AppLayerParserRegisterGetStateFuncs
void AppLayerParserRegisterGetStateFuncs(uint8_t ipproto, AppProto alproto, AppLayerParserGetStateIdByNameFn GetIdByNameFunc, AppLayerParserGetStateNameByIdFn GetNameByIdFunc)
Definition: app-layer-parser.c:643
DE_QUIET
#define DE_QUIET
Definition: detect.h:333
SMTP_REPLY_552
@ SMTP_REPLY_552
Definition: app-layer-smtp.c:316
SCConfValIsFalse
int SCConfValIsFalse(const char *val)
Check if a value is false.
Definition: conf.c:603
ALPROTO_FTP
@ ALPROTO_FTP
Definition: app-layer-protos.h:37
UTHBuildPacket
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
Definition: util-unittest-helper.c:243
ByteExtractStringUint32
int ByteExtractStringUint32(uint32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:195
SMTP_REPLY_550
@ SMTP_REPLY_550
Definition: app-layer-smtp.c:314
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:3064
FILEDATA_CONTENT_LIMIT
#define FILEDATA_CONTENT_LIMIT
Definition: app-layer-smtp.c:59
SMTP_REPLY_334
@ SMTP_REPLY_334
Definition: app-layer-smtp.c:287
SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED
@ SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED
Definition: app-layer-smtp.h:39
TAILQ_INSERT_TAIL
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:294
p
Packet * p
Definition: fuzz_iprep.c:21
Flow_::dp
Port dp
Definition: flow.h:371
DetectEngineAppendSig
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:3859
SMTPThreadCtx_
Definition: app-layer-smtp.c:266
SMTP_REQUEST_COMPLETE
@ SMTP_REQUEST_COMPLETE
Definition: app-layer-smtp.h:77
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:547
AppLayerFrameGetLastOpenByType
Frame * AppLayerFrameGetLastOpenByType(Flow *f, const int dir, const uint8_t frame_type)
Definition: app-layer-frames.c:715
SMTPLine_
Definition: app-layer-smtp.c:119
SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY
#define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY
Definition: app-layer-smtp.c:79
Flow_::protoctx
void * protoctx
Definition: flow.h:434
AppLayerGetTxIterTuple::tx_ptr
void * tx_ptr
Definition: app-layer-parser.h:154
SMTP_REPLY_541
@ SMTP_REPLY_541
Definition: app-layer-smtp.c:312
SMTP_REPLY_251
@ SMTP_REPLY_251
Definition: app-layer-smtp.c:284
util-unittest.h
smtp_decoder_event_table
SCEnumCharMap smtp_decoder_event_table[]
Definition: app-layer-smtp.c:128
SMTPConfig::content_inspect_min_size
uint32_t content_inspect_min_size
Definition: app-layer-smtp.h:123
util-unittest-helper.h
SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE
@ SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE
Definition: app-layer-smtp.h:43
SMTP_REPLY_502
@ SMTP_REPLY_502
Definition: app-layer-smtp.c:302
SCAppLayerDecoderEventsSetEventRaw
void SCAppLayerDecoderEventsSetEventRaw(AppLayerDecoderEvents **sevents, uint8_t event)
Set an app layer decoder event.
Definition: app-layer-events.c:96
File_::sb
StreamingBuffer * sb
Definition: util-file.h:150
TcpSession_::flags
uint32_t flags
Definition: stream-tcp-private.h:294
SMTPConfig::raw_extraction
bool raw_extraction
Definition: app-layer-smtp.h:127
util-memcmp.h
SCAppLayerProtoDetectConfProtoDetectionEnabled
int SCAppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto)
Given a protocol name, checks if proto detection is enabled in the conf file.
Definition: app-layer-detect-proto.c:2002
SMTP_DECODER_EVENT_DUPLICATE_FIELDS
@ SMTP_DECODER_EVENT_DUPLICATE_FIELDS
Definition: app-layer-smtp.h:61
MpmInitCtx
void MpmInitCtx(MpmCtx *mpm_ctx, uint8_t matcher)
Definition: util-mpm.c:209
SMTPInput_::len
int32_t len
Definition: app-layer-smtp.c:110
AppLayerResult
Definition: app-layer-parser.h:114
SCAppLayerParserTriggerRawStreamInspection
void SCAppLayerParserTriggerRawStreamInspection(Flow *f, int direction)
Definition: app-layer-parser.c:1813
app-layer-detect-proto.h
StreamTcpInitConfig
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition: stream-tcp.c:498
FLOW_INITIALIZE
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:38
SMTP_REPLY_504
@ SMTP_REPLY_504
Definition: app-layer-smtp.c:304
SMTP_COMMAND_DATA_MODE
#define SMTP_COMMAND_DATA_MODE
Definition: app-layer-smtp.c:94
SMTP_COMMAND_STARTTLS
#define SMTP_COMMAND_STARTTLS
Definition: app-layer-smtp.c:87
APP_LAYER_INCOMPLETE
#define APP_LAYER_INCOMPLETE(c, n)
Definition: app-layer-parser.h:70
TAILQ_REMOVE
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:312
decode.h
MpmDestroyThreadCtx
void MpmDestroyThreadCtx(MpmThreadCtx *mpm_thread_ctx, const uint16_t matcher)
Definition: util-mpm.c:202
util-debug.h
SMTP_MPM
#define SMTP_MPM
Definition: app-layer-smtp.c:271
TAILQ_FIRST
#define TAILQ_FIRST(head)
Definition: queue.h:250
AppLayerParserState_
Definition: app-layer-parser.c:148
StreamSlice::offset
uint64_t offset
Definition: app-layer-parser.h:125
AppLayerTxData
Definition: app-layer-parser.h:166
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:22
SMTP_REPLY_235
@ SMTP_REPLY_235
Definition: app-layer-smtp.c:282
SMTP_REPLY_551
@ SMTP_REPLY_551
Definition: app-layer-smtp.c:315
AppLayerProtoDetectHasProbingParsers
bool AppLayerProtoDetectHasProbingParsers(uint8_t ipproto, uint16_t port, AppProto alproto)
Definition: app-layer-detect-proto.c:463
SCAppLayerParserConfParserEnabled
int SCAppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name)
check if a parser is enabled in the config Returns enabled always if: were running unittests
Definition: app-layer-parser.c:377
FileFlowToFlags
uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction)
Definition: util-file.c:272
DetectEngineThreadCtx_
Definition: detect.h:1306
SMTP_COMMAND_BDAT_LAST
#define SMTP_COMMAND_BDAT_LAST
Definition: app-layer-smtp.c:100
SC_FILENAME_MAX
#define SC_FILENAME_MAX
Definition: util-file.h:129
SMTPState_::state_data
AppLayerStateData state_data
Definition: app-layer-smtp.h:133
APP_LAYER_EVENT_TYPE_TRANSACTION
@ APP_LAYER_EVENT_TYPE_TRANSACTION
Definition: app-layer-events.h:55
SMTP_COMMAND_RSET
#define SMTP_COMMAND_RSET
Definition: app-layer-smtp.c:97
AppLayerEventType
AppLayerEventType
Definition: app-layer-events.h:54
SMTPState_::helo
uint8_t * helo
Definition: app-layer-smtp.h:169
SMTP_DEFAULT_MAX_TX
#define SMTP_DEFAULT_MAX_TX
Definition: app-layer-smtp.c:102
ALPROTO_SMTP
@ ALPROTO_SMTP
Definition: app-layer-protos.h:38
alp_tctx
AppLayerParserThreadCtx * alp_tctx
Definition: fuzz_applayerparserparse.c:24
SCMpmAddPatternCI
int SCMpmAddPatternCI(MpmCtx *mpm_ctx, const uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags)
Definition: util-mpm.c:258
AppLayerParserRegisterGetFrameFuncs
void AppLayerParserRegisterGetFrameFuncs(uint8_t ipproto, AppProto alproto, AppLayerParserGetFrameIdByNameFn GetIdByNameFunc, AppLayerParserGetFrameNameByIdFn GetNameByIdFunc)
Definition: app-layer-parser.c:653
SCEnter
#define SCEnter(...)
Definition: util-debug.h:284
SMTPTransaction_::tx_data
AppLayerTxData tx_data
Definition: app-layer-smtp.h:90
SMTPState_::parser_state
uint8_t parser_state
Definition: app-layer-smtp.h:145
FileContainer_::head
File * head
Definition: util-file.h:38
SMTP_REPLY_455
@ SMTP_REPLY_455
Definition: app-layer-smtp.c:298
SCConfGetNonNull
int SCConfGetNonNull(const char *name, const char **vptr)
Retrieve the non-null value of a configuration node.
Definition: conf.c:381
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
SMTP_DECODER_EVENT_MIME_INVALID_BASE64
@ SMTP_DECODER_EVENT_MIME_INVALID_BASE64
Definition: app-layer-smtp.h:51
SMTPTransaction_::mail_from
uint8_t * mail_from
Definition: app-layer-smtp.h:104
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:3626
SMTP_RESPONSE_DATA
@ SMTP_RESPONSE_DATA
Definition: app-layer-smtp.h:82
FileTrackedSize
uint64_t FileTrackedSize(const File *file)
get the size of the file
Definition: util-file.c:325
AppLayerParserRegisterStateFuncs
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void *, AppProto), void(*StateFree)(void *))
Definition: app-layer-parser.c:485
FILEDATA_CONTENT_INSPECT_MIN_SIZE
#define FILEDATA_CONTENT_INSPECT_MIN_SIZE
Definition: app-layer-smtp.c:61
SMTPState_::curr_tx
SMTPTransaction * curr_tx
Definition: app-layer-smtp.h:134
SMTP_COMMAND_BDAT
#define SMTP_COMMAND_BDAT
Definition: app-layer-smtp.c:89
SMTPState_::discard_till_lf_ts
bool discard_till_lf_ts
Definition: app-layer-smtp.h:141
SMTPInput_::consumed
int32_t consumed
Definition: app-layer-smtp.c:116
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:262
SMTP_REPLY_211
@ SMTP_REPLY_211
Definition: app-layer-smtp.c:278
SMTP_REPLY_220
@ SMTP_REPLY_220
Definition: app-layer-smtp.c:280
SMTPFrameTypes
SMTPFrameTypes
Definition: app-layer-smtp.c:159
app-layer-parser.h
Flow_::todstbytecnt
uint64_t todstbytecnt
Definition: flow.h:498
SMTPInput
struct SMTPInput_ SMTPInput
AppLayerParserRegisterGetEventInfo
void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, int(*StateGetEventInfo)(const char *event_name, uint8_t *event_id, AppLayerEventType *event_type))
Definition: app-layer-parser.c:663
smtp_config
SMTPConfig smtp_config
Definition: app-layer-smtp.c:370
SCReturn
#define SCReturn
Definition: util-debug.h:286
SMTP_RAW_EXTRACTION_DEFAULT_VALUE
#define SMTP_RAW_EXTRACTION_DEFAULT_VALUE
Definition: app-layer-smtp.c:66
AppLayerParserRegisterProtocolUnittests
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
Definition: app-layer-parser.c:2116
AppLayerGetTxIterState
Definition: app-layer-parser.h:142
SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG
@ SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG
Definition: app-layer-smtp.h:57
SMTP_REPLY_252
@ SMTP_REPLY_252
Definition: app-layer-smtp.c:285
Packet_
Definition: decode.h:516
SMTPTransaction_
Definition: app-layer-smtp.h:86
detect-engine-build.h
SCConfGetChildValueInt
int SCConfGetChildValueInt(const SCConfNode *base, const char *name, intmax_t *val)
Definition: conf.c:476
SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED
@ SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED
Definition: app-layer-smtp.h:45
SMTP_REPLY_250
@ SMTP_REPLY_250
Definition: app-layer-smtp.c:283
detect-engine-alert.h
conf.h
SMTP_REPLY_555
@ SMTP_REPLY_555
Definition: app-layer-smtp.c:319
StreamingBufferCompareRawData
int StreamingBufferCompareRawData(const StreamingBuffer *sb, const uint8_t *rawdata, uint32_t rawdata_len)
Definition: util-streaming-buffer.c:1850
Frame::len
int64_t len
Definition: app-layer-frames.h:50
FileOpenFileWithId
int FileOpenFileWithId(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, const uint8_t *name, uint16_t name_len, const uint8_t *data, uint32_t data_len, uint16_t flags)
Open a new File.
Definition: util-file.c:966
SMTPState_::current_command
uint8_t current_command
Definition: app-layer-smtp.h:147
File_::name
uint8_t * name
Definition: util-file.h:155
SMTP_PARSER_STATE_COMMAND_DATA_MODE
#define SMTP_PARSER_STATE_COMMAND_DATA_MODE
Definition: app-layer-smtp.c:75
AppLayerParserRegisterGetTxFilesFunc
void AppLayerParserRegisterGetTxFilesFunc(uint8_t ipproto, AppProto alproto, AppLayerGetFileState(*GetTxFiles)(void *, uint8_t))
Definition: app-layer-parser.c:508
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
SMTPTransaction_::files_ts
FileContainer files_ts
Definition: app-layer-smtp.h:109
AppLayerProtoDetectRegisterProtocol
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
Definition: app-layer-detect-proto.c:1782
AppLayerGetTxIterTuple
Definition: app-layer-parser.h:153
rawmsgname
#define rawmsgname
Definition: app-layer-smtp.c:1291
SMTP_COMMAND_BUFFER_STEPS
#define SMTP_COMMAND_BUFFER_STEPS
Definition: app-layer-smtp.c:68
SMTPTransaction_::mail_from_len
uint16_t mail_from_len
Definition: app-layer-smtp.h:105
FileAppendData
int FileAppendData(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data, uint32_t data_len)
Store/handle a chunk of file data in the File structure The last file in the FileContainer will be us...
Definition: util-file.c:765
MpmTableElmt_::Search
uint32_t(* Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t)
Definition: util-mpm.h:200
FILE_NOMD5
#define FILE_NOMD5
Definition: util-file.h:114
RunmodeIsUnittests
int RunmodeIsUnittests(void)
Definition: suricata.c:292
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:232
SMTP_REPLY_554
@ SMTP_REPLY_554
Definition: app-layer-smtp.c:318
SMTPConfig::max_tx
uint64_t max_tx
Definition: app-layer-smtp.h:125
SMTPStateAlloc
void * SMTPStateAlloc(void *orig_state, AppProto proto_orig)
Definition: app-layer-smtp.c:1742
AppLayerParserRegisterParser
int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, uint8_t direction, AppLayerParserFPtr Parser)
Register app layer parser for the protocol.
Definition: app-layer-parser.c:452
DETECT_ENGINE_STATE_FLAG_FILE_NEW
#define DETECT_ENGINE_STATE_FLAG_FILE_NEW
Definition: detect-engine-state.h:73
SMTPLine_::lf_found
bool lf_found
Definition: app-layer-smtp.c:125
FileDataSize
uint64_t FileDataSize(const File *file)
get the size of the file data
Definition: util-file.c:308
SMTP_REPLY_452
@ SMTP_REPLY_452
Definition: app-layer-smtp.c:296
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2300
SMTPThreadCtx_::smtp_mpm_thread_ctx
MpmThreadCtx * smtp_mpm_thread_ctx
Definition: app-layer-smtp.c:267
StatsThreadInit
void StatsThreadInit(StatsThreadContext *stats)
Definition: counters.c:1333
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
SCAppLayerProtoDetectPPRegister
void SCAppLayerProtoDetectPPRegister(uint8_t ipproto, const char *portstr, AppProto alproto, uint16_t min_depth, uint16_t max_depth, uint8_t direction, ProbingParserFPtr ProbingParser1, ProbingParserFPtr ProbingParser2)
register parser at a port
Definition: app-layer-detect-proto.c:1541
SMTP_FRAME_COMMAND_LINE
@ SMTP_FRAME_COMMAND_LINE
Definition: app-layer-smtp.c:160
AppLayerParserThreadCtxAlloc
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
Definition: app-layer-parser.c:329
SMTP_COMMAND_OTHER_CMD
#define SMTP_COMMAND_OTHER_CMD
Definition: app-layer-smtp.c:96
AppLayerParserRegisterGetTx
void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id))
Definition: app-layer-parser.c:566
SMTPString_::len
uint16_t len
Definition: app-layer-smtp.h:69
SMTP_REPLY_435
@ SMTP_REPLY_435
Definition: app-layer-smtp.c:293
SMTPState_::helo_len
uint16_t helo_len
Definition: app-layer-smtp.h:168
util-mem.h
SCConfNodeLookupChild
SCConfNode * SCConfNodeLookupChild(const SCConfNode *node, const char *name)
Lookup a child configuration node by name.
Definition: conf.c:850
File_::content_inspected
uint64_t content_inspected
Definition: util-file.h:166
SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE
@ SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE
Definition: app-layer-smtp.h:40
SMTPState_::toserver_data_count
uint64_t toserver_data_count
Definition: app-layer-smtp.h:137
File_
Definition: util-file.h:146
APP_LAYER_OK
#define APP_LAYER_OK
Definition: app-layer-parser.h:58
cnt
uint32_t cnt
Definition: tmqh-packetpool.h:7
app-layer-frames.h
SCMapEnumValueToName
const char * SCMapEnumValueToName(int enum_value, SCEnumCharMap *table)
Maps an enum value to a string name, from the supplied table.
Definition: util-enum.c:68
Packet_::flow
struct Flow_ * flow
Definition: decode.h:564
SMTPTransaction_::is_data
bool is_data
Definition: app-layer-smtp.h:99
SCReturnStruct
#define SCReturnStruct(x)
Definition: util-debug.h:304
SMTPState_::cmds
uint8_t * cmds
Definition: app-layer-smtp.h:156
SCConfGetChildValue
int SCConfGetChildValue(const SCConfNode *base, const char *name, const char **vptr)
Definition: conf.c:390
SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE
@ SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE
Definition: app-layer-smtp.h:54
SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST
@ SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST
Definition: app-layer-smtp.h:37
util-mpm.h
StreamTcpFreeConfig
void StreamTcpFreeConfig(bool quiet)
Definition: stream-tcp.c:866
SCMapEnumNameToValue
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:40
flags
uint8_t flags
Definition: decode-gre.h:0
SMTP_REQUEST_DATA
@ SMTP_REQUEST_DATA
Definition: app-layer-smtp.h:76
AppLayerParserParse
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
Definition: app-layer-parser.c:1554
AppLayerGetFileState
Definition: util-file.h:44
SMTPInput_::orig_len
int32_t orig_len
Definition: app-layer-smtp.c:113
suricata-common.h
SMTPTransaction_::tx_id
uint64_t tx_id
Definition: app-layer-smtp.h:88
smtp_frame_table
SCEnumCharMap smtp_frame_table[]
Definition: app-layer-smtp.c:165
AppLayerGetFileState::fc
FileContainer * fc
Definition: util-file.h:45
SMTP_DECODER_EVENT_UNPARSABLE_CONTENT
@ SMTP_DECODER_EVENT_UNPARSABLE_CONTENT
Definition: app-layer-smtp.h:62
AppLayerTxData::updated_tc
bool updated_tc
Definition: app-layer-parser.h:173
SMTP_REPLY_214
@ SMTP_REPLY_214
Definition: app-layer-smtp.c:279
SCEnumCharMap_
Definition: util-enum.h:27
SMTPState_::bdat_chunk_len
uint32_t bdat_chunk_len
Definition: app-layer-smtp.h:149
SMTP_DECODER_EVENT_MIME_LONG_FILENAME
@ SMTP_DECODER_EVENT_MIME_LONG_FILENAME
Definition: app-layer-smtp.h:58
TAILQ_NEXT
#define TAILQ_NEXT(elm, field)
Definition: queue.h:307
AppLayerTxData::files_opened
uint32_t files_opened
track file open/logs so we can know how long to keep the tx
Definition: app-layer-parser.h:182
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Definition: detect-engine.c:3871
SCAppLayerProtoDetectPMRegisterPatternCIwPP
int SCAppLayerProtoDetectPMRegisterPatternCIwPP(uint8_t ipproto, AppProto alproto, const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction, ProbingParserFPtr PPFunc, uint16_t pp_min_depth, uint16_t pp_max_depth)
Definition: app-layer-detect-proto.c:1663
SMTP_COMMAND_QUIT
#define SMTP_COMMAND_QUIT
Definition: app-layer-smtp.c:98
SMTP_PARSER_STATE_PIPELINING_SERVER
#define SMTP_PARSER_STATE_PIPELINING_SERVER
Definition: app-layer-smtp.c:81
AppLayerParserRegisterStateDataFunc
void AppLayerParserRegisterStateDataFunc(uint8_t ipproto, AppProto alproto, AppLayerStateData *(*GetStateData)(void *state))
Definition: app-layer-parser.c:684
FileSetInspectSizes
void FileSetInspectSizes(File *file, const uint32_t win, const uint32_t min)
Definition: util-file.c:842
SMTPString_
Definition: app-layer-smtp.h:67
SCStrdup
#define SCStrdup(s)
Definition: util-mem.h:56
FatalError
#define FatalError(...)
Definition: util-debug.h:517
AppLayerParserRegisterTxDataFunc
void AppLayerParserRegisterTxDataFunc(uint8_t ipproto, AppProto alproto, AppLayerTxData *(*GetTxData)(void *tx))
Definition: app-layer-parser.c:674
AppLayerFrameNewByPointer
Frame * AppLayerFrameNewByPointer(Flow *f, const StreamSlice *stream_slice, const uint8_t *frame_start, const int64_t len, int dir, uint8_t frame_type)
create new frame using a pointer to start of the frame
Definition: app-layer-frames.c:465
SMTP_NO_TX_ID
#define SMTP_NO_TX_ID
Definition: app-layer-smtp.c:105
SCAppLayerRequestProtocolTLSUpgrade
bool SCAppLayerRequestProtocolTLSUpgrade(Flow *f)
request applayer to wrap up this protocol and rerun protocol detection with expectation of TLS....
Definition: app-layer-detect-proto.c:1873
ParseSizeStringU32
int ParseSizeStringU32(const char *size, uint32_t *res)
Definition: util-misc.c:174
app-layer-events.h
util-validate.h
FileContainerRecycle
void FileContainerRecycle(FileContainer *ffc, const StreamingBufferConfig *cfg)
Recycle a FileContainer.
Definition: util-file.c:495
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SMTP_DECODER_EVENT_MIME_INVALID_QP
@ SMTP_DECODER_EVENT_MIME_INVALID_QP
Definition: app-layer-smtp.h:52
SMTPState_::cmds_tx_ids
uint64_t * cmds_tx_ids
Definition: app-layer-smtp.h:158
str
#define str(s)
Definition: suricata-common.h:316
AppLayerParserRegisterGetTxIterator
void AppLayerParserRegisterGetTxIterator(uint8_t ipproto, AppProto alproto, AppLayerGetTxIteratorFunc Func)
Definition: app-layer-parser.c:576
SCConfGetNode
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition: conf.c:184
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:274
SMTP_RESPONSE_COMPLETE
@ SMTP_RESPONSE_COMPLETE
Definition: app-layer-smtp.h:83
MpmTableElmt_::Prepare
int(* Prepare)(MpmConfig *, struct MpmCtx_ *)
Definition: util-mpm.h:193
SMTP_REPLY_402
@ SMTP_REPLY_402
Definition: app-layer-smtp.c:291
MpmTableElmt_::DestroyCtx
void(* DestroyCtx)(struct MpmCtx_ *)
Definition: util-mpm.h:172
AppLayerResult::status
int32_t status
Definition: app-layer-parser.h:115
FileCloseFile
int FileCloseFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data, uint32_t data_len, uint16_t flags)
Close a File.
Definition: util-file.c:1050
SCFree
#define SCFree(p)
Definition: util-mem.h:61
SMTPLine_::delim_len
uint8_t delim_len
Definition: app-layer-smtp.c:124
Flow_::alproto_ts
AppProto alproto_ts
Definition: flow.h:452
SMTP_REPLY_221
@ SMTP_REPLY_221
Definition: app-layer-smtp.c:281
Flow_::alstate
void * alstate
Definition: flow.h:480
SMTPInput_
Definition: app-layer-smtp.c:107
SCAppLayerProtoDetectPPParseConfPorts
int SCAppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, uint8_t ipproto, const char *alproto_name, AppProto alproto, uint16_t min_depth, uint16_t max_depth, ProbingParserFPtr ProbingParserTs, ProbingParserFPtr ProbingParserTc)
Definition: app-layer-detect-proto.c:1577
SMTP_REPLY_530
@ SMTP_REPLY_530
Definition: app-layer-smtp.c:309
smtp_reply_map
SCEnumCharMap smtp_reply_map[]
Definition: app-layer-smtp.c:322
detect-parse.h
FILEDATA_CONTENT_INSPECT_WINDOW
#define FILEDATA_CONTENT_INSPECT_WINDOW
Definition: app-layer-smtp.c:63
Signature_
Signature container.
Definition: detect.h:688
SMTP_LINE_BUFFER_LIMIT
#define SMTP_LINE_BUFFER_LIMIT
Definition: app-layer-smtp.h:33
SMTP_REPLY_450
@ SMTP_REPLY_450
Definition: app-layer-smtp.c:294
MpmInitThreadCtx
void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, MpmCtx *mpm_ctx, uint16_t matcher)
Definition: util-mpm.c:195
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
ALPROTO_FAILED
@ ALPROTO_FAILED
Definition: app-layer-protos.h:33
FLOW_PKT_ESTABLISHED
#define FLOW_PKT_ESTABLISHED
Definition: flow.h:234
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2839
SMTP_REPLY_451
@ SMTP_REPLY_451
Definition: app-layer-smtp.c:295
SMTP_REPLY_511
@ SMTP_REPLY_511
Definition: app-layer-smtp.c:305
RegisterSMTPParsers
void RegisterSMTPParsers(void)
Register the SMTP Protocol parser.
Definition: app-layer-smtp.c:2129
SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME
@ SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME
Definition: app-layer-smtp.h:55
mpm_table
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition: util-mpm.c:47
app-layer-protos.h
SMTP_REPLY_543
@ SMTP_REPLY_543
Definition: app-layer-smtp.c:313
STREAMTCP_FLAG_APP_LAYER_DISABLED
#define STREAMTCP_FLAG_APP_LAYER_DISABLED
Definition: stream-tcp-private.h:201
STREAMTCP_STREAM_FLAG_NOREASSEMBLY
#define STREAMTCP_STREAM_FLAG_NOREASSEMBLY
Definition: stream-tcp-private.h:219
suricata.h
AppLayerParserRegisterGetTxCnt
void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t(*StateGetTxCnt)(void *alstate))
Definition: app-layer-parser.c:556
APP_LAYER_ERROR
#define APP_LAYER_ERROR
Definition: app-layer-parser.h:62
SMTPConfig::sbcfg
StreamingBufferConfig sbcfg
Definition: app-layer-smtp.h:129
PmqFree
void PmqFree(PrefilterRuleStore *pmq)
Cleanup and free a Pmq.
Definition: util-prefilter.c:126
SMTP_REPLY_501
@ SMTP_REPLY_501
Definition: app-layer-smtp.c:301
SMTP_DECODER_EVENT_MIME_PARSE_FAILED
@ SMTP_DECODER_EVENT_MIME_PARSE_FAILED
Definition: app-layer-smtp.h:49
FILE_USE_DETECT
#define FILE_USE_DETECT
Definition: util-file.h:125
AppLayerTxData::events
AppLayerDecoderEvents * events
Definition: app-layer-parser.h:218
SMTPLine_::len
int32_t len
Definition: app-layer-smtp.c:123
SMTP_DECODER_EVENT_TRUNCATED_LINE
@ SMTP_DECODER_EVENT_TRUNCATED_LINE
Definition: app-layer-smtp.h:64
AppLayerParserRegisterGetEventInfoById
void AppLayerParserRegisterGetEventInfoById(uint8_t ipproto, AppProto alproto, int(*StateGetEventInfoById)(uint8_t event_id, const char **event_name, AppLayerEventType *event_type))
Definition: app-layer-parser.c:599
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:989
SMTPString_::str
uint8_t * str
Definition: app-layer-smtp.h:68
SMTPState_::file_track_id
uint32_t file_track_id
Definition: app-layer-smtp.h:173
AppLayerParserThreadCtx_
Definition: app-layer-parser.c:60
app-layer-smtp.h
SMTP_REQUEST_STARTED
@ SMTP_REQUEST_STARTED
Definition: app-layer-smtp.h:75
SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED
@ SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED
Definition: app-layer-smtp.h:41
FlowChangeProto
int FlowChangeProto(Flow *f)
Check if change proto flag is set for flow.
Definition: flow.c:196
MpmCtx_
Definition: util-mpm.h:111
TcpSession_
Definition: stream-tcp-private.h:283
SMTPState_::cmds_buffer_len
uint16_t cmds_buffer_len
Definition: app-layer-smtp.h:160
SMTPParserRegisterTests
void SMTPParserRegisterTests(void)
Definition: app-layer-smtp.c:4513
util-misc.h
SCEnumCharMap_::enum_name
const char * enum_name
Definition: util-enum.h:28
SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE
@ SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE
Definition: app-layer-smtp.h:56
FILE_NOMAGIC
#define FILE_NOMAGIC
Definition: util-file.h:113
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:451
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SMTP_DECODER_EVENT_INVALID_REPLY
@ SMTP_DECODER_EVENT_INVALID_REPLY
Definition: app-layer-smtp.h:36
util-enum.h
ThreadVars_::stats
StatsThreadContext stats
Definition: threadvars.h:121
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:288
SCConfNode_
Definition: conf.h:37
StatsThreadCleanup
void StatsThreadCleanup(StatsThreadContext *stats)
Definition: counters.c:1429
SCConfNode_::val
char * val
Definition: conf.h:39
SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE
@ SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE
Definition: app-layer-smtp.h:46
SMTPParserCleanup
void SMTPParserCleanup(void)
Free memory allocated for global SMTP parser state.
Definition: app-layer-smtp.c:2187
SMTPConfig::content_inspect_window
uint32_t content_inspect_window
Definition: app-layer-smtp.h:124
SMTPThreadCtx_::pmq
PrefilterRuleStore * pmq
Definition: app-layer-smtp.c:268
SMTP_REPLY_354
@ SMTP_REPLY_354
Definition: app-layer-smtp.c:288
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:109
SMTP_DECODER_EVENT_INVALID_BDAT
@ SMTP_DECODER_EVENT_INVALID_BDAT
Definition: app-layer-smtp.h:42
FLOW_DESTROY
#define FLOW_DESTROY(f)
Definition: flow-util.h:119
SCAppLayerGetEventIdByName
int SCAppLayerGetEventIdByName(const char *event_name, SCEnumCharMap *table, uint8_t *event_id)
Definition: app-layer-events.c:30
PmqSetup
int PmqSetup(PrefilterRuleStore *pmq)
Setup a pmq.
Definition: util-prefilter.c:37
AppLayerStateData::file_flags
uint16_t file_flags
Definition: app-layer-parser.h:150
PKT_STREAM_EST
#define PKT_STREAM_EST
Definition: decode.h:1307
AppLayerGetTxIterState::un
union AppLayerGetTxIterState::@7 un
AppLayerTxData::file_tx
uint8_t file_tx
Definition: app-layer-parser.h:193
AppLayerTxData::updated_ts
bool updated_ts
Definition: app-layer-parser.h:174
app-layer.h
PrefilterRuleStore_::rule_id_array
SigIntId * rule_id_array
Definition: util-prefilter.h:38
SMTPTransaction_::mime_state
MimeStateSMTP * mime_state
Definition: app-layer-smtp.h:101
UTHFreePackets
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself.
Definition: util-unittest-helper.c:455