LCOV - code coverage report
Current view: top level - src - POP3.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 195 437 44.6 %
Date: 2010-12-13 Functions: 16 23 69.6 %
Branches: 102 304 33.6 %

           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 :         }

Generated by: LCOV version 1.8