1 //--------------------------------------------------------------------------
2 // Copyright (C) 2015-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation. You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 //--------------------------------------------------------------------------
18
19 // pop.cc author Bhagyashree Bantwal < bbantwal@cisco.com>
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "pop.h"
26
27 #include "detection/detection_engine.h"
28 #include "log/messages.h"
29 #include "profiler/profiler.h"
30 #include "protocols/packet.h"
31 #include "protocols/ssl.h"
32 #include "pub_sub/opportunistic_tls_event.h"
33 #include "search_engines/search_tool.h"
34 #include "stream/stream.h"
35 #include "utils/util_cstring.h"
36
37 #include "pop_module.h"
38 #include "pop_paf.h"
39
40 using namespace snort;
41
42 THREAD_LOCAL ProfileStats popPerfStats;
43 THREAD_LOCAL PopStats popstats;
44
45 POPToken pop_known_cmds[] =
46 {
47 { "APOP", 4, CMD_APOP },
48 { "AUTH", 4, CMD_AUTH },
49 { "CAPA", 4, CMD_CAPA },
50 { "DELE", 4, CMD_DELE },
51 { "LIST", 4, CMD_LIST },
52 { "NOOP", 4, CMD_NOOP },
53 { "PASS", 4, CMD_PASS },
54 { "QUIT", 4, CMD_QUIT },
55 { "RETR", 4, CMD_RETR },
56 { "RSET", 4, CMD_RSET },
57 { "STAT", 4, CMD_STAT },
58 { "STLS", 4, CMD_STLS },
59 { "TOP", 3, CMD_TOP },
60 { "UIDL", 4, CMD_UIDL },
61 { "USER", 4, CMD_USER },
62 { nullptr, 0, 0 }
63 };
64
65 POPToken pop_resps[] =
66 {
67 { "+OK", 3, RESP_OK }, /* SUCCESS */
68 { "-ERR", 4, RESP_ERR }, /* FAILURE */
69 { nullptr, 0, 0 }
70 };
71
72 SearchTool* pop_resp_search_mpse = nullptr;
73 SearchTool* pop_cmd_search_mpse = nullptr;
74
75 POPSearch pop_resp_search[RESP_LAST];
76 POPSearch pop_cmd_search[CMD_LAST];
77
78 static THREAD_LOCAL const POPSearch* pop_current_search = nullptr;
79 static THREAD_LOCAL POPSearchInfo pop_search_info;
80
81 const PegInfo pop_peg_names[] =
82 {
83 { CountType::SUM, "packets", "total packets processed" },
84 { CountType::SUM, "total_bytes", "total number of bytes processed" },
85 { CountType::SUM, "sessions", "total pop sessions" },
86 { CountType::NOW, "concurrent_sessions", "total concurrent pop sessions" },
87 { CountType::MAX, "max_concurrent_sessions", "maximum concurrent pop sessions" },
88 { CountType::SUM, "start_tls", "total STARTTLS events generated" },
89 { CountType::SUM, "ssl_search_abandoned", "total SSL search abandoned" },
90 { CountType::SUM, "ssl_srch_abandoned_early", "total SSL search abandoned too soon" },
91 { CountType::SUM, "b64_attachments", "total base64 attachments decoded" },
92 { CountType::SUM, "b64_decoded_bytes", "total base64 decoded bytes" },
93 { CountType::SUM, "qp_attachments", "total quoted-printable attachments decoded" },
94 { CountType::SUM, "qp_decoded_bytes", "total quoted-printable decoded bytes" },
95 { CountType::SUM, "uu_attachments", "total uu attachments decoded" },
96 { CountType::SUM, "uu_decoded_bytes", "total uu decoded bytes" },
97 { CountType::SUM, "non_encoded_attachments", "total non-encoded attachments extracted" },
98 { CountType::SUM, "non_encoded_bytes", "total non-encoded extracted bytes" },
99
100 { CountType::END, nullptr, nullptr }
101 };
102
103
104 static void snort_pop(POP_PROTO_CONF* GlobalConf, Packet* p);
105 static void POP_ResetState(Flow*);
106
PopFlowData()107 PopFlowData::PopFlowData() : FlowData(inspector_id)
108 {
109 memset(&session, 0, sizeof(session));
110 popstats.concurrent_sessions++;
111 if(popstats.max_concurrent_sessions < popstats.concurrent_sessions)
112 popstats.max_concurrent_sessions = popstats.concurrent_sessions;
113 }
114
~PopFlowData()115 PopFlowData::~PopFlowData()
116 {
117 if (session.mime_ssn)
118 delete(session.mime_ssn);
119
120 assert(popstats.concurrent_sessions > 0);
121 popstats.concurrent_sessions--;
122 }
123
124 unsigned PopFlowData::inspector_id = 0;
get_session_data(Flow * flow)125 static POPData* get_session_data(Flow* flow)
126 {
127 PopFlowData* fd = (PopFlowData*)flow->get_flow_data(PopFlowData::inspector_id);
128 return fd ? &fd->session : nullptr;
129 }
130
SetNewPOPData(POP_PROTO_CONF * config,Packet * p)131 static POPData* SetNewPOPData(POP_PROTO_CONF* config, Packet* p)
132 {
133 POPData* pop_ssn;
134 PopFlowData* fd = new PopFlowData;
135
136 p->flow->set_flow_data(fd);
137 pop_ssn = &fd->session;
138
139 popstats.sessions++;
140 pop_ssn->mime_ssn = new PopMime(p, &(config->decode_conf), &(config->log_config));
141 pop_ssn->mime_ssn->set_mime_stats(&(popstats.mime_stats));
142
143 if (p->packet_flags & SSNFLAG_MIDSTREAM)
144 {
145 pop_ssn->state = STATE_UNKNOWN;
146 }
147
148 return pop_ssn;
149 }
150
POP_SearchInit()151 static void POP_SearchInit()
152 {
153 const POPToken* tmp;
154 if ( pop_cmd_search_mpse )
155 return;
156 pop_cmd_search_mpse = new SearchTool;
157
158 for (tmp = &pop_known_cmds[0]; tmp->name != nullptr; tmp++)
159 {
160 pop_cmd_search[tmp->search_id].name = tmp->name;
161 pop_cmd_search[tmp->search_id].name_len = tmp->name_len;
162 pop_cmd_search_mpse->add(tmp->name, tmp->name_len, tmp->search_id);
163 }
164 pop_cmd_search_mpse->prep();
165 pop_resp_search_mpse = new SearchTool;
166
167 for (tmp = &pop_resps[0]; tmp->name != nullptr; tmp++)
168 {
169 pop_resp_search[tmp->search_id].name = tmp->name;
170 pop_resp_search[tmp->search_id].name_len = tmp->name_len;
171 pop_resp_search_mpse->add(tmp->name, tmp->name_len, tmp->search_id);
172 }
173 pop_resp_search_mpse->prep();
174 }
175
POP_SearchFree()176 static void POP_SearchFree()
177 {
178 if (pop_cmd_search_mpse != nullptr)
179 delete pop_cmd_search_mpse;
180
181 if (pop_resp_search_mpse != nullptr)
182 delete pop_resp_search_mpse;
183 }
184
POP_ResetState(Flow * ssn)185 static void POP_ResetState(Flow* ssn)
186 {
187 POPData* pop_ssn = get_session_data(ssn);
188 pop_ssn->state = STATE_COMMAND;
189 pop_ssn->prev_response = 0;
190 pop_ssn->state_flags = 0;
191 }
192
POP_GetEOL(const uint8_t * ptr,const uint8_t * end,const uint8_t ** eol,const uint8_t ** eolm)193 static void POP_GetEOL(const uint8_t* ptr, const uint8_t* end,
194 const uint8_t** eol, const uint8_t** eolm)
195 {
196 assert(ptr and end and eol and eolm);
197
198 const uint8_t* tmp_eol;
199 const uint8_t* tmp_eolm;
200
201 tmp_eol = (const uint8_t*)memchr(ptr, '\n', end - ptr);
202 if (tmp_eol == nullptr)
203 {
204 tmp_eol = end;
205 tmp_eolm = end;
206 }
207 else
208 {
209 /* end of line marker (eolm) should point to marker and
210 * * end of line (eol) should point to end of marker */
211 if ((tmp_eol > ptr) && (*(tmp_eol - 1) == '\r'))
212 {
213 tmp_eolm = tmp_eol - 1;
214 }
215 else
216 {
217 tmp_eolm = tmp_eol;
218 }
219
220 /* move past newline */
221 tmp_eol++;
222 }
223
224 *eol = tmp_eol;
225 *eolm = tmp_eolm;
226 }
227
InspectPacket(Packet * p)228 static inline int InspectPacket(Packet* p)
229 {
230 return p->has_paf_payload();
231 }
232
POP_Setup(Packet * p,POPData * ssn)233 static int POP_Setup(Packet* p, POPData* ssn)
234 {
235 int pkt_dir;
236
237 /* Get the direction of the packet. */
238 if ( p->is_from_server() )
239 pkt_dir = POP_PKT_FROM_SERVER;
240 else
241 pkt_dir = POP_PKT_FROM_CLIENT;
242
243 if (!(ssn->session_flags & POP_FLAG_CHECK_SSL))
244 ssn->session_flags |= POP_FLAG_CHECK_SSL;
245 /* Check to see if there is a reassembly gap. If so, we won't know
246 * * what state we're in when we get the _next_ reassembled packet */
247 if ((pkt_dir != POP_PKT_FROM_SERVER) &&
248 (p->packet_flags & PKT_REBUILT_STREAM))
249 {
250 int missing_in_rebuilt =
251 Stream::missing_in_reassembled(p->flow, SSN_DIR_FROM_CLIENT);
252
253 if (ssn->session_flags & POP_FLAG_NEXT_STATE_UNKNOWN)
254 {
255 ssn->state = STATE_UNKNOWN;
256 ssn->session_flags &= ~POP_FLAG_NEXT_STATE_UNKNOWN;
257 }
258
259 if (missing_in_rebuilt == SSN_MISSING_BEFORE)
260 {
261 ssn->state = STATE_UNKNOWN;
262 }
263 }
264
265 return pkt_dir;
266 }
267
POP_SearchStrFound(void * id,void *,int index,void *,void *)268 static int POP_SearchStrFound(void* id, void* , int index, void* , void* )
269 {
270 int search_id = (int)(uintptr_t)id;
271
272 pop_search_info.id = search_id;
273 pop_search_info.length = pop_current_search[search_id].name_len;
274 pop_search_info.index = index - pop_search_info.length;
275
276 /* Returning non-zero stops search, which is okay since we only look for one at a time */
277 return 1;
278 }
279
280 /*
281 * Handle COMMAND state
282 *
283 * @param p standard Packet structure
284 * @param ptr pointer into p->data buffer to start looking at data
285 * @param end points to end of p->data buffer
286 *
287 * @return pointer into p->data where we stopped looking at data
288 * will be end of line or end of packet
289 */
POP_HandleCommand(Packet * p,POPData * pop_ssn,const uint8_t * ptr,const uint8_t * end)290 static const uint8_t* POP_HandleCommand(Packet* p, POPData* pop_ssn, const uint8_t* ptr, const
291 uint8_t* end)
292 {
293 const uint8_t* eol; /* end of line */
294 const uint8_t* eolm; /* end of line marker */
295 int cmd_found;
296
297 /* get end of line and end of line marker */
298 POP_GetEOL(ptr, end, &eol, &eolm);
299
300 // FIXIT-M If the end of line marker coincides with the end of data we
301 // can't be sure that we got a command and not a substring which we
302 // could tell through inspection of the next packet. Maybe a command
303 // pending state where the first char in the next packet is checked for
304 // a space and end of line marker
305
306 /* do not confine since there could be space chars before command */
307 pop_current_search = &pop_cmd_search[0];
308 cmd_found = pop_cmd_search_mpse->find(
309 (const char*)ptr, eolm - ptr, POP_SearchStrFound);
310 /* see if we actually found a command and not a substring */
311 if (cmd_found > 0)
312 {
313 const uint8_t* tmp = ptr;
314 const uint8_t* cmd_start = ptr + pop_search_info.index;
315 const uint8_t* cmd_end = cmd_start + pop_search_info.length;
316
317 /* move past spaces up until start of command */
318 while ((tmp < cmd_start) && isspace((int)*tmp))
319 tmp++;
320
321 /* if not all spaces before command, we found a
322 * substring */
323 if (tmp != cmd_start)
324 cmd_found = 0;
325
326 /* if we're before the end of line marker and the next
327 * character is not whitespace, we found a substring */
328 if ((cmd_end < eolm) && !isspace((int)*cmd_end))
329 cmd_found = 0;
330
331 /* there is a chance that end of command coincides with the end of data
332 * in which case, it could be a substring, but for now, we will treat it as found */
333 }
334
335 /* if command not found, alert and move on */
336 if (!cmd_found)
337 {
338 /* check for encrypted */
339 if (pop_ssn->state == STATE_UNKNOWN and
340 pop_ssn->session_flags & POP_FLAG_CHECK_SSL and
341 IsSSL(ptr, end - ptr, p->packet_flags))
342 {
343 pop_ssn->state = STATE_TLS_DATA;
344
345 /* Ignore data */
346 return end;
347 }
348 else
349 {
350 if (pop_ssn->state == STATE_UNKNOWN)
351 {
352 /* don't check for ssl again in this packet */
353 if (pop_ssn->session_flags & POP_FLAG_CHECK_SSL)
354 pop_ssn->session_flags &= ~POP_FLAG_CHECK_SSL;
355
356 pop_ssn->state = STATE_DATA;
357 DetectionEngine::queue_event(GID_POP, POP_UNKNOWN_CMD);
358 return ptr;
359 }
360 DetectionEngine::queue_event(GID_POP, POP_UNKNOWN_CMD);
361 return eol;
362 }
363 }
364 else if (pop_search_info.id == CMD_TOP)
365 {
366 pop_ssn->state = STATE_DATA;
367 }
368 else
369 {
370 if (pop_ssn->state == STATE_UNKNOWN)
371 pop_ssn->state = STATE_COMMAND;
372 }
373
374 if (pop_search_info.id == CMD_STLS)
375 {
376 if (eol == end)
377 pop_ssn->state = STATE_TLS_CLIENT_PEND;
378 }
379
380 return eol;
381 }
382
383 /*
384 * Process client packet
385 *
386 * @param packet standard Packet structure
387 *
388 * @return none
389 */
POP_ProcessClientPacket(Packet * p,POPData * pop_ssn)390 static void POP_ProcessClientPacket(Packet* p, POPData* pop_ssn)
391 {
392 const uint8_t* ptr = p->data;
393 const uint8_t* end = p->data + p->dsize;
394
395 POP_HandleCommand(p, pop_ssn, ptr, end);
396 }
397
398 /*
399 * Process server packet
400 *
401 * @param packet standard Packet structure
402 *
403 */
POP_ProcessServerPacket(Packet * p,POPData * pop_ssn)404 static void POP_ProcessServerPacket(Packet* p, POPData* pop_ssn)
405 {
406 int resp_found;
407 const uint8_t* ptr;
408 const uint8_t* end;
409 const uint8_t* eolm;
410 const uint8_t* eol;
411 int resp_line_len;
412 const char* tmp = nullptr;
413
414 ptr = p->data;
415 end = p->data + p->dsize;
416
417 while (ptr < end)
418 {
419 if (pop_ssn->state == STATE_DATA)
420 {
421 //ptr = POP_HandleData(p, ptr, end);
422 FilePosition position = get_file_position(p);
423 int len = end - ptr;
424 ptr = pop_ssn->mime_ssn->process_mime_data(p, ptr, len, false, position);
425 continue;
426 }
427 POP_GetEOL(ptr, end, &eol, &eolm);
428
429 resp_line_len = eol - ptr;
430
431 /* Check for response code */
432 pop_current_search = &pop_resp_search[0];
433 resp_found = pop_resp_search_mpse->find(
434 (const char*)ptr, resp_line_len, POP_SearchStrFound);
435
436 if (resp_found > 0)
437 {
438 const uint8_t* cmd_start = ptr + pop_search_info.index;
439 switch (pop_search_info.id)
440 {
441 case RESP_OK:
442 tmp = SnortStrcasestr((const char*)cmd_start, (eol - cmd_start), "octets");
443 if (tmp != nullptr)
444 {
445 if (!(pop_ssn->session_flags & POP_FLAG_ABANDON_EVT)
446 and !p->flow->flags.data_decrypted)
447 {
448 pop_ssn->session_flags |= POP_FLAG_ABANDON_EVT;
449 DataBus::publish(SSL_SEARCH_ABANDONED, p);
450 popstats.ssl_search_abandoned++;
451 }
452
453 pop_ssn->state = STATE_DATA;
454 }
455 else if (pop_ssn->state == STATE_TLS_CLIENT_PEND)
456 {
457 if ((pop_ssn->session_flags & POP_FLAG_ABANDON_EVT)
458 and !p->flow->flags.data_decrypted)
459 {
460 popstats.ssl_srch_abandoned_early++;
461 }
462
463 OpportunisticTlsEvent event(p, p->flow->service);
464 DataBus::publish(OPPORTUNISTIC_TLS_EVENT, event, p->flow);
465 popstats.start_tls++;
466 pop_ssn->state = STATE_DECRYPTION_REQ;
467 }
468 else
469 {
470 pop_ssn->prev_response = RESP_OK;
471 pop_ssn->state = STATE_UNKNOWN;
472 }
473 break;
474
475 default:
476 break;
477 }
478 }
479 else
480 {
481 if ((pop_ssn->session_flags & POP_FLAG_CHECK_SSL) &&
482 (IsSSL(ptr, end - ptr, p->packet_flags)))
483 {
484 pop_ssn->state = STATE_TLS_DATA;
485 return;
486 }
487 else if (pop_ssn->session_flags & POP_FLAG_CHECK_SSL)
488 {
489 pop_ssn->session_flags &= ~POP_FLAG_CHECK_SSL;
490 }
491 if (pop_ssn->prev_response == RESP_OK)
492 {
493 {
494 pop_ssn->state = STATE_DATA;
495 pop_ssn->prev_response = 0;
496 continue;
497 }
498 }
499 else if (*ptr == '+')
500 {
501 DetectionEngine::queue_event(GID_POP, POP_UNKNOWN_RESP);
502 }
503 }
504
505 ptr = eol;
506 }
507 }
508
509 // Analyzes POP packets for anomalies/exploits.
510
snort_pop(POP_PROTO_CONF * config,Packet * p)511 static void snort_pop(POP_PROTO_CONF* config, Packet* p)
512 {
513 /* Attempt to get a previously allocated POP block. */
514 POPData* pop_ssn = get_session_data(p->flow);
515
516 if (pop_ssn == nullptr)
517 {
518 /* Check the stream session. If it does not currently
519 * have our POP data-block attached, create one.
520 */
521 pop_ssn = SetNewPOPData(config, p);
522
523 if ( !pop_ssn )
524 {
525 /* Could not get/create the session data for this packet. */
526 return;
527 }
528 }
529
530 popstats.total_bytes += p->dsize;
531 int pkt_dir = POP_Setup(p, pop_ssn);
532
533 if (pkt_dir == POP_PKT_FROM_CLIENT)
534 {
535 /* This packet should be a tls client hello */
536 if ((pop_ssn->state == STATE_TLS_CLIENT_PEND) || (pop_ssn->state == STATE_DECRYPTION_REQ))
537 {
538 if (IsTlsClientHello(p->data, p->data + p->dsize))
539 {
540 pop_ssn->state = STATE_TLS_SERVER_PEND;
541 return;
542 }
543 else
544 {
545 /* reset state - server may have rejected STARTTLS command */
546 pop_ssn->state = STATE_UNKNOWN;
547 }
548 }
549 if ((pop_ssn->state == STATE_TLS_DATA)
550 || (pop_ssn->state == STATE_TLS_SERVER_PEND))
551 {
552 return;
553 }
554 POP_ProcessClientPacket(p, pop_ssn);
555 }
556 else
557 {
558 if (pop_ssn->state == STATE_TLS_SERVER_PEND)
559 {
560 if (IsTlsServerHello(p->data, p->data + p->dsize))
561 {
562 pop_ssn->state = STATE_TLS_DATA;
563 }
564 else if ( !p->test_session_flags(SSNFLAG_MIDSTREAM)
565 && !Stream::missed_packets(p->flow, SSN_DIR_BOTH))
566 {
567 /* revert back to command state - assume server didn't accept STARTTLS */
568 pop_ssn->state = STATE_UNKNOWN;
569 }
570 else
571 return;
572 }
573
574 if (pop_ssn->state == STATE_TLS_DATA)
575 {
576 return;
577 }
578 if ( !InspectPacket(p))
579 {
580 /* Packet will be rebuilt, so wait for it */
581 return;
582 }
583 else if (!(p->packet_flags & PKT_REBUILT_STREAM))
584 {
585 /* If this isn't a reassembled packet and didn't get
586 * inserted into reassembly buffer, there could be a
587 * problem. If we miss syn or syn-ack that had window
588 * scaling this packet might not have gotten inserted
589 * into reassembly buffer because it fell outside of
590 * window, because we aren't scaling it */
591 pop_ssn->session_flags |= POP_FLAG_GOT_NON_REBUILT;
592 pop_ssn->state = STATE_UNKNOWN;
593 }
594 else if (pop_ssn->session_flags & POP_FLAG_GOT_NON_REBUILT)
595 {
596 /* This is a rebuilt packet. If we got previous packets
597 * that were not rebuilt, state is going to be messed up
598 * so set state to unknown. It's likely this was the
599 * beginning of the conversation so reset state */
600 pop_ssn->state = STATE_UNKNOWN;
601 pop_ssn->session_flags &= ~POP_FLAG_GOT_NON_REBUILT;
602 }
603 /* Process as a server packet */
604 POP_ProcessServerPacket(p, pop_ssn);
605 }
606 }
607
decode_alert()608 void PopMime::decode_alert()
609 {
610 switch ( decode_state->get_decode_type() )
611 {
612 case DECODE_B64:
613 DetectionEngine::queue_event(GID_POP, POP_B64_DECODING_FAILED);
614 break;
615 case DECODE_QP:
616 DetectionEngine::queue_event(GID_POP, POP_QP_DECODING_FAILED);
617 break;
618 case DECODE_UU:
619 DetectionEngine::queue_event(GID_POP, POP_UU_DECODING_FAILED);
620 break;
621
622 default:
623 break;
624 }
625 }
626
decompress_alert()627 void PopMime::decompress_alert()
628 {
629 DetectionEngine::queue_event(GID_POP, POP_FILE_DECOMP_FAILED);
630 }
631
reset_state(Flow * ssn)632 void PopMime::reset_state(Flow* ssn)
633 {
634 POP_ResetState(ssn);
635 }
636
637
is_end_of_data(Flow * session)638 bool PopMime::is_end_of_data(Flow* session)
639 {
640 return pop_is_data_end(session);
641 }
642
643 //-------------------------------------------------------------------------
644 // class stuff
645 //-------------------------------------------------------------------------
646
647 class Pop : public Inspector
648 {
649 public:
650 Pop(POP_PROTO_CONF*);
651 ~Pop() override;
652
653 bool configure(SnortConfig*) override;
654 void show(const SnortConfig*) const override;
655 void eval(Packet*) override;
656
get_splitter(bool c2s)657 StreamSplitter* get_splitter(bool c2s) override
658 { return new PopSplitter(c2s); }
659
can_carve_files() const660 bool can_carve_files() const override
661 { return true; }
662
can_start_tls() const663 bool can_start_tls() const override
664 { return true; }
665
666 bool get_buf(InspectionBuffer::Type, Packet*, InspectionBuffer&) override;
667 bool get_fp_buf(snort::InspectionBuffer::Type ibt, snort::Packet* p,
668 snort::InspectionBuffer& b) override;
669
670 private:
671 POP_PROTO_CONF* config;
672 };
673
Pop(POP_PROTO_CONF * pc)674 Pop::Pop(POP_PROTO_CONF* pc)
675 {
676 config = pc;
677 }
678
~Pop()679 Pop::~Pop()
680 {
681 if ( config )
682 delete config;
683 }
684
configure(SnortConfig *)685 bool Pop::configure(SnortConfig* )
686 {
687 config->decode_conf.sync_all_depths();
688
689 if (config->decode_conf.get_file_depth() > -1)
690 config->log_config.log_filename = true;
691
692 POP_SearchInit();
693 return true;
694 }
695
show(const SnortConfig *) const696 void Pop::show(const SnortConfig*) const
697 {
698 if ( config )
699 config->decode_conf.show();
700 }
701
eval(Packet * p)702 void Pop::eval(Packet* p)
703 {
704 Profile profile(popPerfStats);
705
706 // precondition - what we registered for
707 assert(p->has_tcp_data());
708 assert(p->flow);
709
710 ++popstats.packets;
711
712 snort_pop(config, p);
713 }
714
get_buf(InspectionBuffer::Type ibt,Packet * p,InspectionBuffer & b)715 bool Pop::get_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b)
716 {
717 // Fast pattern buffers only supplied at specific times
718 switch (ibt)
719 {
720 case InspectionBuffer::IBT_VBA:
721 {
722 POPData* pop_ssn = get_session_data(p->flow);
723
724 if (!pop_ssn)
725 return false;
726
727 const BufferData& vba_buf = pop_ssn->mime_ssn->get_vba_inspect_buf();
728
729 if (vba_buf.data_ptr() && vba_buf.length())
730 {
731 b.data = vba_buf.data_ptr();
732 b.len = vba_buf.length();
733 return true;
734 }
735 else
736 return false;
737 }
738
739 default:
740 break;
741 }
742 return false;
743 }
744
get_fp_buf(InspectionBuffer::Type ibt,Packet * p,InspectionBuffer & b)745 bool Pop::get_fp_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b)
746 {
747 return get_buf(ibt, p, b);
748 }
749
750 //-------------------------------------------------------------------------
751 // api stuff
752 //-------------------------------------------------------------------------
753
mod_ctor()754 static Module* mod_ctor()
755 { return new PopModule; }
756
mod_dtor(Module * m)757 static void mod_dtor(Module* m)
758 { delete m; }
759
pop_init()760 static void pop_init()
761 {
762 PopFlowData::init();
763 }
764
pop_term()765 static void pop_term()
766 {
767 POP_SearchFree();
768 }
769
pop_ctor(Module * m)770 static Inspector* pop_ctor(Module* m)
771 {
772 PopModule* mod = (PopModule*)m;
773 return new Pop(mod->get_data());
774 }
775
pop_dtor(Inspector * p)776 static void pop_dtor(Inspector* p)
777 {
778 delete p;
779 }
780
781 const InspectApi pop_api =
782 {
783 {
784 PT_INSPECTOR,
785 sizeof(InspectApi),
786 INSAPI_VERSION,
787 0,
788 API_RESERVED,
789 API_OPTIONS,
790 POP_NAME,
791 POP_HELP,
792 mod_ctor,
793 mod_dtor
794 },
795 IT_SERVICE,
796 PROTO_BIT__PDU,
797 nullptr, // buffers
798 "pop3",
799 pop_init,
800 pop_term, // pterm
801 nullptr, // tinit
802 nullptr, // tterm
803 pop_ctor,
804 pop_dtor,
805 nullptr, // ssn
806 nullptr // reset
807 };
808
809 #ifdef BUILDING_SO
810 SO_PUBLIC const BaseApi* snort_plugins[] =
811 {
812 &pop_api.base,
813 nullptr
814 };
815 #else
816 const BaseApi* sin_pop = &pop_api.base;
817 #endif
818
819