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-helper.h"
38 #include "util-memcmp.h"
39 
40 #include "detect-engine-state.h"
41 
42 #include "conf.h"
43 
44 #include "util-misc.h"
45 #include "util-validate.h"
46 #include "detect.h"
47 #include "flow.h"
48 #include "rust.h"
49 #include "stream-tcp-reassemble.h"
50 #include "util-prefilter.h"
51 
52 /* content-limit default value */
53 #define FILEDATA_CONTENT_LIMIT 100000
54 /* content-inspect-min-size default value */
55 #define FILEDATA_CONTENT_INSPECT_MIN_SIZE 32768
56 /* content-inspect-window default value */
57 #define FILEDATA_CONTENT_INSPECT_WINDOW 4096
58 
59 /* raw extraction default value */
60 #define SMTP_RAW_EXTRACTION_DEFAULT_VALUE false
61 
62 #define SMTP_COMMAND_BUFFER_STEPS 5
63 
64 /* we are in process of parsing a fresh command. Just a placeholder. If we
65  * are not in STATE_COMMAND_DATA_MODE, we have to be in this mode */
66 // unused #define SMTP_PARSER_STATE_COMMAND_MODE 0x00
67 /* we are in mode of parsing a command's data. Used when we are parsing tls
68  * or accepting the rfc 2822 mail after DATA command */
69 #define SMTP_PARSER_STATE_COMMAND_DATA_MODE 0x01
70 /* Used to indicate that the parser has seen the first reply */
71 #define SMTP_PARSER_STATE_FIRST_REPLY_SEEN 0x04
72 /* Used to indicate that the parser is parsing a multiline reply */
73 #define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY 0x08
74 /* Used to indicate that the server supports pipelining */
75 #define SMTP_PARSER_STATE_PIPELINING_SERVER 0x10
76 
77 /* Various SMTP commands
78  * We currently have var-ified just STARTTLS and DATA, since we need to them
79  * for state transitions. The rest are just indicate as OTHER_CMD. Other
80  * commands would be introduced as and when needed */
81 #define SMTP_COMMAND_STARTTLS 1
82 #define SMTP_COMMAND_DATA 2
83 #define SMTP_COMMAND_BDAT 3
84 /* not an actual command per se, but the mode where we accept the mail after
85  * DATA has it's own reply code for completion, from the server. We give this
86  * stage a pseudo command of it's own, so that we can add this to the command
87  * buffer to match with the reply */
88 #define SMTP_COMMAND_DATA_MODE 4
89 /* All other commands are represented by this var */
90 #define SMTP_COMMAND_OTHER_CMD 5
91 #define SMTP_COMMAND_RSET 6
92 #define SMTP_COMMAND_QUIT 7
93 /* Pseudo command used to match the final BDAT reply to its transaction. */
94 #define SMTP_COMMAND_BDAT_LAST 8
95 
96 #define SMTP_DEFAULT_MAX_TX 256
97 
98 /* command buffer tx id for commands with no owning transaction */
99 #define SMTP_NO_TX_ID UINT64_MAX
100 
101 typedef struct SMTPInput_ {
102  /* current input that is being parsed */
103  const uint8_t *buf;
104  int32_t len;
105 
106  /* original length of an input */
107  int32_t orig_len;
108 
109  /* Consumed bytes till current line */
110  int32_t consumed;
112 
113 typedef struct SMTPLine_ {
114  /** current line extracted by the parser from the call to SMTPGetline() */
115  const uint8_t *buf;
116  /** length of the line in current_line. Doesn't include the delimiter */
117  int32_t len;
118  uint8_t delim_len;
119  bool lf_found;
121 
123  { "INVALID_REPLY", SMTP_DECODER_EVENT_INVALID_REPLY },
124  { "UNABLE_TO_MATCH_REPLY_WITH_REQUEST", SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST },
125  { "MAX_COMMAND_LINE_LEN_EXCEEDED", SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED },
126  { "MAX_REPLY_LINE_LEN_EXCEEDED", SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED },
127  { "INVALID_PIPELINED_SEQUENCE", SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE },
128  { "BDAT_CHUNK_LEN_EXCEEDED", SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED },
129  { "INVALID_BDAT", SMTP_DECODER_EVENT_INVALID_BDAT },
130  { "NO_SERVER_WELCOME_MESSAGE", SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE },
131  { "TLS_REJECTED", SMTP_DECODER_EVENT_TLS_REJECTED },
132  { "DATA_COMMAND_REJECTED", SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED },
133  { "FAILED_PROTOCOL_CHANGE", SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE },
134 
135  /* MIME Events */
136  { "MIME_PARSE_FAILED", SMTP_DECODER_EVENT_MIME_PARSE_FAILED },
137  { "MIME_INVALID_BASE64", SMTP_DECODER_EVENT_MIME_INVALID_BASE64 },
138  { "MIME_INVALID_QP", SMTP_DECODER_EVENT_MIME_INVALID_QP },
139  { "MIME_LONG_LINE", SMTP_DECODER_EVENT_MIME_LONG_LINE },
140  { "MIME_LONG_ENC_LINE", SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE },
141  { "MIME_LONG_HEADER_NAME", SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME },
142  { "MIME_LONG_HEADER_VALUE", SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE },
143  { "MIME_LONG_BOUNDARY", SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG },
144  { "MIME_LONG_FILENAME", SMTP_DECODER_EVENT_MIME_LONG_FILENAME },
145 
146  /* Invalid behavior or content */
147  { "DUPLICATE_FIELDS", SMTP_DECODER_EVENT_DUPLICATE_FIELDS },
148  { "UNPARSABLE_CONTENT", SMTP_DECODER_EVENT_UNPARSABLE_CONTENT },
149  { "TRUNCATED_LINE", SMTP_DECODER_EVENT_TRUNCATED_LINE },
150  { NULL, -1 },
151 };
152 
157 };
158 
160  {
161  "command_line",
163  },
164  {
165  "data",
167  },
168  {
169  "response_line",
171  },
172  { NULL, -1 },
173 };
174 
175 static int SMTPGetFrameIdByName(const char *frame_name)
176 {
177  int id = SCMapEnumNameToValue(frame_name, smtp_frame_table);
178  if (id < 0) {
179  return -1;
180  }
181  return id;
182 }
183 
184 static const char *SMTPGetFrameNameById(const uint8_t frame_id)
185 {
186  const char *name = SCMapEnumValueToName(frame_id, smtp_frame_table);
187  return name;
188 }
189 
190 static SCEnumCharMap smtp_state_client_table[] = {
191  { "request_started", SMTP_REQUEST_STARTED },
192  { "request_data", SMTP_REQUEST_DATA },
193  { "request_complete", SMTP_REQUEST_COMPLETE },
194  { NULL, -1 },
195 };
196 
197 static SCEnumCharMap smtp_state_server_table[] = {
198  { "response_started", SMTP_RESPONSE_STARTED },
199  { "response_data", SMTP_RESPONSE_DATA },
200  { "response_complete", SMTP_RESPONSE_COMPLETE },
201  { NULL, -1 },
202 };
203 
204 static int SMTPStateGetStateIdByName(const char *name, const uint8_t direction)
205 {
206  SCEnumCharMap *map =
207  direction == STREAM_TOSERVER ? smtp_state_client_table : smtp_state_server_table;
208  int id = SCMapEnumNameToValue(name, map);
209  if (id < 0) {
210  return -1;
211  }
212  return id;
213 }
214 
215 static const char *SMTPStateGetStateNameById(const int id, const uint8_t direction)
216 {
217  SCEnumCharMap *map =
218  direction == STREAM_TOSERVER ? smtp_state_client_table : smtp_state_server_table;
219  return SCMapEnumValueToName(id, map);
220 }
221 
222 static inline void SMTPSetProgressTS(SMTPTransaction *tx, uint8_t progress)
223 {
224  if (tx != NULL && tx->progress_ts < progress) {
225  tx->progress_ts = progress;
226  }
227 }
228 
229 static inline void SMTPSetProgressTC(SMTPTransaction *tx, uint8_t progress)
230 {
231  if (tx != NULL && tx->progress_tc < progress) {
232  tx->progress_tc = progress;
233  tx->tx_data.updated_tc = true;
234  }
235 }
236 
237 static inline void SMTPTransactionCompleteTS(SMTPTransaction *tx)
238 {
239  DEBUG_VALIDATE_BUG_ON(tx == NULL);
240  if (tx) {
241  SMTPSetProgressTS(tx, SMTP_REQUEST_COMPLETE);
242  SCLogDebug("marked tx as ts complete");
243  }
244 }
245 
246 static inline void SMTPTransactionCompleteTC(SMTPTransaction *tx)
247 {
248  DEBUG_VALIDATE_BUG_ON(tx == NULL);
249  if (tx) {
250  SMTPSetProgressTC(tx, SMTP_RESPONSE_COMPLETE);
251  SCLogDebug("marked tx as tc complete");
252  }
253 }
254 
255 static bool SMTPTransactionRequestIsComplete(const SMTPTransaction *tx)
256 {
257  return tx && tx->progress_ts == SMTP_REQUEST_COMPLETE;
258 }
259 
260 typedef struct SMTPThreadCtx_ {
264 
265 #define SMTP_MPM mpm_default_matcher
266 
267 static MpmCtx *smtp_mpm_ctx = NULL;
268 
269 /* smtp reply codes. If an entry is made here, please make a simultaneous
270  * entry in smtp_reply_map */
271 enum SMTPCode {
280 
283 
284  SMTP_REPLY_401, // Unauthorized
285  SMTP_REPLY_402, // Command not implemented
287  SMTP_REPLY_435, // Your account has not yet been verified
291  SMTP_REPLY_454, // Temporary authentication failure
293 
299  SMTP_REPLY_511, // Bad email address
300  SMTP_REPLY_521, // Server does not accept mail
301  SMTP_REPLY_522, // Recipient has exceeded mailbox limit
302  SMTP_REPLY_525, // User Account Disabled
303  SMTP_REPLY_530, // Authentication required
304  SMTP_REPLY_534, // Authentication mechanism is too weak
305  SMTP_REPLY_535, // Authentication credentials invalid
306  SMTP_REPLY_541, // No response from host
307  SMTP_REPLY_543, // Routing server failure. No available route
314 };
315 
317  { "211", SMTP_REPLY_211 },
318  { "214", SMTP_REPLY_214 },
319  { "220", SMTP_REPLY_220 },
320  { "221", SMTP_REPLY_221 },
321  { "235", SMTP_REPLY_235 },
322  { "250", SMTP_REPLY_250 },
323  { "251", SMTP_REPLY_251 },
324  { "252", SMTP_REPLY_252 },
325 
326  { "334", SMTP_REPLY_334 },
327  { "354", SMTP_REPLY_354 },
328 
329  { "401", SMTP_REPLY_401 },
330  { "402", SMTP_REPLY_402 },
331  { "421", SMTP_REPLY_421 },
332  { "435", SMTP_REPLY_435 },
333  { "450", SMTP_REPLY_450 },
334  { "451", SMTP_REPLY_451 },
335  { "452", SMTP_REPLY_452 },
336  { "454", SMTP_REPLY_454 },
337  // { "4.7.0", SMTP_REPLY_454 }, // rfc4954
338  { "455", SMTP_REPLY_455 },
339 
340  { "500", SMTP_REPLY_500 },
341  { "501", SMTP_REPLY_501 },
342  { "502", SMTP_REPLY_502 },
343  { "503", SMTP_REPLY_503 },
344  { "504", SMTP_REPLY_504 },
345  { "511", SMTP_REPLY_511 },
346  { "521", SMTP_REPLY_521 },
347  { "522", SMTP_REPLY_522 },
348  { "525", SMTP_REPLY_525 },
349  { "530", SMTP_REPLY_530 },
350  { "534", SMTP_REPLY_534 },
351  { "535", SMTP_REPLY_535 },
352  { "541", SMTP_REPLY_541 },
353  { "543", SMTP_REPLY_543 },
354  { "550", SMTP_REPLY_550 },
355  { "551", SMTP_REPLY_551 },
356  { "552", SMTP_REPLY_552 },
357  { "553", SMTP_REPLY_553 },
358  { "554", SMTP_REPLY_554 },
359  { "555", SMTP_REPLY_555 },
360  { NULL, -1 },
361 };
362 
363 /* Create SMTP config structure */
365  .decode_mime = true,
366  .content_limit = FILEDATA_CONTENT_LIMIT,
367  .content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE,
368  .content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW,
369  .raw_extraction = SMTP_RAW_EXTRACTION_DEFAULT_VALUE,
371 };
372 
373 static SMTPString *SMTPStringAlloc(void);
374 
375 #define SCHEME_SUFFIX_LEN 3
376 
377 /**
378  * \brief Configure SMTP Mime Decoder by parsing out mime section of YAML
379  * config file
380  *
381  * \return none
382  */
383 static void SMTPConfigure(void) {
384 
385  SCEnter();
386  intmax_t imval;
387  uint32_t content_limit = 0;
388  uint32_t content_inspect_min_size = 0;
389  uint32_t content_inspect_window = 0;
390 
391  SCConfNode *config = SCConfGetNode("app-layer.protocols.smtp.mime");
392  if (config != NULL) {
393  SCConfNode *extract_urls_schemes = NULL;
394 
395  int val;
396  int ret = SCConfGetChildValueBool(config, "decode-mime", &val);
397  if (ret) {
398  smtp_config.decode_mime = val;
399  }
400 
401  ret = SCConfGetChildValueBool(config, "decode-base64", &val);
402  if (ret) {
403  SCMimeSmtpConfigDecodeBase64(val);
404  }
405 
406  ret = SCConfGetChildValueBool(config, "decode-quoted-printable", &val);
407  if (ret) {
408  SCMimeSmtpConfigDecodeQuoted(val);
409  }
410 
411  ret = SCConfGetChildValueInt(config, "header-value-depth", &imval);
412  if (ret) {
413  if (imval < 0 || imval > UINT32_MAX) {
414  FatalError("Invalid value for header-value-depth");
415  }
416  SCMimeSmtpConfigHeaderValueDepth((uint32_t)imval);
417  }
418 
419  ret = SCConfGetChildValueBool(config, "extract-urls", &val);
420  if (ret) {
421  SCMimeSmtpConfigExtractUrls(val);
422  }
423 
424  /* Parse extract-urls-schemes from mime config, add '://' suffix to found schemes,
425  * and provide a default value of 'http' for the schemes to be extracted
426  * if no schemes are found in the config */
427  extract_urls_schemes = SCConfNodeLookupChild(config, "extract-urls-schemes");
428  if (extract_urls_schemes) {
429  SCConfNode *scheme = NULL;
430 
431  TAILQ_FOREACH (scheme, &extract_urls_schemes->head, next) {
432  size_t scheme_len = strlen(scheme->val);
433  if (scheme_len > UINT8_MAX - SCHEME_SUFFIX_LEN) {
434  FatalError("extract-urls-schemes entry '%s' is too long", scheme->val);
435  }
436  if (scheme->val[scheme_len - 1] != '/') {
437  scheme_len += SCHEME_SUFFIX_LEN;
438  char tmp[256];
439  int r = snprintf(tmp, sizeof(tmp), "%s://", scheme->val);
440  if (r != (int)scheme_len) {
441  FatalError("snprintf failure for SMTP url extraction scheme.");
442  }
443  char *new_val = SCStrdup(tmp);
444  if (unlikely(new_val == NULL)) {
445  FatalError("extract-urls-schemes entry SCStrdup failure.");
446  }
447  SCFree(scheme->val);
448  scheme->val = new_val;
449  }
450  int r = SCMimeSmtpConfigExtractUrlsSchemeAdd(scheme->val);
451  if (r < 0) {
452  FatalError("Failed to add smtp extract url scheme");
453  }
454  }
455  } else {
456  /* Add default extract url scheme 'http' since
457  * extract-urls-schemes wasn't found in the config */
458  SCMimeSmtpConfigExtractUrlsSchemeAdd("http://");
459  }
460 
461  ret = SCConfGetChildValueBool(config, "log-url-scheme", &val);
462  if (ret) {
463  SCMimeSmtpConfigLogUrlScheme(val);
464  }
465 
466  // default (if value is absent) is auto : do not set anything
467  const char *strval;
468  if (SCConfGetChildValue(config, "body-md5", &strval) == 1) {
469  if (SCConfValIsFalse(strval)) {
470  SCMimeSmtpConfigBodyMd5(false);
471  } else if (SCConfValIsTrue(strval)) {
472  SCMimeSmtpConfigBodyMd5(true);
473  } else if (strcmp(strval, "auto") != 0) {
474  SCLogWarning("Unknown value for body-md5: %s", strval);
475  }
476  }
477  }
478 
479  SCConfNode *t = SCConfGetNode("app-layer.protocols.smtp.inspected-tracker");
480  SCConfNode *p = NULL;
481 
482  if (t != NULL) {
483  TAILQ_FOREACH(p, &t->head, next) {
484  if (strcasecmp("content-limit", p->name) == 0) {
485  if (ParseSizeStringU32(p->val, &content_limit) < 0) {
486  SCLogWarning("parsing content-limit %s failed", p->val);
487  content_limit = FILEDATA_CONTENT_LIMIT;
488  }
489  smtp_config.content_limit = content_limit;
490  }
491 
492  if (strcasecmp("content-inspect-min-size", p->name) == 0) {
493  if (ParseSizeStringU32(p->val, &content_inspect_min_size) < 0) {
494  SCLogWarning("parsing content-inspect-min-size %s failed", p->val);
495  content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE;
496  }
497  smtp_config.content_inspect_min_size = content_inspect_min_size;
498  }
499 
500  if (strcasecmp("content-inspect-window", p->name) == 0) {
501  if (ParseSizeStringU32(p->val, &content_inspect_window) < 0) {
502  SCLogWarning("parsing content-inspect-window %s failed", p->val);
503  content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW;
504  }
505  smtp_config.content_inspect_window = content_inspect_window;
506  }
507  }
508  }
509 
510  smtp_config.sbcfg.buf_size = content_limit ? content_limit : 256;
511 
512  if (SCConfGetBool("app-layer.protocols.smtp.raw-extraction",
513  (int *)&smtp_config.raw_extraction) != 1) {
515  }
517  SCLogError("\"decode-mime\" and \"raw-extraction\" "
518  "options can't be enabled at the same time, "
519  "disabling raw extraction");
521  }
522 
523  uint64_t value = SMTP_DEFAULT_MAX_TX;
525  const char *str = NULL;
526  if (SCConfGetNonNull("app-layer.protocols.smtp.max-tx", &str) == 1) {
527  if (ParseSizeStringU64(str, &value) < 0) {
528  SCLogWarning("max-tx value cannot be deduced: %s,"
529  " keeping default",
530  str);
531  }
532  smtp_config.max_tx = value;
533  }
534 
535  SCReturn;
536 }
537 
538 static void SMTPSetEvent(SMTPState *s, uint8_t e)
539 {
540  SCLogDebug("setting event %u", e);
541 
542  if (s->curr_tx != NULL) {
544  // s->events++;
545  return;
546  }
547  SCLogDebug("couldn't set event %u", e);
548 }
549 
550 static SMTPTransaction *SMTPTransactionCreate(SMTPState *state)
551 {
552  if (state->nb_live_tx >= smtp_config.max_tx) {
553  return NULL;
554  }
555  SMTPTransaction *tx = SCCalloc(1, sizeof(*tx));
556  if (tx == NULL) {
557  return NULL;
558  }
559 
560  TAILQ_INIT(&tx->rcpt_to_list);
561  tx->tx_data.file_tx = STREAM_TOSERVER; // can xfer files
562  return tx;
563 }
564 
565 static SMTPTransaction *SMTPStateGetTxById(SMTPState *state, uint64_t tx_id)
566 {
567  SMTPTransaction *tx = NULL;
568  TAILQ_FOREACH (tx, &state->tx_list, next) {
569  if (tx->tx_id == tx_id) {
570  return tx;
571  }
572  if (tx->tx_id > tx_id) {
573  break;
574  }
575  }
576  return NULL;
577 }
578 
579 static SMTPTransaction *SMTPGetReplyTx(SMTPState *state)
580 {
581  if (state->cmds_idx >= state->cmds_cnt) {
582  return state->curr_tx;
583  }
584 
585  /* a command with no owning tx, or whose tx is gone, must not resolve
586  * to another tx */
587  if (state->cmds_tx_ids[state->cmds_idx] == SMTP_NO_TX_ID) {
588  return NULL;
589  }
590  return SMTPStateGetTxById(state, state->cmds_tx_ids[state->cmds_idx]);
591 }
592 
593 static void FlagDetectStateNewFile(SMTPTransaction *tx)
594 {
595  if (tx && tx->tx_data.de_state) {
596  SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set");
598  } else if (tx == NULL) {
599  SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW NOT set, no TX");
600  } else if (tx->tx_data.de_state == NULL) {
601  SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW NOT set, no TX DESTATE");
602  }
603 }
604 
605 static void SMTPNewFile(SMTPTransaction *tx, File *file)
606 {
607  DEBUG_VALIDATE_BUG_ON(tx == NULL);
608  DEBUG_VALIDATE_BUG_ON(file == NULL);
609 #ifdef UNITTESTS
610  if (RunmodeIsUnittests()) {
611  if (tx == NULL || file == NULL) {
612  return;
613  }
614  }
615 #endif
616  FlagDetectStateNewFile(tx);
617  tx->tx_data.files_opened++;
618 
619  /* set inspect sizes used in file pruning logic.
620  * TODO consider moving this to the file.data code that
621  * would actually have use for this. */
624 }
625 
626 /**
627  * \internal
628  * \brief Get the next line from input. It doesn't do any length validation.
629  *
630  * \param state The smtp state.
631  *
632  * \retval 0 On success.
633  * \retval -1 Either when we don't have any new lines to supply anymore or
634  * on failure.
635  */
636 static AppLayerResult SMTPGetLine(Flow *f, StreamSlice *slice, SMTPState *state, SMTPInput *input,
637  SMTPLine *line, uint16_t direction)
638 {
639  SCEnter();
640 
641  /* we have run out of input */
642  if (input->len <= 0)
643  return APP_LAYER_ERROR;
644 
645  const uint8_t type = direction == 0 ? SMTP_FRAME_COMMAND_LINE : SMTP_FRAME_RESPONSE_LINE;
646  Frame *frame = AppLayerFrameGetLastOpenByType(f, direction, type);
647  if (frame == NULL) {
648  if (direction == 0 &&
649  !(state->current_command == SMTP_COMMAND_DATA &&
652  f, slice, input->buf + input->consumed, -1, 0, SMTP_FRAME_COMMAND_LINE);
653  /* can't set tx id before (possibly) creating it */
654 
655  } else if (direction == 1) {
657  f, slice, input->buf + input->consumed, -1, 1, SMTP_FRAME_RESPONSE_LINE);
658  SMTPTransaction *reply_tx = SMTPGetReplyTx(state);
659  if (frame != NULL && reply_tx != NULL) {
660  AppLayerFrameSetTxId(frame, reply_tx->tx_id);
661  }
662  }
663  }
664  SCLogDebug("frame %p", frame);
665 
666  const uint8_t *lf_idx = memchr(input->buf + input->consumed, 0x0a, input->len);
667  bool discard_till_lf = (direction == 0) ? state->discard_till_lf_ts : state->discard_till_lf_tc;
668 
669  if (lf_idx == NULL) {
670  if (!discard_till_lf && input->len >= SMTP_LINE_BUFFER_LIMIT) {
671  line->buf = input->buf;
672  line->len = SMTP_LINE_BUFFER_LIMIT;
673  line->delim_len = 0;
675  }
676  SCReturnStruct(APP_LAYER_INCOMPLETE(input->consumed, input->len + 1));
677  } else {
678  /* There could be one chunk of command data that has LF but post the line limit
679  * e.g. input_len = 5077
680  * lf_idx = 5010
681  * max_line_len = 4096 */
682  uint32_t o_consumed = input->consumed;
683  input->consumed = (uint32_t)(lf_idx - input->buf + 1);
684  line->len = input->consumed - o_consumed;
685  line->lf_found = true;
686  DEBUG_VALIDATE_BUG_ON(line->len < 0);
687  if (line->len < 0)
689  input->len -= line->len;
690  DEBUG_VALIDATE_BUG_ON((input->consumed + input->len) != input->orig_len);
691  line->buf = input->buf + o_consumed;
692 
693  if (frame != NULL) {
694  frame->len = (int64_t)line->len;
695  }
696 
697  if (line->len >= SMTP_LINE_BUFFER_LIMIT) {
698  line->len = SMTP_LINE_BUFFER_LIMIT;
699  line->delim_len = 0;
701  }
702  if (discard_till_lf) {
703  // Whatever came in with first LF should also get discarded
704  if (direction == 0) {
705  state->discard_till_lf_ts = false;
706  } else {
707  state->discard_till_lf_tc = false;
708  }
709  line->len = 0;
710  line->delim_len = 0;
712  }
713  if (input->consumed >= 2 && input->buf[input->consumed - 2] == 0x0D) {
714  line->delim_len = 2;
715  line->len -= 2;
716  } else {
717  line->delim_len = 1;
718  line->len -= 1;
719  }
721  }
722 }
723 
724 static int SMTPInsertCommandIntoCommandBuffer(
725  SMTPState *state, uint8_t command, const SMTPTransaction *tx)
726 {
727  SCEnter();
728  void *ptmp;
729 
730  if (state->cmds_cnt >= state->cmds_buffer_len) {
731  int increment = SMTP_COMMAND_BUFFER_STEPS;
732  if ((int)(state->cmds_buffer_len + SMTP_COMMAND_BUFFER_STEPS) > (int)USHRT_MAX) {
733  increment = USHRT_MAX - state->cmds_buffer_len;
734  }
735 
736  ptmp = SCRealloc(state->cmds,
737  sizeof(uint8_t) * (state->cmds_buffer_len + increment));
738  if (ptmp == NULL) {
739  SCFree(state->cmds);
740  SCFree(state->cmds_tx_ids);
741  state->cmds = NULL;
742  state->cmds_tx_ids = NULL;
743  SCLogDebug("SCRealloc failure");
744  return -1;
745  }
746  state->cmds = ptmp;
747 
748  ptmp = SCRealloc(
749  state->cmds_tx_ids, sizeof(uint64_t) * (state->cmds_buffer_len + increment));
750  if (ptmp == NULL) {
751  SCFree(state->cmds);
752  SCFree(state->cmds_tx_ids);
753  state->cmds = NULL;
754  state->cmds_tx_ids = NULL;
755  SCLogDebug("SCRealloc failure");
756  return -1;
757  }
758  state->cmds_tx_ids = ptmp;
759 
760  state->cmds_buffer_len += increment;
761  }
762  if (state->cmds_cnt >= 1 &&
763  ((state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_STARTTLS) ||
764  (state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_DATA))) {
765  /* decoder event */
767  /* we have to have EHLO, DATA, VRFY, EXPN, TURN, QUIT, NOOP,
768  * STARTTLS as the last command in pipelined mode */
769  }
770 
771  /** \todo decoder event */
772  if ((int)(state->cmds_cnt + 1) > (int)USHRT_MAX) {
773  SCLogDebug("command buffer overflow");
774  return -1;
775  }
776 
777  state->cmds[state->cmds_cnt] = command;
778  state->cmds_tx_ids[state->cmds_cnt] = tx != NULL ? tx->tx_id : SMTP_NO_TX_ID;
779  state->cmds_cnt++;
780 
781  return 0;
782 }
783 
784 static int SMTPProcessCommandBDAT(SMTPState *state, SMTPTransaction *tx, const SMTPLine *line)
785 {
786  SCEnter();
787 
788  state->bdat_chunk_idx += (line->len + line->delim_len);
789  if (state->bdat_chunk_idx > state->bdat_chunk_len) {
791  /* decoder event */
792  SMTPSetEvent(state, SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED);
793  SCReturnInt(-1);
794  } else if (state->bdat_chunk_idx == state->bdat_chunk_len) {
796  if (state->current_command == SMTP_COMMAND_BDAT_LAST) {
797  SMTPTransactionCompleteTS(tx);
798  }
799  }
800 
801  SCReturnInt(0);
802 }
803 
804 static void SetMimeEvents(SMTPState *state, uint32_t events)
805 {
806  if (events == 0) {
807  return;
808  }
809 
810  if (events & MIME_ANOM_INVALID_BASE64) {
811  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_BASE64);
812  }
813  if (events & MIME_ANOM_INVALID_QP) {
814  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_QP);
815  }
816  if (events & MIME_ANOM_LONG_LINE) {
817  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_LINE);
818  }
819  if (events & MIME_ANOM_LONG_ENC_LINE) {
820  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE);
821  }
822  if (events & MIME_ANOM_LONG_HEADER_NAME) {
823  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME);
824  }
825  if (events & MIME_ANOM_LONG_HEADER_VALUE) {
826  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE);
827  }
828  if (events & MIME_ANOM_LONG_BOUNDARY) {
829  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG);
830  }
831  if (events & MIME_ANOM_LONG_FILENAME) {
832  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_FILENAME);
833  }
834 }
835 
836 static inline void SMTPTransactionComplete(SMTPTransaction *tx)
837 {
838  DEBUG_VALIDATE_BUG_ON(tx == NULL);
839  if (tx) {
840  SMTPSetProgressTS(tx, SMTP_REQUEST_COMPLETE);
841  SMTPSetProgressTC(tx, SMTP_RESPONSE_COMPLETE);
842  }
843 }
844 
845 /**
846  * \retval 0 ok
847  * \retval -1 error
848  */
849 static int SMTPProcessCommandDATA(
850  SMTPState *state, SMTPTransaction *tx, Flow *f, const SMTPLine *line)
851 {
852  SCEnter();
853  DEBUG_VALIDATE_BUG_ON(tx == NULL);
854 
855  SCTxDataUpdateFileFlags(&tx->tx_data, state->state_data.file_flags);
857  /* looks like are still waiting for a confirmation from the server */
858  return 0;
859  }
860 
861  if (line->len == 1 && line->buf[0] == '.') {
863  /* kinda like a hack. The mail sent in DATA mode, would be
864  * acknowledged with a reply. We insert a dummy command to
865  * the command buffer to be used by the reply handler to match
866  * the reply received */
867  SMTPInsertCommandIntoCommandBuffer(state, SMTP_COMMAND_DATA_MODE, tx);
869  /* we use this as the signal that message data is complete. */
870  FileCloseFile(&tx->files_ts, &smtp_config.sbcfg, NULL, 0, 0);
871  } else if (smtp_config.decode_mime && tx->mime_state != NULL) {
872  /* Complete parsing task */
873  SCSmtpMimeComplete(tx->mime_state);
874  if (tx->files_ts.tail && tx->files_ts.tail->state == FILE_STATE_OPENED) {
875  FileCloseFile(&tx->files_ts, &smtp_config.sbcfg, NULL, 0,
876  FileFlowToFlags(f, STREAM_TOSERVER));
877  }
878  }
879  SMTPTransactionCompleteTS(tx);
880  } else if (smtp_config.raw_extraction) {
881  // message not over, store the line. This is a substitution of
882  // ProcessDataChunk
883  FileAppendData(&tx->files_ts, &smtp_config.sbcfg, line->buf, line->len + line->delim_len);
884  }
885 
886  /* If DATA, then parse out a MIME message */
887  if (state->current_command == SMTP_COMMAND_DATA &&
889 
890  if (smtp_config.decode_mime && tx->mime_state != NULL) {
891  uint32_t events;
892  uint16_t flags = FileFlowToFlags(f, STREAM_TOSERVER);
893  const uint8_t *filename = NULL;
894  uint16_t filename_len = 0;
895  uint32_t depth;
896 
897  /* we depend on detection engine for file pruning */
899  MimeSmtpParserResult ret = SCSmtpMimeParseLine(
900  line->buf, line->len, line->delim_len, &events, tx->mime_state);
901  SetMimeEvents(state, events);
902  switch (ret) {
903  case MimeSmtpFileOpen:
904  // get filename owned by mime state
905  SCMimeSmtpGetFilename(state->curr_tx->mime_state, &filename, &filename_len);
906 
907  if (filename_len == 0) {
908  // not an attachment
909  break;
910  }
911  depth = (uint32_t)(smtp_config.content_inspect_min_size +
912  (state->toserver_data_count -
913  state->toserver_last_data_stamp));
914  SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %" PRIu32,
915  depth);
916  StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER, depth);
917 
918  if (filename_len > SC_FILENAME_MAX) {
919  filename_len = SC_FILENAME_MAX;
920  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_FILENAME);
921  }
923  state->file_track_id++, filename, filename_len, NULL, 0,
924  flags) != 0) {
925  SCLogDebug("FileOpenFile() failed");
926  } else {
927  SMTPNewFile(state->curr_tx, tx->files_ts.tail);
928  }
929  break;
930  case MimeSmtpFileChunk:
931  // rust already run FileAppendData
932  if (tx->files_ts.tail && tx->files_ts.tail->content_inspected == 0 &&
934  depth = (uint32_t)(smtp_config.content_inspect_min_size +
935  (state->toserver_data_count -
936  state->toserver_last_data_stamp));
938  SCLogDebug(
939  "StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u", depth);
940  StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER, depth);
941  /* after the start of the body inspection, disable the depth logic */
942  } else if (tx->files_ts.tail && tx->files_ts.tail->content_inspected > 0) {
943  StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER, 0);
944  /* expand the limit as long as we get file data, as the file data is bigger
945  * on the wire due to base64 */
946  } else {
947  depth = (uint32_t)(smtp_config.content_inspect_min_size +
948  (state->toserver_data_count -
949  state->toserver_last_data_stamp));
950  SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %" PRIu32,
951  depth);
952  StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER, depth);
953  }
954  break;
955  case MimeSmtpFileClose:
956  if (tx->files_ts.tail && tx->files_ts.tail->state == FILE_STATE_OPENED) {
957  if (FileCloseFile(&tx->files_ts, &smtp_config.sbcfg, NULL, 0, flags) != 0) {
958  SCLogDebug("FileCloseFile() failed: %d", ret);
959  }
960  } else {
961  SCLogDebug("File already closed");
962  }
963  depth = (uint32_t)(state->toserver_data_count -
964  state->toserver_last_data_stamp);
966  SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u", depth);
967  StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER, depth);
968  }
969  }
970  }
971 
972  return 0;
973 }
974 
975 static inline bool IsReplyToCommand(const SMTPState *state, const uint8_t cmd)
976 {
977  return (state->cmds_idx < state->cmds_cnt && state->cmds[state->cmds_idx] == cmd);
978 }
979 
980 static int SMTPProcessReply(
981  SMTPState *state, Flow *f, SMTPThreadCtx *td, SMTPInput *input, const SMTPLine *line)
982 {
983  SCEnter();
984 
985  /* Line with just LF */
986  if (line->len == 0 && input->consumed == 1 && line->delim_len == 1) {
987  return 0; // to continue processing further
988  }
989 
990  SMTPTransaction *reply_tx = SMTPGetReplyTx(state);
991  if (reply_tx != NULL) {
992  reply_tx->tx_data.updated_tc = true;
993  }
994  /* the reply code has to contain at least 3 bytes, to hold the 3 digit
995  * reply code */
996  if (line->len < 3) {
997  /* decoder event */
998  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
999  return -1;
1000  }
1001 
1002  if (line->len >= 4) {
1004  if (line->buf[3] != '-') {
1006  }
1007  } else {
1008  if (line->buf[3] == '-') {
1010  }
1011  }
1012  } else {
1015  }
1016  }
1017 
1018  /* I don't like this pmq reset here. We'll devise a method later, that
1019  * should make the use of the mpm very efficient */
1020  PmqReset(td->pmq);
1021  int mpm_cnt = mpm_table[SMTP_MPM].Search(
1022  smtp_mpm_ctx, td->smtp_mpm_thread_ctx, td->pmq, line->buf, 3);
1023  if (mpm_cnt == 0) {
1024  /* set decoder event - reply code invalid */
1025  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
1026  SCLogDebug("invalid reply code %02x %02x %02x", line->buf[0], line->buf[1], line->buf[2]);
1027  SCReturnInt(-1);
1028  }
1029  enum SMTPCode reply_code = smtp_reply_map[td->pmq->rule_id_array[0]].enum_value;
1030  SCLogDebug("REPLY: reply_code %u / %s", reply_code,
1031  smtp_reply_map[reply_code].enum_name);
1032 
1033  if (state->cmds_idx == state->cmds_cnt) {
1035  /* the first server reply can be a multiline message. Let's
1036  * flag the fact that we have seen the first reply only at the end
1037  * of a multiline reply
1038  */
1041  if (reply_code == SMTP_REPLY_220)
1042  SCReturnInt(0);
1043  else {
1044  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
1045  SCReturnInt(0);
1046  }
1047  } else {
1048  /* decoder event - unable to match reply with request */
1049  SCLogDebug("unable to match reply with request");
1050  SCReturnInt(0);
1051  }
1052  }
1053 
1054  if (state->cmds_cnt == 0) {
1055  /* reply but not a command we have stored, fall through */
1056  } else if (IsReplyToCommand(state, SMTP_COMMAND_STARTTLS)) {
1057  if (reply_code == SMTP_REPLY_220) {
1058  /* we are entering STARTTLS data mode */
1061  SMTPSetEvent(state, SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE);
1062  }
1063  if (reply_tx) {
1064  SMTPTransactionComplete(reply_tx);
1065  }
1066  } else {
1067  /* decoder event */
1068  SMTPSetEvent(state, SMTP_DECODER_EVENT_TLS_REJECTED);
1069  }
1070  } else if (IsReplyToCommand(state, SMTP_COMMAND_DATA)) {
1071  if (reply_code == SMTP_REPLY_354) {
1072  SMTPSetProgressTC(reply_tx, SMTP_RESPONSE_DATA);
1073  /* Next comes the mail for the DATA command in toserver direction */
1075  } else {
1076  /* decoder event */
1078  // reset data mode if we had entered it prematurely
1080  }
1081  SMTPSetEvent(state, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED);
1082  }
1083  } else if (IsReplyToCommand(state, SMTP_COMMAND_BDAT)) {
1085  state->current_command == SMTP_COMMAND_BDAT &&
1086  state->cmds_idx + 1 == state->cmds_cnt) {
1087  // The server replied before receiving the entire chunk.
1089  }
1090  SMTPSetProgressTC(reply_tx, SMTP_RESPONSE_DATA);
1091  } else if (IsReplyToCommand(state, SMTP_COMMAND_BDAT_LAST)) {
1094  state->cmds_idx + 1 == state->cmds_cnt) {
1095  // The server replied before receiving the entire chunk.
1097  }
1098  if (reply_tx && !(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) {
1099  SMTPTransactionCompleteTC(reply_tx);
1100  }
1101  } else if (IsReplyToCommand(state, SMTP_COMMAND_DATA_MODE)) {
1102  if (reply_tx && !(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) {
1103  SMTPTransactionCompleteTC(reply_tx);
1104  }
1105  } else if (IsReplyToCommand(state, SMTP_COMMAND_RSET)) {
1106  if (reply_code == SMTP_REPLY_250 && reply_tx &&
1108  SMTPTransactionComplete(reply_tx);
1109  }
1110  } else if (IsReplyToCommand(state, SMTP_COMMAND_QUIT)) {
1111  if (reply_code == SMTP_REPLY_221 && reply_tx &&
1113  SMTPTransactionComplete(reply_tx);
1114  }
1115  } else {
1116  /* we don't care for any other command for now */
1117  }
1118 
1119  /* if it is a multi-line reply, we need to move the index only once for all
1120  * the line of the reply. We unset the multiline flag on the last
1121  * line of the multiline reply, following which we increment the index */
1123  state->cmds_idx++;
1124  } else if (state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1125  /* we check if the server is indicating pipelining support */
1126  if (reply_code == SMTP_REPLY_250 && line->len == 14 &&
1127  SCMemcmpLowercase("pipelining", line->buf + 4, 10) == 0) {
1129  }
1130  }
1131 
1132  /* if we have matched all the buffered commands, reset the cnt and index */
1133  if (state->cmds_idx == state->cmds_cnt) {
1134  state->cmds_cnt = 0;
1135  state->cmds_idx = 0;
1136  }
1138 
1139  return 0;
1140 }
1141 
1142 static int SMTPParseCommandBDAT(SMTPState *state, const SMTPLine *line, bool *last)
1143 {
1144  SCEnter();
1145 
1146  *last = false;
1147 
1148  int i = 4;
1149  while (i < line->len) {
1150  if (line->buf[i] != ' ') {
1151  break;
1152  }
1153  i++;
1154  }
1155  if (i == 4) {
1156  /* decoder event */
1157  return -1;
1158  }
1159  if (i == line->len) {
1160  /* decoder event */
1161  return -1;
1162  }
1163  // copy in temporary null-terminated buffer for conversion
1164  char strbuf[24];
1165  int len = 23;
1166  if (line->len - i < len) {
1167  len = line->len - i;
1168  }
1169  memcpy(strbuf, line->buf + i, len);
1170  strbuf[len] = '\0';
1171  int parsed = ByteExtractStringUint32(&state->bdat_chunk_len, 10, 0, strbuf);
1172  if (parsed < 0) {
1173  /* decoder event */
1174  return -1;
1175  }
1176  state->bdat_chunk_idx = 0;
1177 
1178  i += parsed;
1179  if (i < line->len && line->buf[i] != ' ') {
1180  return -1;
1181  }
1182  while (i < line->len && line->buf[i] == ' ') {
1183  i++;
1184  }
1185  if (line->len - i == 4 && SCMemcmpLowercase("last", line->buf + i, 4) == 0) {
1186  *last = true;
1187  } else if (i != line->len) {
1188  return -1;
1189  }
1190 
1191  return 0;
1192 }
1193 
1194 static int SMTPParseCommandWithParam(SMTPState *state, const SMTPLine *line, uint8_t prefix_len,
1195  uint8_t **target, uint16_t *target_len)
1196 {
1197  int i = prefix_len + 1;
1198 
1199  while (i < line->len) {
1200  if (line->buf[i] != ' ') {
1201  break;
1202  }
1203  i++;
1204  }
1205 
1206  /* rfc1870: with the size extension the mail from can be followed by an option.
1207  We use the space separator to detect it. */
1208  int spc_i = i;
1209  while (spc_i < line->len) {
1210  if (line->buf[spc_i] == ' ') {
1211  break;
1212  }
1213  spc_i++;
1214  }
1215 
1216  *target = SCMalloc(spc_i - i + 1);
1217  if (*target == NULL)
1218  return -1;
1219  memcpy(*target, line->buf + i, spc_i - i);
1220  (*target)[spc_i - i] = '\0';
1221  if (spc_i - i > UINT16_MAX) {
1222  *target_len = UINT16_MAX;
1224  } else {
1225  *target_len = (uint16_t)(spc_i - i);
1226  }
1227 
1228  return 0;
1229 }
1230 
1231 static int SMTPParseCommandHELO(SMTPState *state, const SMTPLine *line)
1232 {
1233  if (state->helo) {
1234  SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1235  return 0;
1236  }
1237  return SMTPParseCommandWithParam(state, line, 4, &state->helo, &state->helo_len);
1238 }
1239 
1240 static int SMTPParseCommandMAILFROM(SMTPState *state, const SMTPLine *line)
1241 {
1242  if (state->curr_tx->mail_from) {
1243  SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1244  return 0;
1245  }
1246  return SMTPParseCommandWithParam(
1247  state, line, 9, &state->curr_tx->mail_from, &state->curr_tx->mail_from_len);
1248 }
1249 
1250 static int SMTPParseCommandRCPTTO(SMTPState *state, const SMTPLine *line)
1251 {
1252  uint8_t *rcptto;
1253  uint16_t rcptto_len;
1254 
1255  if (SMTPParseCommandWithParam(state, line, 7, &rcptto, &rcptto_len) == 0) {
1256  SMTPString *rcptto_str = SMTPStringAlloc();
1257  if (rcptto_str) {
1258  rcptto_str->str = rcptto;
1259  rcptto_str->len = rcptto_len;
1260  TAILQ_INSERT_TAIL(&state->curr_tx->rcpt_to_list, rcptto_str, next);
1261  } else {
1262  SCFree(rcptto);
1263  return -1;
1264  }
1265  } else {
1266  return -1;
1267  }
1268  return 0;
1269 }
1270 
1271 /* consider 'rset' and 'quit' to be part of the existing state */
1272 static int NoNewTx(SMTPState *state, const SMTPLine *line)
1273 {
1275  if (line->len >= 4 && SCMemcmpLowercase("rset", line->buf, 4) == 0) {
1276  return 1;
1277  } else if (line->len >= 4 && SCMemcmpLowercase("quit", line->buf, 4) == 0) {
1278  return 1;
1279  }
1280  }
1281  return 0;
1282 }
1283 
1284 /* XXX have a better name */
1285 #define rawmsgname "rawmsg"
1287 /*
1288  * @brief Process an SMTP Request
1289  *
1290  * Parse and decide the current command and set appropriate variables on the state
1291  * accordingly. Create transactions if needed or update the current transaction
1292  * with the appropriate data/params. Pass the control to the respective command
1293  * parser in the end.
1294  *
1295  * @param state Pointer to current SMTPState
1296  * @param f Pointer to the current Flow
1297  * @param pstate Pointer to the current AppLayerParserState
1298  * @param input Pointer to the current input data to SMTP parser
1299  * @param line Pointer to the current line being parsed by the SMTP parser
1300  * @return 0 for success
1301  * -1 for errors and inconsistent states
1302  * -2 if MIME state could not be allocated
1303  * */
1304 static int SMTPProcessRequest(
1305  SMTPState *state, Flow *f, SMTPInput *input, const SMTPLine *line, const StreamSlice *slice)
1306 {
1307  SCEnter();
1308  SMTPTransaction *tx = state->curr_tx;
1309 
1311  if (frame) {
1312  frame->len = (int64_t)line->len;
1313  } else {
1314  if (!(state->current_command == SMTP_COMMAND_DATA &&
1316  frame = AppLayerFrameNewByPointer(
1317  f, slice, line->buf, line->len, 0, SMTP_FRAME_COMMAND_LINE);
1318  }
1319  }
1320 
1321  /* If current input is to be discarded because it completes a long line,
1322  * line's length and delimiter len are reset to 0. Skip processing this line.
1323  * This line is only to get us out of the state where we should discard any
1324  * data till LF. */
1325  if (line->len == 0 && line->delim_len == 0) {
1326  return 0;
1327  }
1328  const bool no_new_tx = NoNewTx(state, line);
1329  if ((state->curr_tx == NULL && (state->tx_cnt == 0 || !no_new_tx)) ||
1330  (SMTPTransactionRequestIsComplete(state->curr_tx) && !no_new_tx)) {
1331  tx = SMTPTransactionCreate(state);
1332  if (tx == NULL)
1333  return -1;
1334  state->curr_tx = tx;
1335  TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
1336  state->nb_live_tx++;
1337  tx->tx_id = state->tx_cnt++;
1338 
1339  /* keep track of the start of the tx */
1343  }
1344  if (frame != NULL && state->curr_tx) {
1345  AppLayerFrameSetTxId(frame, state->curr_tx->tx_id);
1346  }
1347  if (tx != NULL) {
1348  tx->tx_data.updated_ts = true;
1349  }
1350 
1351  state->toserver_data_count += (line->len + line->delim_len);
1352 
1354  SMTPSetEvent(state, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE);
1355  }
1356 
1357  /* there are 2 commands that can push it into this COMMAND_DATA mode -
1358  * STARTTLS and DATA */
1360  int r = 0;
1362 
1363  if (tx == NULL) {
1364  DEBUG_VALIDATE_BUG_ON(!no_new_tx);
1365  const bool is_rset = SCMemcmpLowercase("rset", line->buf, 4) == 0;
1366  if (is_rset)
1367  state->bdat_chunk_idx = 0;
1369  } else if (line->len >= 8 && SCMemcmpLowercase("starttls", line->buf, 8) == 0) {
1371  } else if (line->len >= 4 && SCMemcmpLowercase("data", line->buf, 4) == 0) {
1373  SMTPSetProgressTS(tx, SMTP_REQUEST_DATA);
1374  if (state->curr_tx->is_data) {
1375  // We did not receive a confirmation from server
1376  // And now client sends a next DATA
1377  SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT);
1378  SCReturnInt(0);
1379  } else if (smtp_config.raw_extraction) {
1381  (uint8_t *)rawmsgname, strlen(rawmsgname), NULL, 0,
1382  FILE_NOMD5 | FILE_NOMAGIC) == 0) {
1383  SMTPNewFile(tx, tx->files_ts.tail);
1384  }
1385  } else if (smtp_config.decode_mime) {
1387  tx->mime_state = SCMimeSmtpStateInit(&tx->files_ts, &smtp_config.sbcfg);
1388  if (tx->mime_state == NULL) {
1389  SCLogDebug("MimeDecInitParser() failed to "
1390  "allocate data");
1391  return -1;
1392  }
1393  }
1394  state->curr_tx->is_data = true;
1395 
1396  Frame *data_frame = AppLayerFrameNewByPointer(
1397  f, slice, input->buf + input->consumed, -1, 0, SMTP_FRAME_DATA);
1398  if (data_frame == NULL) {
1399  SCLogDebug("data_frame %p - no data frame set up", data_frame);
1400  } else {
1401  AppLayerFrameSetTxId(data_frame, state->curr_tx->tx_id);
1402  }
1403 
1404  /* Enter immediately data mode without waiting for server reply */
1407  }
1408  } else if (line->len >= 4 && SCMemcmpLowercase("bdat", line->buf, 4) == 0) {
1409  bool last = false;
1410  r = SMTPParseCommandBDAT(state, line, &last);
1411  if (r == -1) {
1412  /* Invalid BDAT syntax is recoverable: the server rejects the
1413  * command and the session continues. */
1414  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_BDAT);
1416  r = 0;
1417  } else {
1419  SMTPSetProgressTS(tx, SMTP_REQUEST_DATA);
1420  if (state->bdat_chunk_len > 0) {
1422  } else if (last) {
1423  SMTPTransactionCompleteTS(tx);
1424  }
1425  }
1426  } else if (line->len >= 4 && ((SCMemcmpLowercase("helo", line->buf, 4) == 0) ||
1427  SCMemcmpLowercase("ehlo", line->buf, 4) == 0)) {
1428  r = SMTPParseCommandHELO(state, line);
1429  if (r == -1) {
1430  SCReturnInt(-1);
1431  }
1432  if (state->curr_tx->mail_from != NULL || !TAILQ_EMPTY(&state->curr_tx->rcpt_to_list) ||
1434  /* Mid-session HELO/EHLO resets the state as if a RSET
1435  * had been issued (RFC 5321 4.1.4). The progress check
1436  * catches a transaction with no envelope but an attempted
1437  * DATA or BDAT, such as a rejected envelope-less DATA. */
1438  state->bdat_chunk_idx = 0;
1440  } else {
1442  }
1443  } else if (line->len >= 9 && SCMemcmpLowercase("mail from", line->buf, 9) == 0) {
1444  r = SMTPParseCommandMAILFROM(state, line);
1445  if (r == -1) {
1446  SCReturnInt(-1);
1447  }
1449  } else if (line->len >= 7 && SCMemcmpLowercase("rcpt to", line->buf, 7) == 0) {
1450  r = SMTPParseCommandRCPTTO(state, line);
1451  if (r == -1) {
1452  SCReturnInt(-1);
1453  }
1455  } else if (line->len >= 4 && SCMemcmpLowercase("rset", line->buf, 4) == 0) {
1456  // Resets chunk index in case of connection reuse
1457  state->bdat_chunk_idx = 0;
1459  } else if (line->len >= 4 && SCMemcmpLowercase("quit", line->buf, 4) == 0) {
1461  } else {
1463  }
1464 
1465  /* Every command is inserted into a command buffer, to be matched
1466  * against reply(ies) sent by the server */
1467  if (SMTPInsertCommandIntoCommandBuffer(state, state->current_command, tx) == -1) {
1468  SCReturnInt(-1);
1469  }
1470 
1471  SCReturnInt(r);
1472  }
1473 
1474  switch (state->current_command) {
1475  case SMTP_COMMAND_DATA:
1476  return SMTPProcessCommandDATA(state, tx, f, line);
1477 
1478  case SMTP_COMMAND_BDAT:
1480  return SMTPProcessCommandBDAT(state, tx, line);
1481 
1482  default:
1483  /* we have nothing to do with any other command at this instant.
1484  * Just let it go through */
1485  SCReturnInt(0);
1486  }
1487 }
1488 
1489 static inline void ResetLine(SMTPLine *line)
1490 {
1491  if (line != NULL) {
1492  line->len = 0;
1493  line->delim_len = 0;
1494  line->buf = NULL;
1495  }
1496 }
1497 
1498 static int SMTPPreProcessCommandBDAT(
1499  SMTPState *state, Flow *f, StreamSlice *slice, SMTPInput *input, SMTPLine *line)
1500 {
1501  if (state->bdat_chunk_idx >= state->bdat_chunk_len) {
1502  /* The BDAT chunk is already complete; data mode was set by another
1503  * command, such as a pipelined DATA reply. Leave data mode and let
1504  * the line parser handle the input as a new command. */
1506  return 1;
1507  }
1508  uint32_t remaining = state->bdat_chunk_len - state->bdat_chunk_idx;
1509  uint32_t consumed = MIN((uint32_t)input->len, remaining);
1510  line->buf = input->buf + input->consumed;
1511  line->len = consumed;
1512  input->consumed += consumed;
1513  input->len -= consumed;
1514  int ret = SMTPProcessRequest(state, f, input, line, slice);
1515  ResetLine(line);
1516  return ret;
1517 }
1518 
1519 /*
1520  * @brief Pre-process command data.
1521  *
1522  * If the command being processed is DATA, its data must be handled by this
1523  * function so the line limit used by GetLine is not applied. GetLine caps lines
1524  * at SMTP_LINE_BUFFER_LIMIT, which could truncate file data or parts of an
1525  * e-mail if a line were too long.
1526  *
1527  * BDAT data is octet-counted and must be consumed only up to the declared chunk
1528  * boundary.
1529  *
1530  * @param state Pointer to the current SMTPState
1531  * @param f Pointer to the current Flow
1532  * @param pstate Pointer to the current AppLayerParserState
1533  * @param input Pointer to the current input data to SMTP parser
1534  * @param line Pointer to the current line being parsed by the SMTP parser
1535  * @return 0 for success
1536  * 1 for handing control over to GetLine
1537  * -1 for errors and inconsistent states
1538  * */
1539 static int SMTPPreProcessCommands(
1540  SMTPState *state, Flow *f, StreamSlice *slice, SMTPInput *input, SMTPLine *line)
1541 {
1543  DEBUG_VALIDATE_BUG_ON(line->len != 0);
1544  DEBUG_VALIDATE_BUG_ON(line->delim_len != 0);
1545 
1546  if (state->current_command == SMTP_COMMAND_BDAT ||
1548  return SMTPPreProcessCommandBDAT(state, f, slice, input, line);
1549  }
1550 
1551  /* fall back to strict line parsing for mime header parsing */
1552  if (state->curr_tx && state->curr_tx->mime_state &&
1553  SCMimeSmtpGetState(state->curr_tx->mime_state) < MimeSmtpBody)
1554  return 1;
1555 
1556  bool line_complete = false;
1557  const int32_t input_len = input->len;
1558  const int32_t offset = input->consumed;
1559  for (int32_t i = 0; i < input_len; i++) {
1560  if (input->buf[offset + i] == 0x0d) {
1561  if (i < input_len - 1 && input->buf[offset + i + 1] == 0x0a) {
1562  i++;
1563  line->delim_len++;
1564  }
1565  /* Line is just ending in CR */
1566  line->delim_len++;
1567  line_complete = true;
1568  } else if (input->buf[offset + i] == 0x0a) {
1569  /* Line is just ending in LF */
1570  line->delim_len++;
1571  line_complete = true;
1572  }
1573  /* Either line is complete or fragmented */
1574  if (line_complete || (i == input_len - 1)) {
1575  DEBUG_VALIDATE_BUG_ON(input->consumed + input->len != input->orig_len);
1576  DEBUG_VALIDATE_BUG_ON(input->len == 0 && input_len != 0);
1577  /* state->input_len reflects data from start of the line in progress. */
1578  if ((input->len == 1 && input->buf[input->consumed] == '-') ||
1579  (input->len > 1 && input->buf[input->consumed] == '-' &&
1580  input->buf[input->consumed + 1] == '-')) {
1581  SCLogDebug("Possible boundary, yield to GetLine");
1582  return 1;
1583  }
1584  /* total_consumed should be input consumed so far + i + 1 */
1585  int32_t total_consumed = offset + i + 1;
1586  int32_t current_line_consumed = total_consumed - input->consumed;
1587  DEBUG_VALIDATE_BUG_ON(current_line_consumed < line->delim_len);
1588  line->buf = input->buf + input->consumed;
1589  line->len = current_line_consumed - line->delim_len;
1590  DEBUG_VALIDATE_BUG_ON(line->len < 0);
1591  if (line->len < 0) {
1592  return -1;
1593  }
1594 
1595  input->consumed = total_consumed;
1596  input->len -= current_line_consumed;
1597  DEBUG_VALIDATE_BUG_ON(input->consumed + input->len != input->orig_len);
1598  if (SMTPProcessRequest(state, f, input, line, slice) == -1) {
1599  return -1;
1600  }
1601  line_complete = false;
1602  line->buf = NULL;
1603  line->len = 0;
1604  line->delim_len = 0;
1605 
1606  /* bail if `SMTPProcessRequest` ended the data mode */
1607  if ((state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE) == 0) {
1609  if (data_frame) {
1610  data_frame->len = (slice->offset + input->consumed) - data_frame->offset;
1611  }
1612  break;
1613  }
1614  }
1615  }
1616  return 0;
1617 }
1618 
1619 static AppLayerResult SMTPParse(uint8_t direction, Flow *f, SMTPState *state,
1620  AppLayerParserState *pstate, StreamSlice stream_slice, SMTPThreadCtx *thread_data)
1621 {
1622  SCEnter();
1623 
1624  const uint8_t *input_buf = StreamSliceGetData(&stream_slice);
1625  uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
1626 
1627  if (input_buf == NULL &&
1628  ((direction == 0 && SCAppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) ||
1629  (direction == 1 &&
1630  SCAppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC)))) {
1632  } else if (input_buf == NULL || input_len == 0) {
1634  }
1635 
1636  SMTPInput input = { .buf = input_buf, .len = input_len, .orig_len = input_len, .consumed = 0 };
1637  SMTPLine line = { NULL, 0, 0, false };
1638 
1639  /* toserver */
1640  if (direction == 0) {
1641  if (((state->current_command == SMTP_COMMAND_DATA) ||
1642  (state->current_command == SMTP_COMMAND_BDAT) ||
1643  (state->current_command == SMTP_COMMAND_BDAT_LAST)) &&
1645  int ret = SMTPPreProcessCommands(state, f, &stream_slice, &input, &line);
1646  DEBUG_VALIDATE_BUG_ON(ret != 0 && ret != -1 && ret != 1);
1647  if (ret == 0 && input.consumed == input.orig_len) {
1649  } else if (ret < 0) {
1651  }
1652  }
1653  AppLayerResult res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1654  while (res.status == 0) {
1655  int retval = SMTPProcessRequest(state, f, &input, &line, &stream_slice);
1656  if (retval != 0)
1658  if (line.delim_len == 0 && line.len == SMTP_LINE_BUFFER_LIMIT) {
1659  if (!line.lf_found) {
1660  state->discard_till_lf_ts = true;
1661  }
1662  input.consumed = input.len + 1; // For the newly found LF
1663  SMTPSetEvent(state, SMTP_DECODER_EVENT_TRUNCATED_LINE);
1664  break;
1665  }
1666  /* If request was successfully parsed, reset line as it has already been used
1667  * wherever it had to be */
1668  ResetLine(&line);
1669 
1670  /* If command data mode was entered in the middle of input parsing, first pass it to
1671  * SMTPPreProcessCommands so input limits are not applied to DATA bodies and BDAT data
1672  * is not consumed past its chunk boundary. SMTPPreProcessCommands should either
1673  * consume all remaining input or stop at a MIME or BDAT chunk boundary, after which
1674  * control is passed to SMTPGetLine. */
1675  if ((input.len > 0) &&
1676  ((state->current_command == SMTP_COMMAND_DATA) ||
1677  (state->current_command == SMTP_COMMAND_BDAT) ||
1678  (state->current_command == SMTP_COMMAND_BDAT_LAST)) &&
1680  int ret = SMTPPreProcessCommands(state, f, &stream_slice, &input, &line);
1681  DEBUG_VALIDATE_BUG_ON(ret != 0 && ret != -1 && ret != 1);
1682  if (ret == 0 && input.consumed == input.orig_len) {
1684  } else if (ret < 0) {
1686  }
1687  }
1688  res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1689  }
1690  if (res.status == 1)
1691  return res;
1692  /* toclient */
1693  } else {
1694  AppLayerResult res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1695  while (res.status == 0) {
1696  if (SMTPProcessReply(state, f, thread_data, &input, &line) != 0)
1698  if (line.delim_len == 0 && line.len == SMTP_LINE_BUFFER_LIMIT) {
1699  if (!line.lf_found) {
1700  state->discard_till_lf_tc = true;
1701  }
1702  input.consumed = input.len + 1; // For the newly found LF
1703  SMTPSetEvent(state, SMTP_DECODER_EVENT_TRUNCATED_LINE);
1704  break;
1705  }
1706  res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1707  }
1708  if (res.status == 1)
1709  return res;
1710  }
1711 
1713 }
1714 
1715 static AppLayerResult SMTPParseClientRecord(Flow *f, void *alstate, AppLayerParserState *pstate,
1716  StreamSlice stream_slice, void *local_data)
1717 {
1718  SCEnter();
1719 
1720  /* first arg 0 is toserver */
1721  return SMTPParse(0, f, alstate, pstate, stream_slice, local_data);
1722 }
1723 
1724 static AppLayerResult SMTPParseServerRecord(Flow *f, void *alstate, AppLayerParserState *pstate,
1725  StreamSlice stream_slice, void *local_data)
1726 {
1727  SCEnter();
1728 
1729  /* first arg 1 is toclient */
1730  return SMTPParse(1, f, alstate, pstate, stream_slice, local_data);
1731 }
1732 
1733 /**
1734  * \internal
1735  * \brief Function to allocate SMTP state memory.
1736  */
1737 void *SMTPStateAlloc(void *orig_state, AppProto proto_orig)
1738 {
1739  SMTPState *smtp_state = SCCalloc(1, sizeof(SMTPState));
1740  if (unlikely(smtp_state == NULL))
1741  return NULL;
1742 
1743  smtp_state->cmds = SCMalloc(sizeof(uint8_t) *
1745  if (smtp_state->cmds == NULL) {
1746  SCFree(smtp_state);
1747  return NULL;
1748  }
1749  smtp_state->cmds_tx_ids = SCMalloc(sizeof(uint64_t) * SMTP_COMMAND_BUFFER_STEPS);
1750  if (smtp_state->cmds_tx_ids == NULL) {
1751  SCFree(smtp_state->cmds);
1752  SCFree(smtp_state);
1753  return NULL;
1754  }
1756 
1757  TAILQ_INIT(&smtp_state->tx_list);
1758 
1759  return smtp_state;
1760 }
1761 
1762 static SMTPString *SMTPStringAlloc(void)
1763 {
1764  SMTPString *smtp_string = SCCalloc(1, sizeof(SMTPString));
1765  if (unlikely(smtp_string == NULL))
1766  return NULL;
1767 
1768  return smtp_string;
1769 }
1770 
1771 
1772 static void SMTPStringFree(SMTPString *str)
1773 {
1774  if (str->str) {
1775  SCFree(str->str);
1776  }
1777  SCFree(str);
1778 }
1779 
1780 static void *SMTPLocalStorageAlloc(void)
1781 {
1782  /* needed by the mpm */
1783  SMTPThreadCtx *td = SCCalloc(1, sizeof(*td));
1784  if (td == NULL) {
1785  exit(EXIT_FAILURE);
1786  }
1787 
1788  td->pmq = SCCalloc(1, sizeof(*td->pmq));
1789  if (td->pmq == NULL) {
1790  exit(EXIT_FAILURE);
1791  }
1792  PmqSetup(td->pmq);
1793 
1794  td->smtp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx));
1795  if (unlikely(td->smtp_mpm_thread_ctx == NULL)) {
1796  exit(EXIT_FAILURE);
1797  }
1798  MpmInitThreadCtx(td->smtp_mpm_thread_ctx, smtp_mpm_ctx, SMTP_MPM);
1799  return td;
1800 }
1801 
1802 static void SMTPLocalStorageFree(void *ptr)
1803 {
1804  SMTPThreadCtx *td = ptr;
1805  if (td != NULL) {
1806  if (td->pmq != NULL) {
1807  PmqFree(td->pmq);
1808  SCFree(td->pmq);
1809  }
1810 
1811  if (td->smtp_mpm_thread_ctx != NULL) {
1814  }
1815 
1816  SCFree(td);
1817  }
1818 }
1819 
1820 static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state)
1821 {
1822  if (tx->mime_state != NULL) {
1823  SCMimeSmtpStateFree(tx->mime_state);
1824  }
1825 
1827 
1828  if (tx->mail_from)
1829  SCFree(tx->mail_from);
1830 
1831  SMTPString *str = NULL;
1832  while ((str = TAILQ_FIRST(&tx->rcpt_to_list))) {
1833  TAILQ_REMOVE(&tx->rcpt_to_list, str, next);
1834  SMTPStringFree(str);
1835  }
1837 
1838  SCFree(tx);
1839 }
1840 
1841 /**
1842  * \internal
1843  * \brief Function to free SMTP state memory.
1844  */
1845 static void SMTPStateFree(void *p)
1846 {
1847  SMTPState *smtp_state = (SMTPState *)p;
1848 
1849  if (smtp_state->cmds != NULL) {
1850  SCFree(smtp_state->cmds);
1851  }
1852  if (smtp_state->cmds_tx_ids != NULL) {
1853  SCFree(smtp_state->cmds_tx_ids);
1854  }
1855 
1856  if (smtp_state->helo) {
1857  SCFree(smtp_state->helo);
1858  }
1859 
1860  SMTPTransaction *tx = NULL;
1861  while ((tx = TAILQ_FIRST(&smtp_state->tx_list))) {
1862  TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1863  SMTPTransactionFree(tx, smtp_state);
1864  }
1865 
1866  SCFree(smtp_state);
1867 }
1868 
1869 static void SMTPSetMpmState(void)
1870 {
1871  smtp_mpm_ctx = SCCalloc(1, sizeof(MpmCtx));
1872  if (unlikely(smtp_mpm_ctx == NULL)) {
1873  exit(EXIT_FAILURE);
1874  }
1875  MpmInitCtx(smtp_mpm_ctx, SMTP_MPM);
1876 
1877  uint32_t i = 0;
1878  for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) {
1879  SCEnumCharMap *map = &smtp_reply_map[i];
1880  /* The third argument is 3, because reply code is always 3 bytes. */
1881  SCMpmAddPatternCI(smtp_mpm_ctx, (uint8_t *)map->enum_name, 3, 0 /* defunct */,
1882  0 /* defunct */, i /* pattern id */, i /* rule id */, 0 /* no flags */);
1883  }
1884 
1885  mpm_table[SMTP_MPM].Prepare(NULL, smtp_mpm_ctx);
1886 }
1887 
1888 static void SMTPFreeMpmState(void)
1889 {
1890  if (smtp_mpm_ctx != NULL) {
1891  mpm_table[SMTP_MPM].DestroyCtx(smtp_mpm_ctx);
1892  SCFree(smtp_mpm_ctx);
1893  smtp_mpm_ctx = NULL;
1894  }
1895 }
1896 
1897 static int SMTPStateGetEventInfo(
1898  const char *event_name, uint8_t *event_id, AppLayerEventType *event_type)
1899 {
1900  if (SCAppLayerGetEventIdByName(event_name, smtp_decoder_event_table, event_id) == 0) {
1901  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
1902  return 0;
1903  }
1904  return -1;
1905 }
1906 
1907 static int SMTPStateGetEventInfoById(
1908  uint8_t event_id, const char **event_name, AppLayerEventType *event_type)
1909 {
1910  *event_name = SCMapEnumValueToName(event_id, smtp_decoder_event_table);
1911  if (*event_name == NULL) {
1912  SCLogError("event \"%d\" not present in "
1913  "smtp's enum map table.",
1914  event_id);
1915  /* yes this is fatal */
1916  return -1;
1917  }
1918 
1919  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
1920 
1921  return 0;
1922 }
1923 
1924 // This probing parser checks the port after ambiguous patterns
1925 // that may be used by other protocols such as FTP
1926 static AppProto SMTPClientProbingParserCheckPort(
1927  const Flow *f, uint8_t direction, const uint8_t *input, uint32_t len, uint8_t *rdir)
1928 {
1929  if (AppLayerProtoDetectHasProbingParsers(IPPROTO_TCP, f->dp, ALPROTO_FTP)) {
1930  return ALPROTO_FAILED;
1931  }
1932  return ALPROTO_SMTP;
1933 }
1934 
1935 static AppProto SMTPServerProbingParser(
1936  const Flow *f, uint8_t direction, const uint8_t *input, uint32_t len, uint8_t *rdir)
1937 {
1938  // another check for minimum length
1939  if (len < 5) {
1940  return ALPROTO_UNKNOWN;
1941  }
1942  // begins by 220
1943  if (input[0] != '2' || input[1] != '2' || input[2] != '0') {
1944  return ALPROTO_FAILED;
1945  }
1946  // followed by space or hypen
1947  if (input[3] != ' ' && input[3] != '-') {
1948  return ALPROTO_FAILED;
1949  }
1950  // If client side is SMTP, do not validate domain
1951  // so that server banner can be parsed first.
1952  if (f->alproto_ts == ALPROTO_SMTP) {
1953  if (memchr(input + 4, '\n', len - 4) != NULL) {
1954  return ALPROTO_SMTP;
1955  }
1956  return ALPROTO_UNKNOWN;
1957  }
1959  if (f->todstbytecnt > 4 && (f->alproto_ts == ALPROTO_UNKNOWN || f->alproto_ts == ALPROTO_TLS)) {
1960  // Only validates SMTP if client side is unknown
1961  // despite having received bytes.
1962  r = ALPROTO_SMTP;
1963  }
1964  uint32_t offset = SCValidateDomain(input + 4, len - 4);
1965  if (offset == 0) {
1966  return ALPROTO_FAILED;
1967  }
1968  if (r != ALPROTO_UNKNOWN && memchr(input + 4, '\n', len - 4) != NULL) {
1969  return r;
1970  }
1971  // This should not go forever because of engine limiting probing parsers.
1972  return ALPROTO_UNKNOWN;
1973 }
1974 
1975 static int SMTPRegisterPatternsForProtocolDetection(void)
1976 {
1978  IPPROTO_TCP, ALPROTO_SMTP, "EHLO", 4, 0, STREAM_TOSERVER) < 0) {
1979  return -1;
1980  }
1982  IPPROTO_TCP, ALPROTO_SMTP, "HELO", 4, 0, STREAM_TOSERVER) < 0) {
1983  return -1;
1984  }
1985  if (SCAppLayerProtoDetectPMRegisterPatternCIwPP(IPPROTO_TCP, ALPROTO_SMTP, "QUIT", 4, 0,
1986  STREAM_TOSERVER, SMTPClientProbingParserCheckPort, 4, 4) < 0) {
1987  return -1;
1988  }
1989 
1991  "tcp", IPPROTO_TCP, "smtp", ALPROTO_SMTP, 0, 5, NULL, SMTPServerProbingParser)) {
1992  // STREAM_TOSERVER means here use 25 as flow destination port
1993  SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "25,465", ALPROTO_SMTP, 0, 5, STREAM_TOSERVER,
1994  NULL, SMTPServerProbingParser);
1995  }
1996 
1997  return 0;
1998 }
1999 
2000 static void SMTPStateTransactionFree (void *state, uint64_t tx_id)
2001 {
2002  SMTPState *smtp_state = state;
2003  SMTPTransaction *tx = NULL;
2004  TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
2005  if (tx_id < tx->tx_id)
2006  break;
2007  else if (tx_id > tx->tx_id)
2008  continue;
2009 
2010  if (tx == smtp_state->curr_tx)
2011  smtp_state->curr_tx = NULL;
2012  TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
2013  smtp_state->nb_live_tx--;
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:577
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:271
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:162
Flow_::flags
uint64_t flags
Definition: flow.h:408
SMTP_REPLY_534
@ SMTP_REPLY_534
Definition: app-layer-smtp.c:304
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:302
SMTP_PARSER_STATE_FIRST_REPLY_SEEN
#define SMTP_PARSER_STATE_FIRST_REPLY_SEEN
Definition: app-layer-smtp.c:71
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:103
SMTP_COMMAND_DATA
#define SMTP_COMMAND_DATA
Definition: app-layer-smtp.c:82
SMTP_REPLY_535
@ SMTP_REPLY_535
Definition: app-layer-smtp.c:305
MpmThreadCtx_
Definition: util-mpm.h:62
stream-tcp.h
SMTP_REPLY_401
@ SMTP_REPLY_401
Definition: app-layer-smtp.c:284
SMTPState_::bdat_chunk_idx
uint32_t bdat_chunk_idx
Definition: app-layer-smtp.h:151
SMTPTransaction_::progress_ts
uint8_t progress_ts
Definition: app-layer-smtp.h: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:101
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:190
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:115
SMTPConfig
Structure for containing configuration options.
Definition: app-layer-smtp.h:118
SMTP_REPLY_421
@ SMTP_REPLY_421
Definition: app-layer-smtp.c:286
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:142
name
const char * name
Definition: detect-engine-proto.c:47
Flow_::proto
uint8_t proto
Definition: flow.h:381
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:2180
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:55
Frame
Definition: app-layer-frames.h:49
Flow_
Flow data structure.
Definition: flow.h:359
SMTP_REPLY_454
@ SMTP_REPLY_454
Definition: app-layer-smtp.c:291
SCHEME_SUFFIX_LEN
#define SCHEME_SUFFIX_LEN
Definition: app-layer-smtp.c:375
SMTP_REPLY_503
@ SMTP_REPLY_503
Definition: app-layer-smtp.c:297
File_::state
FileState state
Definition: util-file.h:149
SMTP_REPLY_553
@ SMTP_REPLY_553
Definition: app-layer-smtp.c:311
SMTP_REPLY_500
@ SMTP_REPLY_500
Definition: app-layer-smtp.c:294
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:138
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:66
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:136
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2912
SMTP_REPLY_522
@ SMTP_REPLY_522
Definition: app-layer-smtp.c:301
SCConfGetChildValueBool
int SCConfGetChildValueBool(const SCConfNode *base, const char *name, int *val)
Definition: conf.c:541
SMTP_REPLY_521
@ SMTP_REPLY_521
Definition: app-layer-smtp.c:300
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:156
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:165
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:236
SMTP_FRAME_DATA
@ SMTP_FRAME_DATA
Definition: app-layer-smtp.c:155
rust.h
FileContainer_::tail
File * tail
Definition: util-file.h:39
MIN
#define MIN(x, y)
Definition: suricata-common.h:413
SCConfGetBool
int SCConfGetBool(const char *name, int *val)
Retrieve a configuration value as a boolean.
Definition: conf.c:523
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:310
SCConfValIsFalse
int SCConfValIsFalse(const char *val)
Check if a value is false.
Definition: conf.c:602
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:241
ByteExtractStringUint32
int ByteExtractStringUint32(uint32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:194
SMTP_REPLY_550
@ SMTP_REPLY_550
Definition: app-layer-smtp.c:308
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:3305
FILEDATA_CONTENT_LIMIT
#define FILEDATA_CONTENT_LIMIT
Definition: app-layer-smtp.c:53
p
Packet * p
Definition: fuzz_dataset.c:30
SMTP_REPLY_334
@ SMTP_REPLY_334
Definition: app-layer-smtp.c:281
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:375
DetectEngineAppendSig
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:3971
SMTPThreadCtx_
Definition: app-layer-smtp.c:260
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:113
SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY
#define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY
Definition: app-layer-smtp.c:73
Flow_::protoctx
void * protoctx
Definition: flow.h:438
AppLayerGetTxIterTuple::tx_ptr
void * tx_ptr
Definition: app-layer-parser.h:160
SMTP_REPLY_541
@ SMTP_REPLY_541
Definition: app-layer-smtp.c:306
SMTP_REPLY_251
@ SMTP_REPLY_251
Definition: app-layer-smtp.c:278
smtp_decoder_event_table
SCEnumCharMap smtp_decoder_event_table[]
Definition: app-layer-smtp.c:122
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:296
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:208
SMTPInput_::len
int32_t len
Definition: app-layer-smtp.c:104
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:496
FLOW_INITIALIZE
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:38
SMTP_REPLY_504
@ SMTP_REPLY_504
Definition: app-layer-smtp.c:298
SMTP_COMMAND_DATA_MODE
#define SMTP_COMMAND_DATA_MODE
Definition: app-layer-smtp.c:88
SMTP_COMMAND_STARTTLS
#define SMTP_COMMAND_STARTTLS
Definition: app-layer-smtp.c:81
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:201
util-debug.h
SMTP_MPM
#define SMTP_MPM
Definition: app-layer-smtp.c:265
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:276
SMTP_REPLY_551
@ SMTP_REPLY_551
Definition: app-layer-smtp.c:309
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:94
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:91
AppLayerEventType
AppLayerEventType
Definition: app-layer-events.h:54
SMTPState_::helo
uint8_t * helo
Definition: app-layer-smtp.h:169
SMTP_DEFAULT_MAX_TX
#define SMTP_DEFAULT_MAX_TX
Definition: app-layer-smtp.c:96
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:257
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:145
FileContainer_::head
File * head
Definition: util-file.h:38
SMTP_REPLY_455
@ SMTP_REPLY_455
Definition: app-layer-smtp.c:292
SCConfGetNonNull
int SCConfGetNonNull(const char *name, const char **vptr)
Retrieve the non-null value of a configuration node.
Definition: conf.c:380
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:57
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:3660
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:55
SMTPState_::curr_tx
SMTPTransaction * curr_tx
Definition: app-layer-smtp.h:133
SMTP_COMMAND_BDAT
#define SMTP_COMMAND_BDAT
Definition: app-layer-smtp.c:83
SMTPState_::discard_till_lf_ts
bool discard_till_lf_ts
Definition: app-layer-smtp.h:141
SMTPInput_::consumed
int32_t consumed
Definition: app-layer-smtp.c:110
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:272
SMTP_REPLY_220
@ SMTP_REPLY_220
Definition: app-layer-smtp.c:274
SMTPFrameTypes
SMTPFrameTypes
Definition: app-layer-smtp.c:153
app-layer-parser.h
Flow_::todstbytecnt
uint64_t todstbytecnt
Definition: flow.h:502
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:364
SCReturn
#define SCReturn
Definition: util-debug.h:286
SMTP_RAW_EXTRACTION_DEFAULT_VALUE
#define SMTP_RAW_EXTRACTION_DEFAULT_VALUE
Definition: app-layer-smtp.c:60
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:279
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:475
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:277
detect-engine-alert.h
conf.h
SMTP_REPLY_555
@ SMTP_REPLY_555
Definition: app-layer-smtp.c:313
StreamingBufferCompareRawData
int StreamingBufferCompareRawData(const StreamingBuffer *sb, const uint8_t *rawdata, uint32_t rawdata_len)
Definition: util-streaming-buffer.c:1850
Frame::len
int64_t len
Definition: app-layer-frames.h:56
FileOpenFileWithId
int FileOpenFileWithId(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, const uint8_t *name, uint16_t name_len, const uint8_t *data, uint32_t data_len, uint16_t flags)
Open a new File.
Definition: util-file.c:966
SMTPState_::current_command
uint8_t current_command
Definition: app-layer-smtp.h:147
File_::name
uint8_t * name
Definition: util-file.h:155
SMTP_PARSER_STATE_COMMAND_DATA_MODE
#define SMTP_PARSER_STATE_COMMAND_DATA_MODE
Definition: app-layer-smtp.c:69
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:1285
SMTP_COMMAND_BUFFER_STEPS
#define SMTP_COMMAND_BUFFER_STEPS
Definition: app-layer-smtp.c:62
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:293
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:312
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:1737
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:119
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:290
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:261
StatsThreadInit
void StatsThreadInit(StatsThreadContext *stats)
Definition: counters.c:1332
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:154
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:90
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:287
SMTPState_::helo_len
uint16_t helo_len
Definition: app-layer-smtp.h:168
SCConfNodeLookupChild
SCConfNode * SCConfNodeLookupChild(const SCConfNode *node, const char *name)
Lookup a child configuration node by name.
Definition: conf.c:849
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:137
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:156
SCConfGetChildValue
int SCConfGetChildValue(const SCConfNode *base, const char *name, const char **vptr)
Definition: conf.c:389
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:864
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:107
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:159
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:273
SCEnumCharMap_
Definition: util-enum.h:27
SMTPState_::bdat_chunk_len
uint32_t bdat_chunk_len
Definition: app-layer-smtp.h:149
SMTP_DECODER_EVENT_MIME_LONG_FILENAME
@ SMTP_DECODER_EVENT_MIME_LONG_FILENAME
Definition: app-layer-smtp.h: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:3905
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:92
SMTP_PARSER_STATE_PIPELINING_SERVER
#define SMTP_PARSER_STATE_PIPELINING_SERVER
Definition: app-layer-smtp.c:75
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:99
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:173
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:158
str
#define str(s)
Definition: suricata-common.h:313
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:183
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:285
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:118
Flow_::alproto_ts
AppProto alproto_ts
Definition: flow.h:456
SMTP_REPLY_221
@ SMTP_REPLY_221
Definition: app-layer-smtp.c:275
Flow_::alstate
void * alstate
Definition: flow.h:484
SMTPInput_
Definition: app-layer-smtp.c:101
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:303
smtp_reply_map
SCEnumCharMap smtp_reply_map[]
Definition: app-layer-smtp.c:316
detect-parse.h
FILEDATA_CONTENT_INSPECT_WINDOW
#define FILEDATA_CONTENT_INSPECT_WINDOW
Definition: app-layer-smtp.c:57
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:288
MpmInitThreadCtx
void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, MpmCtx *mpm_ctx, uint16_t matcher)
Definition: util-mpm.c:194
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:238
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2873
SMTP_REPLY_451
@ SMTP_REPLY_451
Definition: app-layer-smtp.c:289
SMTP_REPLY_511
@ SMTP_REPLY_511
Definition: app-layer-smtp.c:299
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:46
app-layer-protos.h
SMTP_REPLY_543
@ SMTP_REPLY_543
Definition: app-layer-smtp.c:307
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:295
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:117
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:173
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:194
MpmCtx_
Definition: util-mpm.h:111
TcpSession_
Definition: stream-tcp-private.h:283
SMTPState_::cmds_buffer_len
uint16_t cmds_buffer_len
Definition: app-layer-smtp.h:160
SMTPParserRegisterTests
void SMTPParserRegisterTests(void)
Definition: app-layer-smtp.c: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:455
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:120
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:288
SCConfNode_
Definition: conf.h:37
StatsThreadCleanup
void StatsThreadCleanup(StatsThreadContext *stats)
Definition: counters.c:1428
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:262
SMTP_REPLY_354
@ SMTP_REPLY_354
Definition: app-layer-smtp.c:282
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
SMTPState_::nb_live_tx
uint64_t nb_live_tx
Definition: app-layer-smtp.h:135
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:453