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