Branch data Line data Source code
1 : : // $Id: POP3.cc 6782 2009-06-28 02:19:03Z vern $
2 : :
3 : : // This code contributed to Bro by Florian Schimandl, Hugh Dollman and
4 : : // Robin Sommer.
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <stdlib.h>
9 : : #include <iostream>
10 : : #include <vector>
11 : : #include <string>
12 : : #include <ctype.h>
13 : :
14 : : #include "NetVar.h"
15 : : #include "POP3.h"
16 : : #include "Event.h"
17 : : #include "NVT.h"
18 : :
19 : : #undef POP3_CMD_DEF
20 : : #define POP3_CMD_DEF(cmd) #cmd,
21 : :
22 : : static const char* pop3_cmd_word[] = {
23 : : #include "POP3_cmd.def"
24 : : };
25 : :
26 : : #define POP3_CMD_WORD(code) ((code >= 0) ? pop3_cmd_word[code] : "(UNKNOWN)")
27 : :
28 : :
29 : 5 : POP3_Analyzer::POP3_Analyzer(Connection* conn)
30 : 5 : : TCP_ApplicationAnalyzer(AnalyzerTag::POP3, conn)
31 : : {
32 : 5 : masterState = POP3_START;
33 : 5 : subState = POP3_WOK;
34 : 5 : state = START;
35 : 5 : lastState = START;
36 : :
37 : 5 : guessing = false;
38 : 5 : waitingForAuthentication = false;
39 : 5 : requestForMultiLine = false;
40 : 5 : multiLine = false;
41 : 5 : backOff = false;
42 : :
43 : 5 : mail = 0;
44 : :
45 : 5 : AddSupportAnalyzer(new ContentLine_Analyzer(conn, true));
46 : 5 : AddSupportAnalyzer(new ContentLine_Analyzer(conn, false));
47 : 5 : }
48 : :
49 : 5 : POP3_Analyzer::~POP3_Analyzer()
50 : : {
51 [ + - ][ # # ]: 5 : }
[ # # ]
52 : :
53 : 5 : void POP3_Analyzer::Done()
54 : : {
55 : 5 : TCP_ApplicationAnalyzer::Done();
56 : :
57 [ - + ]: 5 : if ( mail )
58 : 0 : EndData();
59 : 5 : }
60 : :
61 : :
62 : 969 : void POP3_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
63 : : {
64 : 969 : TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
65 : :
66 [ + - + - ]: 969 : if ( (TCP() && TCP()->IsPartial()) || backOff )
[ - + ][ + - ]
67 : 969 : return;
68 : :
69 : 969 : BroString terminated_string(data, len, 1);
70 : :
71 [ + + ]: 969 : if ( orig )
72 : 25 : ProcessRequest(len, (char*) terminated_string.Bytes());
73 : : else
74 : 969 : ProcessReply(len, (char*) terminated_string.Bytes());
75 : : }
76 : :
77 : 966 : static string trim_whitespace(const char* in)
78 : : {
79 : 966 : int n = strlen(in);
80 : 966 : char out[n];
81 : 966 : char* out_p = out;
82 : :
83 : 966 : in = skip_whitespace(in);
84 : :
85 [ + + ]: 15923 : while ( *in )
86 : : {
87 : : // It might be better to use isspace() here, but the
88 : : // original code just compared with ' '.
89 [ + + ]: 14961 : if ( *in == ' ' )
90 : : {
91 : : // See if there is any following character.
92 : 1245 : ++in;
93 [ + + ][ + + ]: 1253 : while ( *in && *in == ' ' )
94 : 8 : ++in;
95 : :
96 [ + + ]: 1245 : if ( ! *in )
97 : 4 : break;
98 : :
99 : : // There's a following character, so put in a
100 : : // single blank to represent the ones we
101 : : // compressed out.
102 : 1241 : *(out_p++) = ' ';
103 : : }
104 : :
105 : : // If we get this far, then we have a non-blank
106 : : // character to copy.
107 : 14957 : *(out_p++) = *(in++);
108 : : }
109 : :
110 : 966 : *out_p = 0;
111 : :
112 : 966 : return string(out);
113 : : }
114 : :
115 : 25 : void POP3_Analyzer::ProcessRequest(int length, const char* line)
116 : : {
117 [ - + ]: 25 : if ( waitingForAuthentication )
118 : : {
119 : 0 : ++authLines;
120 : :
121 : 0 : BroString encoded(line);
122 : 0 : BroString* decoded = decode_base64(&encoded);
123 : :
124 [ # # ]: 0 : if ( ! decoded )
125 : : {
126 : 0 : Weird("pop3_bad_base64_encoding");
127 : : return;
128 : : }
129 : :
130 [ # # # # : 0 : switch ( state ) {
# ]
131 : : case AUTH_LOGIN:
132 : : // Format: Line 1 - User
133 : : // Line 2 - Password
134 [ # # ]: 0 : if ( authLines == 1 )
135 : 0 : user = decoded->CheckString();
136 : :
137 [ # # ]: 0 : else if ( authLines == 2 )
138 : 0 : password = decoded->CheckString();
139 : :
140 : 0 : break;
141 : :
142 : : case AUTH_PLAIN:
143 : : {
144 : : // Format: "authorization identity<NUL>authentication
145 : : // identity<NUL>password"
146 : 0 : char* str = (char*) decoded->Bytes();
147 : 0 : int len = decoded->Len();
148 : 0 : char* end = str + len;
149 : : char* s;
150 : : char* e;
151 : :
152 [ # # ][ # # ]: 0 : for ( s = str; s < end && *s; ++s )
153 : : ;
154 : 0 : ++s;
155 : :
156 [ # # ][ # # ]: 0 : for ( e = s; e < end && *e; ++e )
157 : : ;
158 : :
159 [ # # ]: 0 : if ( e >= end )
160 : : {
161 : 0 : Weird("pop3_malformed_auth_plain");
162 : 0 : return;
163 : : }
164 : :
165 : 0 : user = s;
166 : 0 : s = e + 1;
167 : :
168 [ # # ]: 0 : if ( s >= end )
169 : : {
170 : 0 : Weird("pop3_malformed_auth_plain");
171 : : return;
172 : : }
173 : :
174 : 0 : char tmp[len]; // more than enough
175 : 0 : int n = len - (s - str);
176 : 0 : memcpy(tmp, s, n);
177 : 0 : tmp[n] = '\0';
178 [ # # ]: 0 : password = tmp;
179 : :
180 : 0 : break;
181 : : }
182 : :
183 : : case AUTH_CRAM_MD5:
184 : : { // Format: "user<space>password-hash"
185 : : char* s;
186 : 0 : char* str = (char*) decoded->CheckString();
187 : :
188 [ # # ][ # # ]: 0 : for ( s = str; *s && *s != '\t' && *s != ' '; ++s )
[ # # ]
189 : : ;
190 : 0 : *s = '\0';
191 : :
192 : 0 : user = str;
193 : 0 : password = "";
194 : :
195 : 0 : break;
196 : : }
197 : :
198 : : case AUTH:
199 : 0 : break;
200 : :
201 : : default:
202 : 0 : internal_error("unexpected authorization state");
203 : : }
204 : :
205 [ # # ][ # # ]: 0 : delete decoded;
206 : : }
207 : :
208 : : else
209 : : {
210 : : // Some clients pipeline their commands (i.e., keep sending
211 : : // without waiting for a server's responses). Therefore we
212 : : // keep a list of pending commands.
213 : 25 : cmds.push_back(string(line));
214 : :
215 [ + + ]: 25 : if ( cmds.size() == 1 )
216 : : // Not waiting for another server response,
217 : : // so we can process it immediately.
218 : 25 : ProcessClientCmd();
219 : : }
220 : :
221 : : }
222 : :
223 [ + + ]: 63 : static string commands[] = {
224 : : "OK", "ERR", "USER", "PASS", "APOP", "AUTH",
225 : : "STAT", "LIST", "RETR", "DELE", "RSET", "NOOP", "LAST", "QUIT",
226 : : "TOP", "CAPA", "UIDL", "STLS", "XSENDER",
227 [ # # ][ # # ]: 3 : };
228 : :
229 : 0 : void POP3_Analyzer::NotAllowed(const char* cmd, const char* state)
230 : : {
231 : : POP3Event(pop3_unexpected, true, cmd,
232 : 0 : fmt("not allowed in other state than '%s'", state));
233 : 0 : }
234 : :
235 : 43 : void POP3_Analyzer::ProcessClientCmd()
236 : : {
237 [ + + ]: 43 : if ( ! cmds.size() )
238 : 21 : return;
239 : :
240 : 22 : string str = trim_whitespace(cmds.front().c_str());
241 : 22 : vector<string> tokens = TokenizeLine(str, ' ');
242 : :
243 : 22 : int cmd_code = -1;
244 : 22 : const char* cmd = "";
245 : :
246 [ + - ]: 22 : if ( tokens.size() > 0 )
247 : 22 : cmd_code = ParseCmd(tokens[0]);
248 : :
249 [ - + ]: 22 : if ( cmd_code == -1 )
250 : : {
251 [ # # ]: 0 : if ( ! waitingForAuthentication )
252 : : {
253 : 0 : Weird("pop3_client_command_unknown");
254 [ # # ]: 0 : if ( subState == POP3_WOK )
255 : 0 : subState = POP3_OK;
256 : : }
257 : 43 : return;
258 : : }
259 : :
260 : 22 : cmd = commands[cmd_code].c_str();
261 : :
262 [ + + ]: 22 : const char* message = tokens.size() > 1 ? tokens[1].c_str() : "";
263 : :
264 [ - + + - - : 22 : switch ( cmd_code ) {
+ - - - -
- - + - -
- + - - ]
265 : : case POP3_CMD_ERR:
266 : : case POP3_CMD_OK:
267 : 0 : Weird("pop3_client_sending_server_commands");
268 : 0 : break;
269 : :
270 : : case POP3_CMD_USER:
271 [ + - ]: 4 : if ( masterState == POP3_AUTHORIZATION )
272 : : {
273 : 4 : POP3Event(pop3_request, true, cmd, message);
274 : 4 : state = USER;
275 : 4 : subState = POP3_WOK;
276 : 4 : user = message;
277 : : }
278 : : else
279 : 0 : NotAllowed(cmd, "authorization");
280 : 4 : break;
281 : :
282 : : case POP3_CMD_PASS:
283 [ + - ]: 4 : if ( masterState == POP3_AUTHORIZATION )
284 : : {
285 [ + - ]: 4 : if ( state == USER )
286 : : {
287 : 4 : POP3Event(pop3_request, true, cmd, message);
288 : 4 : state = PASS;
289 : 4 : subState = POP3_WOK;
290 : 4 : password = message;
291 : : }
292 : : else
293 : : POP3Event(pop3_unexpected, true, cmd,
294 : 4 : "pass must follow the command 'USER'");
295 : : }
296 : : else
297 : 0 : NotAllowed(cmd, "authorization");
298 : 4 : break;
299 : :
300 : : case POP3_CMD_APOP:
301 [ # # ]: 0 : if ( masterState == POP3_AUTHORIZATION )
302 : : {
303 : 0 : POP3Event(pop3_request, true, cmd, message);
304 : 0 : state = APOP;
305 : 0 : subState = POP3_WOK;
306 : :
307 : 0 : char* arg1 = copy_string(message);
308 : : char* e;
309 [ # # ][ # # ]: 0 : for ( e = arg1; *e && *e != ' ' && *e != '\t'; ++e )
[ # # ]
310 : : ;
311 : 0 : *e = '\0';
312 : 0 : user = arg1;
313 [ # # ]: 0 : delete [] arg1;
314 : : }
315 : : else
316 : 0 : NotAllowed(cmd, "authorization");
317 : 0 : break;
318 : :
319 : : case POP3_CMD_AUTH:
320 [ # # ]: 0 : if ( masterState == POP3_AUTHORIZATION )
321 : : {
322 : 0 : POP3Event(pop3_request, true, cmd, message);
323 [ # # ]: 0 : if ( ! *message )
324 : : {
325 : 0 : requestForMultiLine = true;
326 : 0 : state = AUTH;
327 : 0 : subState = POP3_WOK;
328 : : }
329 : : else
330 : : {
331 [ # # ]: 0 : if ( strstr(message, "LOGIN") )
332 : 0 : state = AUTH_LOGIN;
333 [ # # ]: 0 : else if ( strstr(message, "PLAIN") )
334 : 0 : state = AUTH_PLAIN;
335 [ # # ]: 0 : else if ( strstr(message, "CRAM-MD5") )
336 : 0 : state = AUTH_CRAM_MD5;
337 : : else
338 : : {
339 : 0 : state = AUTH;
340 : : POP3Event(pop3_unexpected, true, cmd,
341 : 0 : fmt("unknown AUTH method %s", message));
342 : : }
343 : :
344 : 0 : subState = POP3_WOK;
345 : 0 : waitingForAuthentication = true;
346 : 0 : authLines = 0;
347 : : }
348 : : }
349 : : else
350 : : POP3Event(pop3_unexpected, true, cmd,
351 : 0 : "pass must follow the command 'USER'");
352 : 0 : break;
353 : :
354 : : case POP3_CMD_STAT:
355 [ + - ]: 4 : if ( masterState == POP3_TRANSACTION )
356 : : {
357 : 4 : POP3Event(pop3_request, true, cmd, message);
358 : 4 : subState = POP3_WOK;
359 : 4 : state = STAT;
360 : : }
361 : : else
362 : 0 : NotAllowed(cmd, "transaction");
363 : 4 : break;
364 : :
365 : : case POP3_CMD_LIST:
366 [ # # ]: 0 : if ( masterState == POP3_TRANSACTION )
367 : : {
368 : 0 : POP3Event(pop3_request, true, cmd, message);
369 [ # # ]: 0 : if ( ! *message )
370 : : {
371 : 0 : requestForMultiLine = true;
372 : 0 : state = LIST;
373 : 0 : subState = POP3_WOK;
374 : : }
375 : : else
376 : : {
377 : 0 : state = LIST;
378 : 0 : subState = POP3_WOK;
379 : : }
380 : : }
381 : : else
382 : : {
383 [ # # ]: 0 : if ( ! *message )
384 : 0 : requestForMultiLine = true;
385 : :
386 : 0 : guessing = true;
387 : 0 : lastState = LIST;
388 : 0 : NotAllowed(cmd, "transaction");
389 : : }
390 : 0 : break;
391 : :
392 : : case POP3_CMD_RETR:
393 : 0 : requestForMultiLine = true;
394 [ # # ]: 0 : if ( masterState == POP3_TRANSACTION )
395 : : {
396 : 0 : POP3Event(pop3_request, true, cmd, message);
397 : 0 : subState = POP3_WOK;
398 : 0 : state = RETR;
399 : : }
400 : : else
401 : : {
402 : 0 : guessing = true;
403 : 0 : lastState = RETR;
404 : 0 : NotAllowed(cmd, "transaction");
405 : : }
406 : 0 : break;
407 : :
408 : : case POP3_CMD_DELE:
409 [ # # ]: 0 : if ( masterState == POP3_TRANSACTION )
410 : : {
411 : 0 : POP3Event(pop3_request, true, cmd, message);
412 : 0 : subState = POP3_WOK;
413 : 0 : state = DELE;
414 : : }
415 : : else
416 : : {
417 : 0 : guessing = true;
418 : 0 : lastState = DELE;
419 : 0 : NotAllowed(cmd, "transaction");
420 : : }
421 : 0 : break;
422 : :
423 : : case POP3_CMD_RSET:
424 [ # # ]: 0 : if ( masterState == POP3_TRANSACTION )
425 : : {
426 : 0 : POP3Event(pop3_request, true, cmd, message);
427 : 0 : subState = POP3_WOK;
428 : 0 : state = RSET;
429 : : }
430 : : else
431 : : {
432 : 0 : guessing = true;
433 : 0 : lastState = RSET;
434 : 0 : NotAllowed(cmd, "transaction");
435 : : }
436 : 0 : break;
437 : :
438 : : case POP3_CMD_NOOP:
439 [ # # ]: 0 : if ( masterState == POP3_TRANSACTION )
440 : : {
441 : 0 : POP3Event(pop3_request, true, cmd, message);
442 : 0 : subState = POP3_WOK;
443 : 0 : state = NOOP;
444 : : }
445 : : else
446 : : {
447 : 0 : guessing = true;
448 : 0 : lastState = NOOP;
449 : 0 : NotAllowed(cmd, "transaction");
450 : : }
451 : 0 : break;
452 : :
453 : : case POP3_CMD_LAST:
454 [ # # ]: 0 : if ( masterState == POP3_TRANSACTION )
455 : : {
456 : 0 : POP3Event(pop3_request, true, cmd, message);
457 : 0 : subState = POP3_WOK;
458 : 0 : state = LAST;
459 : : }
460 : : else
461 : : {
462 : 0 : guessing = true;
463 : 0 : lastState = LAST;
464 : 0 : NotAllowed(cmd, "transaction");
465 : : }
466 : 0 : break;
467 : :
468 : : case POP3_CMD_QUIT:
469 [ + - ][ - + ]: 6 : if ( masterState == POP3_AUTHORIZATION ||
[ # # ]
470 : : masterState == POP3_TRANSACTION ||
471 : : masterState == POP3_START )
472 : : {
473 : 3 : POP3Event(pop3_request, true, cmd, message);
474 : 3 : subState = POP3_WOK;
475 : 3 : state = QUIT;
476 : : }
477 : : else
478 : : {
479 : 0 : guessing = true;
480 : 0 : lastState = LAST;
481 : 0 : NotAllowed(cmd, "transaction");
482 : : }
483 : 3 : break;
484 : :
485 : : case POP3_CMD_TOP:
486 : 0 : requestForMultiLine = true;
487 : :
488 [ # # ]: 0 : if ( masterState == POP3_TRANSACTION )
489 : : {
490 : 0 : POP3Event(pop3_request, true, cmd, message);
491 : 0 : subState = POP3_WOK;
492 : 0 : state = TOP;
493 : : }
494 : : else
495 : : {
496 : 0 : guessing = true;
497 : 0 : lastState = TOP;
498 : 0 : NotAllowed(cmd, "transaction");
499 : : }
500 : 0 : break;
501 : :
502 : : case POP3_CMD_CAPA:
503 : 0 : POP3Event(pop3_request, true, cmd, message);
504 : 0 : subState = POP3_WOK;
505 : 0 : state = CAPA;
506 : 0 : requestForMultiLine = true;
507 : 0 : break;
508 : :
509 : : case POP3_CMD_STLS:
510 : 0 : POP3Event(pop3_request, true, cmd, message);
511 : 0 : subState = POP3_WOK;
512 : 0 : state = STLS;
513 : 0 : break;
514 : :
515 : : case POP3_CMD_UIDL:
516 [ + - ]: 7 : if ( masterState == POP3_TRANSACTION )
517 : : {
518 : 7 : POP3Event(pop3_request, true, cmd, message);
519 [ + + ]: 7 : if ( ! *message )
520 : : {
521 : 1 : requestForMultiLine = true;
522 : 1 : state = UIDL;
523 : 1 : subState = POP3_WOK;
524 : : }
525 : : else
526 : : {
527 : 6 : state = UIDL;
528 : 7 : subState = POP3_WOK;
529 : : }
530 : : }
531 : : else
532 : : {
533 [ # # ]: 0 : if ( ! *message )
534 : 0 : requestForMultiLine = true;
535 : :
536 : 0 : guessing = true;
537 : 0 : lastState = UIDL;
538 : 0 : NotAllowed(cmd, "transaction");
539 : : }
540 : 7 : break;
541 : :
542 : : case POP3_CMD_XSENDER:
543 [ # # ]: 0 : if ( masterState == POP3_TRANSACTION )
544 : : {
545 : 0 : POP3Event(pop3_request, true, cmd, message);
546 : 0 : subState = POP3_WOK;
547 : 0 : state = LAST;
548 : : }
549 : : else
550 : : {
551 : 0 : guessing = true;
552 : 0 : lastState = XSENDER;
553 : 0 : NotAllowed(cmd, "transaction");
554 : : }
555 : 0 : break;
556 : :
557 : : default:
558 : 22 : internal_error("command not known");
559 [ - + ][ - + ]: 22 : }
560 : : }
561 : :
562 : 25 : void POP3_Analyzer::FinishClientCmd()
563 : : {
564 [ + + ]: 25 : if ( ! cmds.size() )
565 : 4 : return;
566 : :
567 : 21 : cmds.pop_front();
568 : 25 : ProcessClientCmd();
569 : : }
570 : :
571 : 944 : void POP3_Analyzer::ProcessReply(int length, const char* line)
572 : : {
573 : 944 : const char* end_of_line = line + length;
574 : 944 : string str = trim_whitespace(line);
575 : :
576 [ + + ]: 944 : if ( multiLine == true )
577 : : {
578 : : bool terminator =
579 : : length > 1 && line[0] == '.' &&
580 : : (line[1] == '\n' ||
581 [ + + ][ - + ]: 918 : (length > 2 && line[1] == '\r' && line[2] == '\n'));
[ # # ][ # # ]
[ # # ][ # # ]
582 : :
583 [ - + ]: 918 : if ( terminator )
584 : : {
585 : 0 : requestForMultiLine = false;
586 : 0 : multiLine = false;
587 [ # # ]: 0 : if ( mail )
588 : 0 : EndData();
589 : 0 : FinishClientCmd();
590 : : }
591 : : else
592 : : {
593 [ + - ][ - + ]: 918 : if ( state == RETR || state == TOP )
594 : : {
595 : 0 : int data_len = end_of_line - line;
596 : 0 : ProcessData(data_len, line);
597 : : }
598 : :
599 : : // ### It can be quite costly doing this per-line
600 : : // as opposed to amortized over large packets that
601 : : // contain many lines.
602 : 918 : POP3Event(pop3_data, false, str.c_str());
603 : : }
604 : 944 : return;
605 : : }
606 : :
607 : 26 : int cmd_code = -1;
608 : 26 : const char* cmd = "";
609 : :
610 : 26 : vector<string> tokens = TokenizeLine(str, ' ');
611 [ + - ]: 26 : if ( tokens.size() > 0 )
612 : 26 : cmd_code = ParseCmd(tokens[0]);
613 : :
614 [ - + ]: 26 : if ( cmd_code == -1 )
615 : : {
616 [ # # ]: 0 : if ( ! waitingForAuthentication )
617 : : {
618 : : ProtocolViolation(fmt("unknown server command (%s)",
619 : : (tokens.size() > 0 ?
620 : : tokens[0].c_str() :
621 : : "???")),
622 [ # # ]: 0 : line, length);
623 : :
624 : 0 : Weird("pop3_server_command_unknown");
625 [ # # ]: 0 : if ( subState == POP3_WOK )
626 : 0 : subState = POP3_OK;
627 : : }
628 : : return;
629 : : }
630 : :
631 : 26 : cmd = commands[cmd_code].c_str();
632 : :
633 [ + + ]: 26 : const char* message = tokens.size() > 1 ? tokens[1].c_str() : "";
634 : :
635 [ + - - ]: 26 : switch ( cmd_code ) {
636 : : case POP3_CMD_OK:
637 [ + - ]: 26 : if ( subState == POP3_WOK )
638 : 26 : subState = POP3_OK;
639 : :
640 [ - + ]: 26 : if ( guessing )
641 : : {
642 : 0 : masterState = POP3_TRANSACTION;
643 : 0 : guessing = false;
644 : 0 : state = lastState;
645 : : POP3Event(pop3_unexpected, false, cmd,
646 : 0 : "no auth required -> state changed to 'transaction'");
647 : : }
648 : :
649 [ + + + - - : 26 : switch ( state ) {
+ - + - ]
650 : : case START:
651 : 4 : masterState = POP3_AUTHORIZATION;
652 : 4 : break;
653 : :
654 : : case USER:
655 : 4 : state = USER;
656 : 4 : masterState = POP3_AUTHORIZATION;
657 : 4 : ProtocolConfirmation();
658 : 4 : break;
659 : :
660 : : case PASS:
661 : : case APOP:
662 : : case NOOP:
663 : : case LAST:
664 : : case STAT:
665 : : case RSET:
666 : : case DELE:
667 : : case XSENDER:
668 [ + + ]: 8 : if ( masterState == POP3_AUTHORIZATION )
669 : 4 : AuthSuccessfull();
670 : 8 : masterState = POP3_TRANSACTION;
671 : 8 : break;
672 : :
673 : : case AUTH:
674 : : case AUTH_PLAIN:
675 : : case AUTH_CRAM_MD5:
676 : : case AUTH_LOGIN:
677 [ # # ]: 0 : if ( requestForMultiLine == true )
678 : 0 : multiLine = true;
679 [ # # ]: 0 : if ( waitingForAuthentication )
680 : 0 : masterState = POP3_TRANSACTION;
681 : 0 : waitingForAuthentication = false;
682 : 0 : AuthSuccessfull();
683 : 0 : break;
684 : :
685 : : case TOP:
686 : : case RETR:
687 : : {
688 : 0 : int data_len = end_of_line - line;
689 [ # # ]: 0 : if ( ! mail )
690 : 0 : BeginData();
691 : 0 : ProcessData(data_len, line);
692 [ # # ]: 0 : if ( requestForMultiLine == true )
693 : 0 : multiLine = true;
694 : 0 : break;
695 : : }
696 : :
697 : : case UIDL:
698 : : case LIST:
699 : : case CAPA:
700 [ + + ]: 7 : if (requestForMultiLine == true)
701 : 1 : multiLine = true;
702 : 7 : break;
703 : :
704 : : case STLS:
705 : 0 : backOff = true;
706 : 0 : POP3Event(pop3_terminate, false, "Terminating due to TLS");
707 : : return;
708 : :
709 : : case QUIT:
710 [ + - ][ - + ]: 3 : if ( masterState == POP3_AUTHORIZATION ||
711 : : masterState == POP3_START )
712 : 0 : masterState = POP3_FINISHED;
713 : :
714 [ + - ]: 3 : else if ( masterState == POP3_TRANSACTION )
715 : 3 : masterState = POP3_UPDATE;
716 : :
717 : : break;
718 : : }
719 : :
720 : 26 : POP3Event(pop3_reply, false, cmd, message);
721 : : // no else part, ignoring multiple OKs
722 : :
723 [ + + ]: 26 : if ( ! multiLine )
724 : 25 : FinishClientCmd();
725 : 26 : break;
726 : :
727 : : case POP3_CMD_ERR:
728 [ # # ]: 0 : if ( subState == POP3_WOK )
729 : 0 : subState = POP3_OK;
730 : :
731 : 0 : multiLine = false;
732 : 0 : requestForMultiLine = false;
733 : 0 : guessing = false;
734 : 0 : waitingForAuthentication = false;
735 : :
736 [ # # # # # : 0 : switch ( state ) {
# ]
737 : : case START:
738 : 0 : break;
739 : :
740 : : case USER:
741 : : case PASS:
742 : : case APOP:
743 : : case AUTH:
744 : : case AUTH_LOGIN:
745 : : case AUTH_PLAIN:
746 : : case AUTH_CRAM_MD5:
747 : 0 : masterState = POP3_AUTHORIZATION;
748 : 0 : state = START;
749 : 0 : waitingForAuthentication = false;
750 : :
751 [ # # ]: 0 : if ( user.size() )
752 : : POP3Event(pop3_login_failure, false,
753 : 0 : user.c_str(), password.c_str());
754 : 0 : break;
755 : :
756 : : case NOOP:
757 : : case LAST:
758 : : case STAT:
759 : : case RSET:
760 : : case DELE:
761 : : case LIST:
762 : : case RETR:
763 : : case UIDL:
764 : : case TOP:
765 : : case XSENDER:
766 : 0 : masterState = POP3_TRANSACTION;
767 : 0 : break;
768 : :
769 : : case CAPA:
770 : 0 : break;
771 : :
772 : : case QUIT:
773 [ # # ][ # # ]: 0 : if ( masterState == POP3_AUTHORIZATION ||
[ # # ]
774 : : masterState == POP3_TRANSACTION ||
775 : : masterState == POP3_START )
776 : 0 : masterState = POP3_FINISHED;
777 : : break;
778 : : }
779 : :
780 : 0 : POP3Event(pop3_reply, false, cmd, message);
781 : :
782 [ # # ]: 0 : if ( ! multiLine )
783 : 0 : FinishClientCmd();
784 : 0 : break;
785 : :
786 : : default:
787 : 26 : Weird("pop3_server_sending_client_commands");
788 : : break;
789 [ - + ][ + + ]: 944 : }
790 : : }
791 : :
792 : 4 : void POP3_Analyzer::AuthSuccessfull()
793 : : {
794 [ + - ]: 4 : if ( user.size() )
795 : : POP3Event(pop3_login_success, false,
796 : 4 : user.c_str(), password.c_str());
797 : 4 : }
798 : :
799 : 0 : void POP3_Analyzer::BeginData()
800 : : {
801 [ # # ]: 0 : delete mail;
802 : 0 : mail = new MIME_Mail(this);
803 : 0 : }
804 : :
805 : 0 : void POP3_Analyzer::EndData()
806 : : {
807 [ # # ]: 0 : if ( ! mail )
808 : 0 : warn("unmatched end of data");
809 : : else
810 : : {
811 : 0 : mail->Done();
812 [ # # ]: 0 : delete mail;
813 : 0 : mail = 0;
814 : : }
815 : 0 : }
816 : :
817 : 0 : void POP3_Analyzer::ProcessData(int length, const char* line)
818 : : {
819 : 0 : mail->Deliver(length, line, 1);
820 : 0 : }
821 : :
822 : 48 : int POP3_Analyzer::ParseCmd(string cmd)
823 : : {
824 [ - + ]: 48 : if ( cmd.size() == 0 )
825 : 0 : return -1;
826 : :
827 [ + - ]: 243 : for ( int code = POP3_CMD_OK; code <= POP3_CMD_END; ++code )
828 : : {
829 : 243 : char c = cmd.c_str()[0];
830 [ + + - + ]: 243 : if ( c == '+' || c == '-' )
831 : 26 : cmd = cmd.substr(1);
832 : :
833 [ + + ]: 1163 : for ( unsigned int i = 0; i < cmd.size(); ++i )
834 : 920 : cmd[i] = toupper(cmd[i]);
835 : :
836 [ + + ]: 243 : if ( ! cmd.compare(pop3_cmd_word[code]) )
837 : 48 : return code;
838 : : }
839 : :
840 : 48 : return -1;
841 : : }
842 : :
843 : 48 : vector<string> POP3_Analyzer::TokenizeLine(const string input, const char split)
844 : : {
845 : 48 : vector<string> tokens;
846 : :
847 [ + - ]: 48 : if ( input.size() < 1 )
848 : 48 : return tokens;
849 : :
850 : 48 : int start = 0;
851 : 48 : unsigned int splitPos = 0;
852 : 48 : string token = "";
853 : :
854 [ + + ]: 48 : if ( input.find(split, 0) == string::npos )
855 : : {
856 : 11 : tokens.push_back(input);
857 : 48 : return tokens;
858 : : }
859 : :
860 [ + - ]: 37 : if ( (splitPos = input.find(split, 0)) < input.size() )
861 : : {
862 : 37 : token = input.substr(start, splitPos);
863 [ + - + - ]: 37 : if ( token.size() > 0 && token[0] != split )
[ + - ]
864 : 37 : tokens.push_back(token);
865 : :
866 : 37 : token = input.substr(splitPos+1, input.size() - splitPos);
867 : 37 : tokens.push_back(token);
868 : : }
869 : :
870 : 48 : return tokens;
871 : : }
872 : :
873 : : void POP3_Analyzer::POP3Event(EventHandlerPtr event, bool is_orig,
874 : 970 : const char* arg1, const char* arg2)
875 : : {
876 [ + + ]: 970 : if ( ! event )
877 : 918 : return;
878 : :
879 : 52 : val_list* vl = new val_list;
880 : :
881 : 52 : vl->append(BuildConnVal());
882 : 52 : vl->append(new Val(is_orig, TYPE_BOOL));
883 [ + - ]: 52 : if ( arg1 )
884 : 52 : vl->append(new StringVal(arg1));
885 [ + - ]: 52 : if ( arg2 )
886 : 52 : vl->append(new StringVal(arg2));
887 : :
888 : 970 : ConnectionEvent(event, vl);
889 [ + - ][ + - ]: 6 : }
|