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