Guest User

SMTPConnection.cpp

a guest
Dec 26th, 2013
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 70.39 KB | None | 0 0
  1. // Copyright (c) 2005 Martin Knafve / hMailServer.com.  
  2. // http://www.hmailserver.com
  3.  
  4.  
  5. #include "stdafx.h"
  6. #include "../common/bo/Messages.h"
  7. #include "../common/bo/MessageData.h"
  8.  
  9. #include "../common/Cache/CacheContainer.h"
  10. #include "../common/Util/PasswordValidator.h"
  11. #include "../common/Util/AccountLogon.h"
  12. #include "../common/persistence/PersistentMessage.h"
  13. #include "../common/persistence/PersistentAccount.h"
  14. #include "../common/BO/Message.h"
  15. #include "../common/Mime/MimeCode.h"
  16. #include "../common/Mime/Mime.h"
  17. #include "../common/util/MessageUtilities.h"
  18. #include "../common/util/Utilities.h"
  19. #include "../common/util/File.h"
  20. #include "../common/util/Time.h"
  21. #include "../common/Application/ClientINfo.h"
  22. #include "../common/AntiSpam/SpamTestResult.h"
  23. #include "../Common/UTil/Math.h"
  24. #include "../Common/UTil/SignatureAdder.h"
  25. #include "../common/BO/Routes.h"
  26. #include "../common/BO/RouteAddresses.h"
  27. #include "../common/BO/SecurityRange.h"
  28. #include "../common/BO/MessageRecipient.h"
  29. #include "../common/BO/MessageRecipients.h"
  30. #include "../Common/Util/ByteBuffer.h"
  31. #include "../Common/Util/ServerStatus.h"
  32. #include "../Common/Util/AWstats.h"
  33. #include "../Common/Util/TransparentTransmissionBuffer.h"
  34. #include "../Common/Application/ObjectCache.h"
  35. #include "../Common/Application/DefaultDomain.h"
  36. #include "../Common/Application/SessionManager.h"
  37. #include "../Common/Cache/MessageCache.h"
  38. #include "../Common/BO/DomainAliases.h"
  39. #include "../Common/BO/Account.h"
  40. #include "../Common/BO/Domains.h"
  41. #include "../Common/BO/Domain.h"
  42.  
  43. #include "../Common/BO/Collection.h"
  44. #include "../common/persistence/PersistentDomain.h"
  45.  
  46. #include "../common/Threading/AsynchronousTask.h"
  47. #include "../common/Threading/WorkQueue.h"
  48.  
  49. #include "SMTPConnection.h"
  50. #include "SMTPConfiguration.h"
  51. #include "SMTPDeliveryManager.h"
  52.  
  53. #include "../Common/AntiSpam/AntiSpamConfiguration.h"
  54. #include "../Common/AntiSpam/SpamProtection.h"
  55.  
  56. #include "../Common/Application/TimeoutCalculator.h"
  57. #include "../Common/Application/ScriptingHost/ScriptServer.h"
  58. #include "../Common/Application/ScriptingHost/ScriptObjectContainer.h"
  59. #include "../Common/Application/ScriptingHost/Result.h"
  60.  
  61. #include "../Common/Application/IniFileSettings.h"
  62.  
  63. using namespace std;
  64.  
  65. #ifdef _DEBUG
  66. #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
  67. #define new DEBUG_NEW
  68. #endif
  69.  
  70. namespace HM
  71. {
  72.    SMTPConnection::SMTPConnection() :  
  73.       m_bRejectedByDelayedGreyListing(false),
  74.       m_CurrentState(AUTHENTICATION),
  75.       m_bTraceHeadersWritten(true),
  76.       _requestedAuthenticationType(AUTH_NONE),
  77.       m_iMaxMessageSizeKB(0),
  78.       m_iCurNoOfRCPTTO(0),
  79.       m_iCurNoOfInvalidCommands(0),
  80.       m_bReAuthenticateUser(false),
  81.       m_spType(SPNone),
  82.       m_bPendingDisconnect(false),
  83.       _isAuthenticated(false)
  84.    {
  85.       m_SMTPConf = Configuration::Instance()->GetSMTPConfiguration();
  86.  
  87.       /* RFC 2821:    
  88.          An SMTP server SHOULD have a timeout of at least 5 minutes while it
  89.          is awaiting the next command from the sender.
  90.  
  91.          Since the DATA command has a timeout on 10 minutes, we can just
  92.          as well set the entire timeout to 10.
  93.  
  94.          Under very high load, the timeout will decrease below the values specified
  95.          by the RFC. The reasoning is that it's better to disconnect slow clients
  96.          than it is to disconnect everyone.
  97.       */
  98.  
  99.       TimeoutCalculator calculator;
  100.       SetTimeout(calculator.Calculate(IniFileSettings::Instance()->GetSMTPDMinTimeout(), IniFileSettings::Instance()->GetSMTPDMaxTimeout()));
  101. //      SetTimeout(calculator.Calculate(10, 30 * 60));
  102.    }
  103.  
  104.    SMTPConnection::~SMTPConnection()
  105.    {
  106.        LOG_DEBUG("SMTPConnection::~SMTPConnection");
  107.       _ResetCurrentMessage();
  108.  
  109.       SessionManager::Instance()->OnDisconnect(STSMTP);
  110.    }
  111.  
  112.    void
  113.    SMTPConnection::OnConnected()
  114.    {
  115.       String sWelcome = Configuration::Instance()->GetSMTPConfiguration()->GetWelcomeMessage();
  116.  
  117.       String sData = "220 ";
  118.  
  119.       if (sWelcome.IsEmpty())
  120.          sData += Utilities::ComputerName() + " ESMTP";
  121.       else
  122.          sData += sWelcome;
  123.  
  124.       LOG_DEBUG("SENT BANNER");
  125.       _SendData(sData);
  126.  
  127.       PostReceive();
  128.    }
  129.  
  130.    AnsiString
  131.    SMTPConnection::GetCommandSeparator() const
  132.    {
  133.       return "\r\n";
  134.    }
  135.  
  136.    eSMTPCommandTypes
  137.    SMTPConnection::_GetCommandType(const String &sFirstWord)
  138.    {
  139.       if (sFirstWord == _T("HELO"))
  140.          return SMTP_COMMAND_HELO;
  141.       else if (sFirstWord == _T("HELP"))
  142.          return SMTP_COMMAND_HELP;
  143.       else if (sFirstWord == _T("QUIT"))
  144.          return SMTP_COMMAND_QUIT;
  145.       else if (sFirstWord == _T("EHLO"))
  146.          return SMTP_COMMAND_EHLO;
  147.       else if (sFirstWord == _T("AUTH"))
  148.          return SMTP_COMMAND_AUTH;
  149.       else if (sFirstWord == _T("MAIL"))
  150.          return SMTP_COMMAND_MAIL;
  151.       else if (sFirstWord == _T("RCPT"))
  152.          return SMTP_COMMAND_RCPT;
  153.       else if (sFirstWord == _T("TURN"))
  154.          return SMTP_COMMAND_TURN;
  155.       else if (sFirstWord == _T("VRFY"))
  156.          return SMTP_COMMAND_VRFY;
  157.       else if (sFirstWord == _T("DATA"))
  158.          return SMTP_COMMAND_DATA;
  159.       else if (sFirstWord == _T("RSET"))
  160.          return SMTP_COMMAND_RSET;
  161.       else if (sFirstWord == _T("NOOP"))
  162.          return SMTP_COMMAND_NOOP;
  163.       else if (sFirstWord == _T("ETRN"))
  164.          return SMTP_COMMAND_ETRN;
  165.       else if (sFirstWord == _T("STARTTLS"))
  166.          return SMTP_COMMAND_STARTTLS;
  167.  
  168.       return SMTP_COMMAND_UNKNOWN;
  169.    }
  170.  
  171.    void
  172.    SMTPConnection::_LogClientCommand(const String &sClientData) const
  173.    //---------------------------------------------------------------------------()
  174.    // DESCRIPTION:
  175.    // Logs one client command.
  176.    //---------------------------------------------------------------------------()
  177.    {
  178.       if (Logger::Instance()->GetLogSMTP())
  179.       {
  180.  
  181.          String sLogData = sClientData;
  182.  
  183.          if (m_CurrentState == SMTPUSERNAME && _requestedAuthenticationType == AUTH_PLAIN)
  184.          {
  185.             // Both user name and password in line.
  186.             sLogData = "***";
  187.  
  188.             String sAuthentication;
  189.             StringParser::Base64Decode(sClientData, sAuthentication);
  190.  
  191.             // Extract the username and password from the decoded string.
  192.             int iSecondTab = sAuthentication.Find(_T("\t"),1);
  193.             if (iSecondTab > 0)
  194.             {
  195.                String username = sAuthentication.Mid(0, iSecondTab);
  196.  
  197.  
  198.                sLogData = username + " ***";
  199.             }
  200.          }
  201.          else if (m_CurrentState == SMTPUPASSWORD)
  202.          {
  203.             sLogData = "***";
  204.          }        
  205.          
  206.          // Append
  207.          sLogData = "RECEIVED: " + sLogData;
  208.          sLogData.Replace(_T("\r\n"), _T("[nl]"));
  209.  
  210.          LOG_SMTP(GetSessionID(), GetIPAddressString(), sLogData);      
  211.       }
  212.    }
  213.  
  214.    void
  215.    SMTPConnection::ParseData(const AnsiString &sRequest)
  216.    {
  217.       InternalParseData(sRequest);
  218.  
  219.       if (m_bPendingDisconnect == false)
  220.       {
  221.          if (m_CurrentState == DATA)
  222.             PostBufferReceive();
  223.          else
  224.             PostReceive();
  225.       }
  226.    }
  227.  
  228.    void
  229.    SMTPConnection::InternalParseData(const AnsiString &sRequest)
  230.    //---------------------------------------------------------------------------()
  231.    // DESCRIPTION:
  232.    // Parses a clients SMTP command in ASCII mode.
  233.    //---------------------------------------------------------------------------()
  234.    {
  235.       _LogClientCommand(sRequest);
  236.  
  237.       if (sRequest.GetLength() > 510)
  238.       {
  239.          // This line is to long... is this an evil user?
  240.          _SendData("500 Line to long.");
  241.          return;
  242.       }
  243.  
  244.       int lFirstSpace = sRequest.Find(" ");
  245.       String sFirstWord;
  246.       if (lFirstSpace > -1)
  247.          sFirstWord = sRequest.Mid(0,lFirstSpace);
  248.       else
  249.          sFirstWord = sRequest;
  250.  
  251.       sFirstWord.MakeUpper();
  252.  
  253.       if (Configuration::Instance()->GetDisconnectInvalidClients() &&
  254.           m_iCurNoOfInvalidCommands > Configuration::Instance()->GetMaximumIncorrectCommands())
  255.       {
  256.          // Disconnect
  257.          _SendData("Too many invalid commands. Bye!");
  258.          m_bPendingDisconnect = true;
  259.          PostDisconnect();
  260.          return;
  261.       }
  262.  
  263.       eSMTPCommandTypes eCommandType = _GetCommandType(sFirstWord);
  264.  
  265.       // The following commands are independent of state.
  266.       switch (eCommandType)
  267.       {
  268.       case SMTP_COMMAND_HELP:
  269.          {
  270.             _ProtocolHELP();
  271.             return;
  272.          }
  273.       case SMTP_COMMAND_EHLO:
  274.          {
  275.             _ProtocolEHLO(sRequest);
  276.             return;
  277.          }
  278.       case SMTP_COMMAND_HELO:
  279.          {
  280.             _ProtocolHELO(sRequest);
  281.             return;
  282.          }
  283.       case SMTP_COMMAND_QUIT:
  284.          {
  285.             _ProtocolQUIT();
  286.             return;
  287.          }
  288.       case SMTP_COMMAND_NOOP:
  289.          {
  290.             _ProtocolNOOP();
  291.             return;
  292.          }
  293.       case SMTP_COMMAND_RSET:
  294.          {
  295.             _ProtocolRSET();
  296.             return;
  297.          }
  298.       }
  299.  
  300.       if (m_CurrentState == AUTHENTICATION)
  301.       {      
  302.          _requestedAuthenticationType = AUTH_NONE;
  303.          _SendErrorResponse(502, "Use HELO/EHLO first.");
  304.          return;
  305.       }
  306.       else if (m_CurrentState == SMTPUSERNAME)
  307.       {
  308.          if (_requestedAuthenticationType == AUTH_LOGIN)
  309.          {
  310.             StringParser::Base64Decode(sRequest, m_sUsername);
  311.             String sEncoded;
  312.             StringParser::Base64Encode("Password:", sEncoded);
  313.             _SendData("334 " + sEncoded);
  314.             m_CurrentState = SMTPUPASSWORD;
  315.          }
  316.          else
  317.          {
  318.             _AuthenticateUsingPLAIN(sRequest);
  319.          }
  320.  
  321.          return;
  322.  
  323.       }
  324.       else if (m_CurrentState == SMTPUPASSWORD)
  325.       {
  326.          if (_requestedAuthenticationType == AUTH_LOGIN)
  327.             StringParser::Base64Decode(sRequest, m_sPassword);
  328.          else if (_requestedAuthenticationType == AUTH_PLAIN)
  329.             m_sPassword = sRequest;
  330.  
  331.          _Authenticate();
  332.  
  333.          return;
  334.  
  335.       }
  336.       else if (m_CurrentState == HEADER)
  337.       {
  338.          if (eCommandType == SMTP_COMMAND_AUTH)
  339.          {
  340.             _ProtocolAUTH(sRequest);
  341.             return;
  342.          }
  343.          else if (eCommandType == SMTP_COMMAND_MAIL)
  344.          {
  345.             _ProtocolMAIL(sRequest);
  346.             return;
  347.          }
  348.          else if (eCommandType == SMTP_COMMAND_RCPT)
  349.          {
  350.             _ProtocolRCPT(sRequest);
  351.             return;
  352.          }
  353.          else if (eCommandType == SMTP_COMMAND_TURN)
  354.          {
  355.             _SendData("502 TURN disallowed.");
  356.          
  357.             return;
  358.          }
  359.          else if (eCommandType == SMTP_COMMAND_ETRN)
  360.          {
  361.             _ProtocolETRN(sRequest);
  362.          
  363.             return;
  364.          }
  365.          else if (eCommandType == SMTP_COMMAND_STARTTLS){
  366.             _SendData("200  2.0.0 Ready to start TLS");
  367.             usingStartTLS = true;
  368.             StartTLS();        
  369.             return;
  370.          }
  371.  
  372.          else if (eCommandType == SMTP_COMMAND_VRFY)
  373.          {
  374.             _SendData("502 VRFY disallowed.");
  375.          
  376.             return;
  377.          }
  378.          else if (eCommandType == SMTP_COMMAND_DATA)
  379.          {
  380.    
  381.             if (!m_pCurrentMessage)
  382.             {
  383.                // User tried to send a mail without specifying a correct mail from or rcpt to.
  384.                _SendData("503 Must have sender and recipient first.");
  385.            
  386.                return;
  387.             }  
  388.             else if ( m_pCurrentMessage->GetRecipients()->GetCount() == 0)
  389.             {
  390.                // User tried to send a mail without specifying a correct mail from or rcpt to.
  391.                _SendData("503 Must have sender and recipient first.");
  392.            
  393.                return;
  394.             }  
  395.  
  396.             // Let's add an event call on DATA so we can act on reception during SMTP conversation..
  397.             if (Configuration::Instance()->GetUseScriptServer())
  398.             {
  399.                shared_ptr<ScriptObjectContainer> pContainer = shared_ptr<ScriptObjectContainer>(new ScriptObjectContainer);
  400.                shared_ptr<Result> pResult = shared_ptr<Result>(new Result);
  401.                shared_ptr<ClientInfo> pClientInfo = shared_ptr<ClientInfo>(new ClientInfo);
  402.  
  403.                pClientInfo->SetUsername(m_sUsername);
  404.                pClientInfo->SetIPAddress(GetIPAddressString());
  405.                pClientInfo->SetPort(GetLocalPort());
  406.                pClientInfo->SetHELO(m_sHeloHost);
  407.  
  408.                pContainer->AddObject("HMAILSERVER_MESSAGE", m_pCurrentMessage, ScriptObject::OTMessage);
  409.                pContainer->AddObject("HMAILSERVER_CLIENT", pClientInfo, ScriptObject::OTClient);
  410.                pContainer->AddObject("Result", pResult, ScriptObject::OTResult);
  411.  
  412.                String sEventCaller = "OnSMTPData(HMAILSERVER_CLIENT, HMAILSERVER_MESSAGE)";
  413.                ScriptServer::Instance()->FireEvent(ScriptServer::EventOnSMTPData, sEventCaller, pContainer);
  414.  
  415.                switch (pResult->GetValue())
  416.                {
  417.                case 1:
  418.                   {
  419.                      String sErrorMessage = "554 Rejected";
  420.                      _SendData(sErrorMessage);
  421.                      _LogAwstatsMessageRejected();
  422.                      return;
  423.                   }
  424.                case 2:
  425.                   {
  426.                      String sErrorMessage = "554 " + pResult->GetMessage();
  427.                      _SendData(sErrorMessage);
  428.                      _LogAwstatsMessageRejected();
  429.                      return;
  430.                   }
  431.                case 3:
  432.                   {
  433.                      String sErrorMessage = "453 " + pResult->GetMessage();
  434.                      _SendData(sErrorMessage);
  435.                      _LogAwstatsMessageRejected();
  436.                      return;
  437.                   }
  438.                }
  439.             }      
  440.  
  441.             m_CurrentState = DATA;
  442.  
  443.             m_pTransmissionBuffer = shared_ptr<TransparentTransmissionBuffer>(new TransparentTransmissionBuffer(false));
  444.             m_pTransmissionBuffer->Initialize(PersistentMessage::GetFileName(m_pCurrentMessage));
  445.             m_pTransmissionBuffer->SetMaxSizeKB(m_iMaxMessageSizeKB);
  446.  
  447.             SetReceiveBinary(true);
  448.             m_bTraceHeadersWritten = true;
  449.             m_lMessageStartTC = GetTickCount();
  450.  
  451.             _SendData("354 OK, send.");
  452.  
  453.             return;
  454.          }
  455.       }
  456.  
  457.       _SendErrorResponse(502, "Unimplemented command.");
  458.  
  459.       return;
  460.    }
  461.  
  462.    void
  463.    SMTPConnection::_InitializeSpamProtectionType(const String &sFromAddress)
  464.    {
  465.       // Check if spam protection is enabled for this IP address.
  466.       if (!GetSecurityRange()->GetSpamProtection() ||
  467.            SpamProtection::IsWhiteListed(sFromAddress, GetIPAddress()))
  468.       {
  469.          m_spType = SPNone;
  470.          return;
  471.       }
  472.  
  473.       shared_ptr<IncomingRelays> incomingRelays = Configuration::Instance()->GetSMTPConfiguration()->GetIncomingRelays();
  474.       // Check if we should do it before or after data transfer
  475.       if (incomingRelays->IsIncomingRelay(GetIPAddress()))
  476.          m_spType = SPPostTransmission;
  477.       else
  478.          m_spType = SPPreTransmission;
  479.    }
  480.  
  481.    void
  482.    SMTPConnection::_ProtocolNOOP()
  483.    {
  484.       _SendData("250 OK");
  485.    }
  486.  
  487.    void
  488.    SMTPConnection::_ProtocolRSET()
  489.    {
  490.        LOG_DEBUG("SMTPConnection::_ProtocolRSET");
  491.       _ResetCurrentMessage();
  492.  
  493.       _SendData("250 OK");
  494.  
  495.       return;
  496.    }
  497.  
  498.    bool
  499.    SMTPConnection::_ProtocolMAIL(const String &Request)
  500.    {
  501.       if (m_pCurrentMessage)
  502.       {
  503.          _SendData("503 Issue a reset if you want to start over");
  504.          return 0;
  505.       }
  506.      
  507.       if (Request.GetLength() < 10)
  508.       {
  509.          _SendErrorResponse(550, "Invalid syntax. Syntax should be MAIL FROM:<userdomain>[crlf]");
  510.          return 0;
  511.       }
  512.  
  513.       if (!Request.StartsWith(_T("MAIL FROM:")))
  514.       {
  515.          _SendErrorResponse(550, "Invalid syntax. Syntax should be MAIL FROM:<userdomain>[crlf]");
  516.          return 0;
  517.       }
  518.  
  519.       // Parse the contents of the MAIL FROM: command
  520.       String sMailFromParameters = Request.Mid(10).Trim();
  521.       String sFromAddress;
  522.  
  523.       std::vector<String> vecParams = StringParser::SplitString(sMailFromParameters, " ");
  524.       std::vector<String>::iterator iterParam = vecParams.begin();
  525.  
  526.       if (iterParam != vecParams.end())
  527.       {
  528.          if (!_TryExtractAddress((*iterParam), sFromAddress))
  529.          {
  530.             _SendErrorResponse(550, "Invalid syntax. Syntax should be MAIL FROM:<userdomain>[crlf]");
  531.             return 0;
  532.          }        
  533.  
  534.          iterParam++;
  535.       }
  536.  
  537.       sFromAddress = DefaultDomain::ApplyDefaultDomain(sFromAddress);
  538.  
  539.       if (!CheckIfValidSenderAddress(sFromAddress))
  540.          return false;
  541.  
  542.       // Parse the extensions
  543.       String sAuthParam;
  544.       int iEstimatedMessageSize = 0;
  545.       while (iterParam != vecParams.end())
  546.       {
  547.          String sParam = (*iterParam);
  548.          if (sParam.Left(4).CompareNoCase(_T("SIZE")) == 0)
  549.             iEstimatedMessageSize = _ttoi(sParam.Mid(5));
  550.          if (sParam.Left(5).CompareNoCase(_T("AUTH")) == 0)
  551.             sAuthParam = sParam.Mid(5);
  552.  
  553.          iterParam++;
  554.       }
  555.  
  556.       // Initialize spam protection now when we know the sender address.
  557.       _InitializeSpamProtectionType(sFromAddress);
  558.  
  559.       // Apply domain name aliases to this domain name.
  560.       shared_ptr<DomainAliases> pDA = ObjectCache::Instance()->GetDomainAliases();
  561.       const String sAccountAddress = pDA->ApplyAliasesOnAddress(sFromAddress);
  562.  
  563.       // Pre-transmission spam protection.
  564.       if (m_spType == SPPreTransmission)
  565.       {
  566.          if (IniFileSettings::Instance()->GetDNSBLChecksAfterMailFrom())
  567.          {
  568.             // The message is not arriving from a white listed host or a host
  569.             // which is configured to be a forwarding relay. This means that
  570.             // we can start spam protection now.
  571.  
  572.             if (!_DoSpamProtection(SPPreTransmission, sFromAddress, m_sHeloHost, GetIPAddress()))
  573.                return false;
  574.          }
  575.       }
  576.  
  577.       try
  578.       {
  579.          m_pSenderDomain = CacheContainer::Instance()->GetDomain(StringParser::ExtractDomain(sAccountAddress));
  580.          m_pSenderAccount = CacheContainer::Instance()->GetAccount(sAccountAddress);
  581.       }
  582.       catch (...)
  583.       {
  584.          ErrorManager::Instance()->ReportError(ErrorManager::Medium, 10001, "SMTPConnection::_ProtocolMAIL", "Exception 1");
  585.          throw;
  586.       }
  587.          
  588.  
  589.       try
  590.       {
  591.          // Check the max size
  592.          m_iMaxMessageSizeKB = _GetMaxMessageSize(m_pSenderDomain);
  593.  
  594.          // Check if estimated message size exceedes our
  595.          // maximum message size (according to RFC1653)
  596.          if (m_iMaxMessageSizeKB > 0 &&
  597.              iEstimatedMessageSize / 1024 > m_iMaxMessageSizeKB)
  598.          {
  599.             // Message to big. Reject it.
  600.             String sMessage;
  601.             sMessage.Format(_T("552 Message size exceeds fixed maximum message size. Size: %d KB, Max size: %d KB"),
  602.                   iEstimatedMessageSize / 1024, m_iMaxMessageSizeKB);
  603.             _SendData(sMessage);
  604.             return false;
  605.          }
  606.       }
  607.       catch (...)
  608.       {
  609.          ErrorManager::Instance()->ReportError(ErrorManager::Medium, 10002, "SMTPConnection::_ProtocolMAIL", "Exception 2");
  610.          throw;
  611.       }
  612.      
  613.       try
  614.       {
  615.          if (m_bReAuthenticateUser && !ReAuthenticateUser())
  616.             return false;
  617.       }
  618.       catch (...)
  619.       {
  620.          ErrorManager::Instance()->ReportError(ErrorManager::Medium, 10003, "SMTPConnection::_ProtocolMAIL", "Exception 3");
  621.          throw;
  622.       }
  623.            
  624.  
  625.       try
  626.       {
  627.          // Next time we do a mail from, we should re-authenticate the login credentials
  628.          m_bReAuthenticateUser = true;
  629.  
  630.          m_pCurrentMessage = shared_ptr<Message> (new Message);
  631.          m_pCurrentMessage->SetFromAddress(sFromAddress);
  632.          m_pCurrentMessage->SetState(Message::Delivering);
  633.       }
  634.       catch (...)
  635.       {
  636.          ErrorManager::Instance()->ReportError(ErrorManager::Medium, 10004, "SMTPConnection::_ProtocolMAIL", "Exception 4");
  637.          throw;
  638.       }
  639.      
  640.       try
  641.       {
  642.          _SendData("250 OK");
  643.       }
  644.       catch (...)
  645.       {
  646.          ErrorManager::Instance()->ReportError(ErrorManager::Medium, 10005, "SMTPConnection::_ProtocolMAIL", "Exception 5");
  647.          throw;
  648.       }      
  649.    
  650.       return 0;
  651.    }
  652.  
  653.    bool
  654.    SMTPConnection::ReAuthenticateUser()
  655.    {
  656.       if (!_isAuthenticated)
  657.       {
  658.          // Nothing to re-authenticate
  659.          return true;
  660.       }
  661.          
  662.       shared_ptr<const Account> pAccount = PasswordValidator::ValidatePassword(m_sUsername, m_sPassword);
  663.      
  664.       if (pAccount)
  665.          return true;
  666.          
  667.       // Reset login credentials
  668.       _ResetLoginCredentials();      
  669.  
  670.       _SendErrorResponse(550, "Login credentials no longer valid. Please re-authenticate.");                      
  671.      
  672.       return false;
  673.    }
  674.  
  675.    bool
  676.    SMTPConnection::CheckIfValidSenderAddress(const String &sFromAddress)
  677.    {
  678.       if (sFromAddress.IsEmpty())
  679.       {
  680.          // The user is trying to send an e-mail without
  681.          // specifying an email address. Should we allow this?
  682.          if (!m_SMTPConf->GetAllowMailFromNull())
  683.          {
  684.             // Nope, we should'nt... We send the below text even
  685.             // though RFC 822 tells us not to...
  686.             _SendErrorResponse(550, "Sender address must be specified.");            
  687.             return false;
  688.          }
  689.       }
  690.       else
  691.       {
  692.          if (!StringParser::IsValidEmailAddress(sFromAddress))
  693.          {
  694.             // The address is not valid...
  695.             _SendErrorResponse(550, "The address is not valid.");
  696.             return false;
  697.          }
  698.       }
  699.  
  700.       return true;
  701.    }
  702.  
  703.    void
  704.    SMTPConnection::_ProtocolRCPT(const String &Request)
  705.    {
  706.       m_iCurNoOfRCPTTO ++;
  707.  
  708.       if (!m_pCurrentMessage)
  709.       {
  710.          _SendData("503 must have sender first.");
  711.          return;
  712.       }
  713.  
  714.       if (!Request.StartsWith(_T("RCPT TO:")))
  715.       {
  716.          _SendErrorResponse(550, "Invalid syntax. Syntax should be RCPT TO:<userdomain>[crlf]");
  717.          return;
  718.       }
  719.  
  720.       String sRecipientAddress;
  721.  
  722.       if (!_TryExtractAddress(Request.Mid(8), sRecipientAddress))
  723.       {
  724.          _SendErrorResponse(550, "Invalid syntax. Syntax should be RCPT TO:<userdomain>[crlf]");
  725.          return;
  726.       }
  727.  
  728.       sRecipientAddress = DefaultDomain::ApplyDefaultDomain(sRecipientAddress);
  729.  
  730.       if (!StringParser::IsValidEmailAddress(sRecipientAddress))
  731.       {
  732.          // The address is not valid...
  733.          _SendErrorResponse(550, "A valid address is required.");
  734.          return;
  735.       }
  736.  
  737.       if (m_pCurrentMessage->GetRecipients()->GetCount() >= MaxNumberOfRecipients)
  738.       {
  739.          // The user has added too many recipients for this message. Let's not try
  740.          // to deliver it.
  741.          _SendErrorResponse(550, "Too many recipients.");
  742.          return;
  743.       }
  744.  
  745.  
  746.       String sErrMsg = "";
  747.       bool localDelivery = false;
  748.      
  749.       RecipientParser::DeliveryPossibility dp = _recipientParser.CheckDeliveryPossibility(_isAuthenticated, m_pCurrentMessage->GetFromAddress(), sRecipientAddress, sErrMsg, localDelivery, 0);
  750.  
  751.       if (dp != RecipientParser::DP_Possible)
  752.       {
  753.          AWStats::LogDeliveryFailure(GetIPAddressString(), m_pCurrentMessage->GetFromAddress(), sRecipientAddress, 550);
  754.          _SendData(sErrMsg);
  755.  
  756.          return;
  757.       }
  758.  
  759.       bool localSender = _GetIsLocalSender();
  760.  
  761.       bool authenticationRequired = true;
  762.       if (localSender && localDelivery)
  763.          authenticationRequired = GetSecurityRange()->GetRequireSMTPAuthLocalToLocal();
  764.       else if (localSender && !localDelivery)
  765.          authenticationRequired = GetSecurityRange()->GetRequireSMTPAuthLocalToExternal();
  766.       else if (!localSender && localDelivery)
  767.          authenticationRequired = GetSecurityRange()->GetRequireSMTPAuthExternalToLocal();
  768.       else if (!localSender && !localDelivery)
  769.          authenticationRequired = GetSecurityRange()->GetRequireSMTPAuthExternalToExternal();
  770.  
  771.       // If the user is local but not authenticated, maybe we should do SMTP authentication.
  772.       if (authenticationRequired && !_isAuthenticated)
  773.       {
  774.          // Authentication is required, but the user hasn't authenticated.
  775.          _SendErrorResponse(530, "SMTP authentication is required.");
  776.          AWStats::LogDeliveryFailure(GetIPAddressString(), m_pCurrentMessage->GetFromAddress(), sRecipientAddress, 530);
  777.          return;
  778.       }
  779.  
  780.       int iRelayOption = 0;
  781.       if (localSender && localDelivery)
  782.          iRelayOption = SecurityRange::IPRANGE_RELAY_LOCAL_TO_LOCAL;
  783.       else if (localSender && !localDelivery)
  784.          iRelayOption = SecurityRange::IPRANGE_RELAY_LOCAL_TO_REMOTE;
  785.       else if (!localSender && localDelivery)
  786.          iRelayOption = SecurityRange::IPRANGE_RELAY_REMOTE_TO_LOCAL;
  787.       else if (!localSender && !localDelivery)
  788.          iRelayOption = SecurityRange::IPRANGE_RELAY_REMOTE_TO_REMOTE;
  789.  
  790.       bool bAllowRelay = GetSecurityRange()->GetAllowOption(iRelayOption);
  791.          
  792.       if (bAllowRelay == false)
  793.       {
  794.          // User is not allowed to send this email.
  795.          _SendErrorResponse(550, "Delivery is not allowed to this address.");
  796.          AWStats::LogDeliveryFailure(GetIPAddressString(), m_pCurrentMessage->GetFromAddress(), sRecipientAddress, 550);
  797.          return;
  798.       }
  799.  
  800.  
  801.       // Pre-transmission spam protection.
  802.       if (m_spType == SPPreTransmission)
  803.       {
  804.          if (!IniFileSettings::Instance()->GetDNSBLChecksAfterMailFrom())
  805.          {
  806.             // The message is not arriving from a white listed host or a host
  807.             // which is configured to be a forwarding relay. This means that
  808.             // we can start spam protection now.
  809.  
  810.             if (!_DoSpamProtection(SPPreTransmission, m_pCurrentMessage->GetFromAddress(), m_sHeloHost, GetIPAddress()))
  811.             {
  812.                AWStats::LogDeliveryFailure(GetIPAddressString(), m_pCurrentMessage->GetFromAddress(), sRecipientAddress, 550);
  813.                return;
  814.             }
  815.          }
  816.       }
  817.  
  818.       if (_GetDoSpamProtection())
  819.       {
  820.          shared_ptr<DomainAliases> pDA = ObjectCache::Instance()->GetDomainAliases();
  821.          const String sToAddress = pDA->ApplyAliasesOnAddress(sRecipientAddress);
  822.  
  823.          if (!SpamProtection::Instance()->PerformGreyListing(m_pCurrentMessage, m_setSpamTestResults, sToAddress, GetIPAddress()))
  824.          {
  825.             if (m_pCurrentMessage->GetFromAddress().IsEmpty())
  826.             {
  827.                // We got a message with an empty sender address.
  828.                // When this happens, we should delay the greylist-reject
  829.                // until after the DATA command. The reason for this is
  830.                // that this may be a SMTP callback from another server
  831.                // that is veriying that the recipient exists, using the
  832.                // RCPT TO command. And we don't want to delay that.
  833.                m_bRejectedByDelayedGreyListing = true;
  834.             }
  835.             else
  836.             {
  837.                // The sender is greylisted. We don't log to awstats here,
  838.                // since we tell the client to try again later.
  839.                _SendErrorResponse(451, "Please try again later.");
  840.                return;
  841.             }
  842.          }
  843.       }
  844.  
  845.       // OK, the recipient is acceptable.
  846.       shared_ptr<MessageRecipients> pRecipients = m_pCurrentMessage->GetRecipients();
  847.       bool recipientOK = false;
  848.       _recipientParser.CreateMessageRecipientList(sRecipientAddress, pRecipients, recipientOK);
  849.  
  850.       if (!recipientOK)
  851.       {
  852.          _SendData("550 Unknown user");
  853.          return;
  854.       }
  855.    
  856.       _SendData("250 OK");
  857.    }
  858.  
  859.    bool
  860.    SMTPConnection::_DoSpamProtection(SpamProtectionType spType, const String &sFromAddress, const String &hostName, const IPAddress & lIPAddress)
  861.    //---------------------------------------------------------------------------()
  862.    // DESCRIPTION:
  863.    // Does IP based spam protection. Returns true if we should
  864.    // continue delivery, false otherwise.  
  865.    //---------------------------------------------------------------------------()
  866.    {
  867.       if (!_GetDoSpamProtection())
  868.          return true;
  869.  
  870.       if (spType == SPPreTransmission)
  871.       {
  872.          set<shared_ptr<SpamTestResult> > setResult =
  873.             SpamProtection::Instance()->RunPreTransmissionTests(sFromAddress, lIPAddress, GetIPAddress(), hostName);
  874.  
  875.          m_setSpamTestResults.insert(setResult.begin(), setResult.end());
  876.       }
  877.       else if (spType == SPPostTransmission)
  878.       {
  879.          set<shared_ptr<SpamTestResult> > setResult =
  880.             SpamProtection::Instance()->RunPostTransmissionTests(sFromAddress, lIPAddress, GetIPAddress(), m_pCurrentMessage);
  881.  
  882.          m_setSpamTestResults.insert(setResult.begin(), setResult.end());
  883.  
  884.       }
  885.  
  886.       int iTotalSpamScore = SpamProtection::CalculateTotalSpamScore(m_setSpamTestResults);
  887.  
  888.       int deleteThreshold = Configuration::Instance()->GetAntiSpamConfiguration().GetSpamDeleteThreshold();
  889.       int markThreshold = Configuration::Instance()->GetAntiSpamConfiguration().GetSpamMarkThreshold();
  890.  
  891.       if (deleteThreshold > 0 && iTotalSpamScore >= deleteThreshold)
  892.       {
  893.          ServerStatus::Instance()->OnSpamMessageDetected();
  894.  
  895.          // Generate a text string to send to the client.
  896.          String messageText = _GetSpamTestResultMessage(m_setSpamTestResults);
  897.  
  898.          if (spType == SPPreTransmission)
  899.             _SendData("550 " + messageText);
  900.          else
  901.             _SendData("554 " + messageText);
  902.  
  903.          String sLogMessage;
  904.          sLogMessage.Format(_T("hMailServer SpamProtection rejected RCPT (Sender: %s, IP:%s, Reason: %s)"), sFromAddress, String(GetIPAddressString()), messageText);
  905.          LOG_APPLICATION(sLogMessage);
  906.  
  907.          return false;
  908.       }
  909.       else if (markThreshold > 0 && iTotalSpamScore >= markThreshold)
  910.       {
  911.          // This message is spam, but we shouldn't delete it. Instead, we will add spam headers to it.
  912.          return true;
  913.       }
  914.  
  915.       return true;
  916.    }
  917.  
  918.    String
  919.    SMTPConnection::_GetSpamTestResultMessage(set<shared_ptr<SpamTestResult> > testResults) const
  920.    {
  921.       boost_foreach(shared_ptr<SpamTestResult> result, testResults)
  922.       {
  923.          if (result->GetResult() == SpamTestResult::Fail)
  924.             return result->GetMessage();
  925.       }
  926.  
  927.       return "";
  928.    }
  929.  
  930.    void
  931.    SMTPConnection::_ProtocolQUIT()
  932.    {
  933.        LOG_DEBUG("SMTPConnection::_ProtocolQUIT");
  934.       // Reset the message here in case a message transmission has started,
  935.       // but hasn't ended. This can happen if the client sends DATA and then
  936.       // the actual email message in the same buffer (which would be a RFC-violation).
  937.       _ResetCurrentMessage();
  938.  
  939.       _SendData("221 goodbye");
  940.      
  941.       m_bPendingDisconnect = true;
  942.       PostDisconnect();
  943.    }
  944.  
  945.    void
  946.    SMTPConnection::_AppendMessageHeaders()
  947.    {
  948.       if (m_bTraceHeadersWritten)
  949.       {
  950.          shared_ptr<ByteBuffer> pBuffer = m_pTransmissionBuffer->GetBuffer();
  951.          shared_ptr<MimeHeader> pHeader = Utilities::GetMimeHeader(pBuffer->GetBuffer(), pBuffer->GetSize());
  952.  
  953.          String sOutput;
  954.  
  955.          // Add received by tag.
  956.          String sReceivedLine;
  957.          String sReceivedIP;
  958.          String sAUTHIP;
  959.          String sAuthSenderReplacementIP = IniFileSettings::Instance()->GetAuthUserReplacementIP();
  960.          bool bAddXAuthUserIP = IniFileSettings::Instance()->GetAddXAuthUserIP();
  961.          
  962.  
  963.          // If sender is logged in and replace IP is enabled use it
  964.          if (!m_sUsername.IsEmpty() && !sAuthSenderReplacementIP.empty())
  965.          {
  966.             sReceivedIP = sAuthSenderReplacementIP;
  967.             sAUTHIP = GetIPAddressString();
  968.          }
  969.          else
  970.          {
  971.             sReceivedIP = GetIPAddressString();
  972.             sAUTHIP = sReceivedIP;
  973.          }
  974.  
  975.          sReceivedLine.Format(_T("Received: %s\r\n"), Utilities::GenerateReceivedHeader(sReceivedIP, m_sHeloHost));
  976.          sOutput += sReceivedLine;
  977.  
  978.          String sComputerName = Utilities::ComputerName();
  979.  
  980.          // Add Message-ID header if it does not exist.
  981.          if (!pHeader->FieldExists("Message-ID"))
  982.          {
  983.             String sTemp;
  984.             sTemp.Format(_T("Message-ID: %s\r\n"), Utilities::GenerateMessageID());
  985.             sOutput += sTemp;
  986.          }
  987.  
  988.          // Add X-AuthUser header if it does not exist.
  989.          if (IniFileSettings::Instance()->GetAddXAuthUserHeader() && !m_sUsername.IsEmpty())
  990.          {
  991.             if (!pHeader->FieldExists("X-AuthUser"))
  992.                sOutput += "X-AuthUser: " + m_sUsername + "\r\n";
  993.          }
  994.  
  995.          // Now add x- header for AUTH user if enabled since it was replaced above if so
  996.          // Likely would be good idea for this to be optional at some point
  997.          if (!m_sUsername.IsEmpty() && !sAuthSenderReplacementIP.empty() && bAddXAuthUserIP)
  998.          {
  999.             if (!pHeader->FieldExists("X-AuthUserIP"))
  1000.                sOutput += "X-AuthUserIP: " + sAUTHIP + "\r\n";
  1001.          }
  1002.          
  1003.          // We need to prepend these headers to the message buffer.
  1004.          shared_ptr<ByteBuffer> pTempBuf = shared_ptr<ByteBuffer>(new ByteBuffer);
  1005.  
  1006.          AnsiString sOutputStr = sOutput;
  1007.          pTempBuf->Add((BYTE*) sOutputStr.GetBuffer(), sOutputStr.GetLength());
  1008.          pTempBuf->Add(m_pTransmissionBuffer->GetBuffer()->GetBuffer(), m_pTransmissionBuffer->GetBuffer()->GetSize());
  1009.  
  1010.          // Add to the original buffer
  1011.          m_pTransmissionBuffer->GetBuffer()->Empty();
  1012.          m_pTransmissionBuffer->GetBuffer()->Add(pTempBuf->GetBuffer(), pTempBuf->GetSize());
  1013.  
  1014.          m_bTraceHeadersWritten = false;
  1015.       }
  1016.    }
  1017.  
  1018.    void
  1019.    SMTPConnection::ParseData(shared_ptr<ByteBuffer> pBuf)
  1020.    //---------------------------------------------------------------------------()
  1021.    // DESCRIPTION:
  1022.    // Parses a clients SMTP command in Binary mode.
  1023.    //---------------------------------------------------------------------------()
  1024.    {
  1025.        LOG_DEBUG("SMTPConnection::ParseData");
  1026.       // Move the data from the incoming buffer to the transparent transmission buffer.
  1027.       // If we've received more data than the max message size, don't save it.
  1028.  
  1029.       m_pTransmissionBuffer->Append(pBuf->GetBuffer(), pBuf->GetSize());
  1030.  
  1031.       // We need current message size in KB
  1032.       int iBufSizeKB = m_pTransmissionBuffer->GetSize() / 1024;
  1033.  
  1034.       // Clear the old buffer
  1035.       pBuf->Empty();
  1036.  
  1037.       // Check if it's time to flush.
  1038.       if (m_pTransmissionBuffer->GetRequiresFlush())
  1039.       {
  1040.          // We need to prepend the transmission buffer
  1041.          // with the headers...
  1042.          _AppendMessageHeaders();
  1043.       }
  1044.  
  1045.       // Flush the transmission buffer
  1046.       m_pTransmissionBuffer->Flush();
  1047.  
  1048.       if (!m_pTransmissionBuffer->GetTransmissionEnded())
  1049.       {
  1050.  
  1051.          String sLogData;
  1052.          int iMaxSizeDrop = IniFileSettings::Instance()->GetSMTPDMaxSizeDrop();
  1053.          if (iMaxSizeDrop > 0 && iBufSizeKB >= iMaxSizeDrop)
  1054.          {
  1055.             sLogData.Format(_T("Size: %d KB, Max size: %d KB - DROP!!"),
  1056.             iBufSizeKB, iMaxSizeDrop);
  1057.             LOG_SMTP(GetSessionID(), GetIPAddressString(), sLogData);      
  1058.             String sMessage;
  1059.             sMessage.Format(_T("552 Message size exceeds the drop maximum message size. Size: %d KB, Max size: %d KB - DROP!"), iBufSizeKB, iMaxSizeDrop);
  1060.             _SendData(sMessage);
  1061.             _LogAwstatsMessageRejected();
  1062.             _ResetCurrentMessage();
  1063.             SetReceiveBinary(false);
  1064.             m_bPendingDisconnect = true;
  1065.             //PostReceive();
  1066.             PostDisconnect();
  1067.  
  1068.             return;
  1069.  
  1070.       } else {
  1071.          // We need more data.
  1072.          PostBufferReceive();
  1073.          return;
  1074.       }
  1075.    }
  1076.  
  1077.       // Since this may be a time-consuming task, do it asynchronously
  1078.       shared_ptr<AsynchronousTask<TCPConnection> > finalizationTask =
  1079.          shared_ptr<AsynchronousTask<TCPConnection> >(new AsynchronousTask<TCPConnection>
  1080.             (boost::bind(&SMTPConnection::_HandleSMTPFinalizationTaskCompleted, shared_from_this()), GetTCPConnectionTemporaryPointer()));
  1081.      
  1082.       Application::Instance()->GetAsyncWorkQueue()->AddTask(finalizationTask);
  1083.    }
  1084.    
  1085.    void
  1086.    SMTPConnection::_HandleSMTPFinalizationTaskCompleted()
  1087.    {
  1088.        LOG_DEBUG("SMTPConnection::_HandleSMTPFinalizationTaskCompleted");
  1089.       if (!_DoPreAcceptSpamProtection())
  1090.       {
  1091.          // This message was stopped by spam protection. The user either needs
  1092.          // to quit or start from rset again.
  1093.          _LogAwstatsMessageRejected();
  1094.  
  1095.          _ResetCurrentMessage();
  1096.          SetReceiveBinary(false);
  1097.          PostReceive();
  1098.          return;
  1099.       }
  1100.  
  1101.       _DoPreAcceptMessageModifications();
  1102.  
  1103.       // Transmission has ended.
  1104.       m_pCurrentMessage->SetSize(FileUtilities::FileSize(PersistentMessage::GetFileName(m_pCurrentMessage)));
  1105.  
  1106.  
  1107.    // Let's archive message we just received
  1108.    String sArchiveDir = IniFileSettings::Instance()->GetArchiveDir();
  1109.  
  1110.    if (!sArchiveDir.empty())
  1111.    {
  1112.       LOG_SMTP(GetSessionID(), GetIPAddressString(), "Archiving..");      
  1113.  
  1114.       bool bArchiveHardlinks = IniFileSettings::Instance()->GetArchiveHardlinks();
  1115.       String _messageFileName;
  1116.       String sFileNameExclPath;
  1117.       String sMessageArchivePath;
  1118.       String sFromAddress1 = m_pCurrentMessage->GetFromAddress();
  1119.       std::vector<String> vecParams1 = StringParser::SplitString(sFromAddress1,  "@");
  1120.  
  1121.       // We need exactly 2 or not an email address
  1122.       if (vecParams1.size() == 2)
  1123.       {
  1124.          String sResponse;
  1125.          String sSenderName = vecParams1[0];
  1126.          sSenderName = sSenderName.ToLower();
  1127.          String sSenderDomain = vecParams1[1];
  1128.          sSenderDomain = sSenderDomain.ToLower();
  1129.          bool blocalSender1 = _GetIsLocalSender();
  1130.  
  1131.          if (blocalSender1)
  1132.          {
  1133.             // First copy goes to local sender
  1134.             _messageFileName = PersistentMessage::GetFileName(m_pCurrentMessage);
  1135.             sFileNameExclPath = FileUtilities::GetFileNameFromFullPath(_messageFileName);
  1136.             sMessageArchivePath = sArchiveDir + "\\" + sSenderDomain + "\\" + sSenderName + "\\Sent-" + sFileNameExclPath;
  1137.  
  1138.             LOG_SMTP(GetSessionID(), GetIPAddressString(), "Local sender: " + sFromAddress1 + ". Putting in user folder: " + sMessageArchivePath);      
  1139.  
  1140.             FileUtilities::Copy(_messageFileName, sMessageArchivePath, true);
  1141.          }
  1142.          else
  1143.          {
  1144.             LOG_SMTP(GetSessionID(), GetIPAddressString(), "Non local sender, putting in common Inbound folder..");      
  1145.  
  1146.             // First copy goes to common archive folder instead
  1147.             _messageFileName = PersistentMessage::GetFileName(m_pCurrentMessage);
  1148.             sFileNameExclPath = FileUtilities::GetFileNameFromFullPath(_messageFileName);
  1149.             sMessageArchivePath = sArchiveDir + "\\Inbound\\" + sFileNameExclPath;
  1150.  
  1151.             FileUtilities::Copy(_messageFileName, sMessageArchivePath, true);
  1152.          }
  1153.             String sMessageArchivePath2;
  1154.  
  1155.             // Now create hardlink/copy for each *local* recipient
  1156.             shared_ptr<const Domain> pDomaintmp;
  1157.             bool bDomainIsLocal = false;
  1158.  
  1159.             const std::vector<shared_ptr<MessageRecipient> > vecRecipients = m_pCurrentMessage->GetRecipients()->GetVector();
  1160.             std::vector<shared_ptr<MessageRecipient> >::const_iterator iterRecipient = vecRecipients.begin();
  1161.             while (iterRecipient != vecRecipients.end())
  1162.             {
  1163.                String sRecipientAddress = (*iterRecipient)->GetAddress();
  1164.                vecParams1 = StringParser::SplitString(sRecipientAddress,  "@");
  1165.  
  1166.                // We need exactly 2 or not an email address
  1167.                if (vecParams1.size() == 2)
  1168.                {
  1169.                   String sResponse;
  1170.                   String sSenderName = vecParams1[0];
  1171.                   sSenderName = sSenderName.ToLower();
  1172.                   String sSenderDomain = vecParams1[1];
  1173.                   sSenderDomain = sSenderDomain.ToLower();
  1174.  
  1175.                   pDomaintmp = CacheContainer::Instance()->GetDomain(sSenderDomain);
  1176.                   bDomainIsLocal = pDomaintmp ? true : false;
  1177.  
  1178.                   if (bDomainIsLocal)
  1179.                   {
  1180.                      sMessageArchivePath2 = sArchiveDir + "\\" + sSenderDomain + "\\" + sSenderName + "\\" + sFileNameExclPath;
  1181.                      LOG_SMTP(GetSessionID(), GetIPAddressString(), "Local recipient: " + sRecipientAddress + ". Putting in user folder: " + sMessageArchivePath2);      
  1182.  
  1183.                      if (bArchiveHardlinks)
  1184.                      {
  1185.                         FileUtilities::CreateDirectoryRecursive(sArchiveDir + "\\" + sSenderDomain + "\\" + sSenderName);
  1186.                         // This function call is odd in that original is 2nd anc destination is 1st..
  1187.                         BOOL fCreatedLink = CreateHardLink( sMessageArchivePath2, sMessageArchivePath, NULL ); // Last is reserved, must be NULL
  1188.  
  1189.                         if ( fCreatedLink == FALSE )
  1190.                         {
  1191.                            // If error try normal copy
  1192.                            FileUtilities::Copy(sMessageArchivePath, sMessageArchivePath2, true);
  1193.                            LOG_SMTP(GetSessionID(), GetIPAddressString(), "HardLink failed.. Falling back to Copy.");      
  1194.                         }
  1195.                         else
  1196.                         {
  1197.                            LOG_SMTP(GetSessionID(), GetIPAddressString(), "HardLink succeeded.");      
  1198.                         }
  1199.                     }
  1200.                     else
  1201.                     {
  1202.                        FileUtilities::Copy(sMessageArchivePath, sMessageArchivePath2, true);
  1203.                     }
  1204.                   }
  1205.                }
  1206.             iterRecipient++;
  1207.          }
  1208.    }
  1209.    else
  1210.    {
  1211.       // Sender is either null/blank (ie <>) or some other odd thing happed so we'll save in Error folder
  1212.       // either way as failsafe.
  1213.       LOG_SMTP(GetSessionID(), GetIPAddressString(), "Sender is NULL or invalid. Saving to Error folder.");      
  1214.  
  1215.       _messageFileName = PersistentMessage::GetFileName(m_pCurrentMessage);
  1216.       sFileNameExclPath = FileUtilities::GetFileNameFromFullPath(_messageFileName);
  1217.       sMessageArchivePath = sArchiveDir + "\\Error\\" + sFileNameExclPath;
  1218.       FileUtilities::Copy(_messageFileName, sMessageArchivePath, true);
  1219.    }
  1220. }  
  1221.  
  1222.       float dTime = ((float) GetTickCount() - (float) m_lMessageStartTC) / (float) 1000;
  1223.       double dTCDiff = Math::Round(dTime ,3);
  1224.  
  1225.       if (_OnPreAcceptTransfer())
  1226.       {
  1227.          // Add the message to the database.
  1228.          if (PersistentMessage::SaveObject(m_pCurrentMessage))
  1229.          {
  1230.             // Make sure the transmission buffer has released the handle
  1231.             // to the file.
  1232.             if (m_pTransmissionBuffer)
  1233.                m_pTransmissionBuffer.reset();
  1234.  
  1235.             // Add this message to the delivery queue cache. This way,
  1236.             // we won't have to read it from the database.
  1237.             MessageCache::Instance()->AddMessage(m_pCurrentMessage);
  1238.  
  1239.             // Free the message, so we don't access it the same time
  1240.             // as the SMTP delivery manager.
  1241.             m_pCurrentMessage.reset();
  1242.  
  1243.             // Tell the deliverer that a new message is pending. This
  1244.             // will cause the SMTP delivery manager to start a new delivery
  1245.             // thread and deliver the message.
  1246.             Application::Instance()->SubmitPendingEmail();
  1247.  
  1248.             // Reset the spam protection results.
  1249.             m_setSpamTestResults.clear();
  1250.  
  1251.             // Tell the client that everything went fine. This
  1252.             // will cause the client to either disconnect or to
  1253.             // start a new message.
  1254.             String sResponse;
  1255.             sResponse.Format(_T("250 Queued (%.3f seconds)"), dTCDiff);
  1256.             _SendData(sResponse);
  1257.  
  1258.             // The message delivery is complete, or
  1259.             // it has failed. Any way, we should start
  1260.             // a new message.
  1261.             m_CurrentState = HEADER;
  1262.          }
  1263.          else
  1264.          {
  1265.             // The delivery of the message failed. This may happen if tables are
  1266.             // corrupt in the database. We now return an error message to the sender.
  1267.             // Hopefully, the sending server will retry later.
  1268.             _SendData("554 Your message was received but it could not be saved. Please retry later.");
  1269.  
  1270.             // Delete the file now since we could not save it in the database.
  1271.             _ResetCurrentMessage();
  1272.            
  1273.          }
  1274.       }
  1275.       else
  1276.       {
  1277.          // The message was rejected by _OnPreAcceptTransfer. For example
  1278.          // this may happen if the message was rejected by a script subscribing
  1279.          // to OnAcceptMessage.
  1280.          _ResetCurrentMessage();
  1281.       }
  1282.  
  1283.       SetReceiveBinary(false);
  1284.       PostReceive();
  1285.  
  1286.    }
  1287.  
  1288.    void
  1289.    SMTPConnection::_DoPreAcceptMessageModifications()
  1290.    //---------------------------------------------------------------------------()
  1291.    // DESCRIPTION:
  1292.    // Make changes to the message before it's accepted for delivery. This is
  1293.    // for example where message signature and spam-headers are added.
  1294.    //---------------------------------------------------------------------------()
  1295.    {
  1296.       shared_ptr<MessageData> pMsgData;
  1297.  
  1298.       // Check if we should add a spam header.
  1299.       int iTotalSpamScore = SpamProtection::CalculateTotalSpamScore(m_setSpamTestResults);
  1300.       int iSpamMarkThreshold = Configuration::Instance()->GetAntiSpamConfiguration().GetSpamMarkThreshold();
  1301.  
  1302.       if (iTotalSpamScore >= iSpamMarkThreshold)
  1303.       {
  1304.          pMsgData = SpamProtection::TagMessageAsSpam(m_pCurrentMessage, m_setSpamTestResults);
  1305.  
  1306.          // Increase the spam-counter
  1307.          ServerStatus::Instance()->OnSpamMessageDetected();
  1308.       }
  1309.  
  1310.       _SetMessageSignature(pMsgData);
  1311.  
  1312.       if (pMsgData)
  1313.          pMsgData->Write(PersistentMessage::GetFileName(m_pCurrentMessage));
  1314.    }
  1315.  
  1316.    void
  1317.    SMTPConnection::_SetMessageSignature(shared_ptr<MessageData> &pMessageData)
  1318.    //---------------------------------------------------------------------------()
  1319.    // DESCRIPTION:
  1320.    // Sets the signature of the message, based on the signature in the account
  1321.    // settings and domain settings.
  1322.    //---------------------------------------------------------------------------()
  1323.    {
  1324.       shared_ptr<SignatureAdder> pSignatureAdder = shared_ptr<SignatureAdder>(new SignatureAdder);
  1325.       pSignatureAdder->SetSignature(m_pCurrentMessage, m_pSenderDomain, m_pSenderAccount, pMessageData);
  1326.    }
  1327.  
  1328.    bool
  1329.    SMTPConnection::_OnPreAcceptTransfer()
  1330.    {
  1331.       if (m_pTransmissionBuffer->GetCancelTransmission())
  1332.       {
  1333.          _SendData("554 "  + m_pTransmissionBuffer->GetCancelMessage());
  1334.          _LogAwstatsMessageRejected();
  1335.          return false;
  1336.       }
  1337.  
  1338.       const String fileName = PersistentMessage::GetFileName(m_pCurrentMessage);
  1339.  
  1340.       if (!FileUtilities::Exists(fileName))
  1341.       {
  1342.          String sErrorMsg;
  1343.          sErrorMsg.Format(_T("Rejected message because no mail data has been saved in file %s"), fileName);
  1344.  
  1345.          ErrorManager::Instance()->ReportError(ErrorManager::Critical, 5019, "SMTPConnection::_OnPreAcceptTransfer", sErrorMsg);
  1346.      
  1347.          _SendData("451 Rejected - No data saved.");
  1348.          _LogAwstatsMessageRejected();
  1349.          return false;
  1350.       }
  1351.  
  1352.  
  1353.       // Check so that message isn't to big. Max message
  1354.       // size is specified in KB.
  1355.       if (m_iMaxMessageSizeKB > 0 && (m_pTransmissionBuffer->GetSize() / 1024) > m_iMaxMessageSizeKB)
  1356.       {
  1357.          String sMessage;
  1358.          sMessage.Format(_T("554 Rejected - Message size exceeds fixed maximum message size. Size: %d KB, Max size: %d KB"),
  1359.             m_pTransmissionBuffer->GetSize() / 1024, m_iMaxMessageSizeKB);
  1360.          _SendData(sMessage);
  1361.          _LogAwstatsMessageRejected();
  1362.          return false;
  1363.       }
  1364.  
  1365.       // Check for bare LF's.
  1366.       if (!Configuration::Instance()->GetSMTPConfiguration()->GetAllowIncorrectLineEndings())
  1367.       {
  1368.          if (!_CheckLineEndings())
  1369.          {
  1370.             String sMessage;
  1371.             sMessage.Format(_T("554 Rejected - Message containing bare LF's."));
  1372.            
  1373.             _SendData(sMessage);
  1374.             _LogAwstatsMessageRejected();
  1375.             return false;
  1376.          }
  1377.  
  1378.       }
  1379.  
  1380.       if (Configuration::Instance()->GetUseScriptServer())
  1381.       {
  1382.          shared_ptr<ScriptObjectContainer> pContainer = shared_ptr<ScriptObjectContainer>(new ScriptObjectContainer);
  1383.          shared_ptr<Result> pResult = shared_ptr<Result>(new Result);
  1384.          shared_ptr<ClientInfo> pClientInfo = shared_ptr<ClientInfo>(new ClientInfo);
  1385.  
  1386.          pClientInfo->SetUsername(m_sUsername);
  1387.          pClientInfo->SetIPAddress(GetIPAddressString());
  1388.          pClientInfo->SetPort(GetLocalPort());
  1389.          pClientInfo->SetHELO(m_sHeloHost);
  1390.  
  1391.          pContainer->AddObject("HMAILSERVER_MESSAGE", m_pCurrentMessage, ScriptObject::OTMessage);
  1392.          pContainer->AddObject("HMAILSERVER_CLIENT", pClientInfo, ScriptObject::OTClient);
  1393.          pContainer->AddObject("Result", pResult, ScriptObject::OTResult);
  1394.  
  1395.          String sEventCaller = "OnAcceptMessage(HMAILSERVER_CLIENT, HMAILSERVER_MESSAGE)";
  1396.          ScriptServer::Instance()->FireEvent(ScriptServer::EventOnAcceptMessage, sEventCaller, pContainer);
  1397.  
  1398.          switch (pResult->GetValue())
  1399.          {
  1400.          case 1:
  1401.             {
  1402.                String sErrorMessage = "554 Rejected";
  1403.                _SendData(sErrorMessage);
  1404.                _LogAwstatsMessageRejected();
  1405.                return false;
  1406.             }
  1407.          case 2:
  1408.             {
  1409.                String sErrorMessage = "554 " + pResult->GetMessage();
  1410.                _SendData(sErrorMessage);
  1411.                _LogAwstatsMessageRejected();
  1412.                return false;
  1413.             }
  1414.          case 3:
  1415.             {
  1416.                String sErrorMessage = "453 " + pResult->GetMessage();
  1417.                _SendData(sErrorMessage);
  1418.                _LogAwstatsMessageRejected();
  1419.                return false;
  1420.             }
  1421.          }
  1422.       }      
  1423.  
  1424.       if (GetSecurityRange()->GetVirusProtection())
  1425.       {
  1426.          m_pCurrentMessage->SetFlagVirusScan(true);
  1427.       }
  1428.  
  1429.       return true;
  1430.    }
  1431.  
  1432.    bool
  1433.    SMTPConnection::_CheckLineEndings() const
  1434.    //---------------------------------------------------------------------------()
  1435.    // DESCRIPTION:
  1436.    // Checks if the message contains any CR with missing LF, or any LF with
  1437.    // missing CR.
  1438.    //---------------------------------------------------------------------------()
  1439.    {
  1440.       try
  1441.       {
  1442.          if (!m_pCurrentMessage)
  1443.             return false;
  1444.  
  1445.          const String fileName = PersistentMessage::GetFileName(m_pCurrentMessage);
  1446.  
  1447.          File oFile;
  1448.          if (!oFile.Open(fileName, File::OTReadOnly))
  1449.             return false;
  1450.  
  1451.          const int iChunkSize = 10000;
  1452.          shared_ptr<ByteBuffer> pBuffer = oFile.ReadChunk(iChunkSize);
  1453.          while (pBuffer)
  1454.          {
  1455.             // Check that buffer contains correct line endings.
  1456.             const char *pChar = pBuffer->GetCharBuffer();
  1457.             int iBufferSize = pBuffer->GetSize();
  1458.  
  1459.             // Check from pos 3 to size-3. Not 100% sure, but
  1460.             // we don't have to worry about buffer start/endings.
  1461.  
  1462.             for (int i = 3; i < iBufferSize - 3; i++)
  1463.             {
  1464.                const char *pCurrentChar = pChar + i;
  1465.  
  1466.                // Check chars.
  1467.                if (*pCurrentChar == '\r')
  1468.                {
  1469.                   // Check next character
  1470.                   if (i >= iBufferSize)
  1471.                      return false;
  1472.  
  1473.                   const char *pNextChar = pCurrentChar + 1;
  1474.                   if (*pNextChar != '\n')
  1475.                      return false;
  1476.                }
  1477.                else if (*pCurrentChar == '\n')
  1478.                {
  1479.                   // Check previous char
  1480.                   if (i == 0)
  1481.                      return false;
  1482.  
  1483.                   const char *pPreviousChar = pCurrentChar - 1;
  1484.                   if (*pPreviousChar != '\r')
  1485.                      return false;
  1486.                }
  1487.             }
  1488.  
  1489.             // Read next chunk
  1490.             pBuffer = oFile.ReadChunk(iChunkSize);
  1491.          }
  1492.       }
  1493.       catch (...)
  1494.       {
  1495.          ErrorManager::Instance()->ReportError(ErrorManager::Medium, 4328, "SMTPConnection::_CheckLineEndings", "Failed to check line endings.");
  1496.       }
  1497.  
  1498.  
  1499.       return true;
  1500.    }
  1501.  
  1502.    void
  1503.    SMTPConnection::_LogAwstatsMessageRejected()
  1504.    //---------------------------------------------------------------------------()
  1505.    // DESCRIPTION:
  1506.    // If awstats logging is enabled, this function goes through all the recipients
  1507.    // of the message, and logs to the awstats log that they have been rejected.
  1508.    // This is used if a message is rejected after it has been transferred from the
  1509.    // client to the server.
  1510.    //---------------------------------------------------------------------------()
  1511.    {
  1512.       // Check that message exists, and that the awstats log is enabled.
  1513.       if (!m_pCurrentMessage || !AWStats::GetEnabled())
  1514.          return;
  1515.  
  1516.       // Go through the recipients and log one row for each of them.
  1517.       String sFromAddress = m_pCurrentMessage->GetFromAddress();
  1518.  
  1519.       const std::vector<shared_ptr<MessageRecipient> > vecRecipients = m_pCurrentMessage->GetRecipients()->GetVector();
  1520.       std::vector<shared_ptr<MessageRecipient> >::const_iterator iterRecipient = vecRecipients.begin();
  1521.       while (iterRecipient != vecRecipients.end())
  1522.       {
  1523.          String sRecipientAddress = (*iterRecipient)->GetAddress();
  1524.  
  1525.          // Log the error message
  1526.          AWStats::LogDeliveryFailure(GetIPAddressString(), sFromAddress, sRecipientAddress, 554);
  1527.  
  1528.          iterRecipient++;
  1529.       }
  1530.  
  1531.    }
  1532.  
  1533.    void
  1534.    SMTPConnection::_ResetCurrentMessage()
  1535.    //---------------------------------------------------------------------------()
  1536.    // DESCRIPTION:
  1537.    // Reset the transmission buffer to free
  1538.    // any handles it has opened to the message
  1539.    // file
  1540.    //---------------------------------------------------------------------------()
  1541.    {
  1542.        LOG_DEBUG("SMTPConnection::_ResetCurrentMessage");
  1543.       if (m_pTransmissionBuffer)
  1544.       {
  1545.          m_pTransmissionBuffer.reset();
  1546.       }
  1547.  
  1548.       // Reset the current message.
  1549.       if (m_pCurrentMessage)
  1550.       {
  1551.          // This message isn't complete, so we should delete it from disk now.
  1552.          shared_ptr<Account> emptyAccount;
  1553.  
  1554.          PersistentMessage::DeleteFile(emptyAccount, m_pCurrentMessage);
  1555.  
  1556.          // Reset message object
  1557.          m_pCurrentMessage.reset();
  1558.       }
  1559.  
  1560.       m_bRejectedByDelayedGreyListing = false;
  1561.  
  1562.       m_pSenderDomain.reset();
  1563.       m_pSenderAccount.reset();
  1564.  
  1565.       m_setSpamTestResults.clear();
  1566.  
  1567.       // Reset the number of RCPT TO's for this
  1568.       // message.
  1569.       m_iCurNoOfRCPTTO = 0;
  1570.  
  1571.       // Switch back to normal ASCII mode and start of session, in
  1572.       // case we are in binary transmission mode.
  1573.       m_CurrentState = HEADER;
  1574.    }
  1575.  
  1576.  
  1577.    bool
  1578.    SMTPConnection::_SendEHLOKeywords()
  1579.    {
  1580.        LOG_DEBUG("SMTPConnection::_SendEHLOKeywords");
  1581.       String sComputerName = Utilities::ComputerName();
  1582.  
  1583.       String sData = "250-" + sComputerName + "\r\n";
  1584.      
  1585.       // Append size keyword
  1586.       {
  1587.          String sSizeKeyword;
  1588.          int iMaxSize = m_SMTPConf->GetMaxMessageSize() * 1000;
  1589.          if (iMaxSize > 0)
  1590.             sSizeKeyword.Format(_T("250-SIZE %d\r\n"), iMaxSize);
  1591.          else
  1592.             sSizeKeyword.Format(_T("250-SIZE\r\n"));
  1593.          sData += sSizeKeyword;
  1594.       }
  1595.  
  1596.       String sAuth = "250-AUTH LOGIN";
  1597.  
  1598.       if (m_SMTPConf->GetAuthAllowPlainText())
  1599.          sAuth += " PLAIN";
  1600.  
  1601.       sData += sAuth;
  1602.       sData += "\r\n250 STARTTLS\r\n";
  1603.       _SendData(sData);
  1604.    
  1605.       return true;
  1606.    }
  1607.  
  1608.    void
  1609.    SMTPConnection::OnConnectionTimeout()
  1610.    {
  1611.       _ResetCurrentMessage();
  1612.  
  1613.       _SendData("421 Connection timeout.\r\n");
  1614.    }
  1615.  
  1616.    void
  1617.    SMTPConnection::OnExcessiveDataReceived()
  1618.    {
  1619.       _ResetCurrentMessage();
  1620.       _SendData("421 Excessive amounts of data sent to server.\r\n");
  1621.    }
  1622.  
  1623.    void
  1624.    SMTPConnection::_SendData(const String &sData)
  1625.    {
  1626.       if (Logger::Instance()->GetLogSMTP())
  1627.       {
  1628.          String sLogData = "SENT: " + sData;
  1629.  
  1630.          sLogData.TrimRight(_T("\r\n"));
  1631.          sLogData.Replace(_T("\r\n"), _T("[nl]"));
  1632.  
  1633.          LOG_SMTP(GetSessionID(), GetIPAddressString(), sLogData);
  1634.       }
  1635.  
  1636.       SendData(sData + "\r\n");
  1637.    }
  1638.  
  1639.    bool
  1640.    SMTPConnection::_ReadDomainAddressFromHelo(const  String &sRequest)
  1641.    {
  1642.       int iFirstSpace = sRequest.Find(_T(" "));
  1643.      
  1644.       if (iFirstSpace == -1)
  1645.       {
  1646.          // No host name has been specified => RFC violation
  1647.          return false;
  1648.       }
  1649.  
  1650.       // Cut out the string after the space.
  1651.       m_sHeloHost = sRequest.Mid(iFirstSpace + 1);
  1652.  
  1653.       // Trim it incase of leading or trailing spaces.
  1654.       m_sHeloHost = m_sHeloHost.Trim();
  1655.  
  1656.       if (m_sHeloHost.IsEmpty())
  1657.          return false;
  1658.  
  1659.       return true;
  1660.  
  1661.    }
  1662.  
  1663.    void
  1664.    SMTPConnection::_ProtocolEHLO(const String &sRequest)
  1665.    {
  1666.  
  1667.       if (!_ReadDomainAddressFromHelo(sRequest))
  1668.       {
  1669.          // The client did not supply a parameter to
  1670.          // the helo command which is syntaxically
  1671.          // incorrect. Reject.
  1672.          _SendErrorResponse(501, "EHLO Invalid domain address.");
  1673.          return;
  1674.       }
  1675.  
  1676.       _SendEHLOKeywords();
  1677.  
  1678.       if (m_CurrentState == AUTHENTICATION)
  1679.          m_CurrentState = HEADER;
  1680.    }
  1681.    
  1682.    void
  1683.    SMTPConnection::_ProtocolHELO(const String &sRequest)
  1684.    {
  1685.       if (!_ReadDomainAddressFromHelo(sRequest))
  1686.       {
  1687.          // The client did not supply a parameter to
  1688.          // the helo command which is syntaxically
  1689.          // incorrect. Reject.
  1690.          _SendErrorResponse(501, "HELO Invalid domain address.");
  1691.          return;
  1692.       }
  1693.  
  1694.       _SendData("250 Hello.");
  1695.  
  1696.       if (m_CurrentState == AUTHENTICATION)
  1697.          m_CurrentState = HEADER;
  1698.  
  1699.    }
  1700.  
  1701.    void
  1702.    SMTPConnection::_ProtocolHELP()
  1703.    {
  1704.       _SendData("211 DATA HELO EHLO MAIL NOOP QUIT RCPT RSET SAML TURN VRFY\r\n");
  1705.    }
  1706.  
  1707.    void
  1708.    SMTPConnection::_ProtocolAUTH(const String &sRequest)
  1709.    {
  1710.       _requestedAuthenticationType = AUTH_NONE;
  1711.  
  1712.       std::vector<String> vecParams = StringParser::SplitString(sRequest,  " ");
  1713.  
  1714.       if (vecParams.size() == 1)
  1715.       {
  1716.          _SendErrorResponse(504, "Authentication type not specified.");
  1717.          return;
  1718.       }
  1719.      
  1720.       String sAuthenticationType = vecParams[1];
  1721.       sAuthenticationType.MakeUpper();
  1722.  
  1723.       if (sAuthenticationType == _T("LOGIN"))
  1724.       {
  1725.          _requestedAuthenticationType = AUTH_LOGIN;
  1726.  
  1727.          String sResponse;
  1728.  
  1729.          if (vecParams.size() == 3)
  1730.          {
  1731.             // Fetch username from third parameter.
  1732.             StringParser::Base64Decode(vecParams[2], m_sUsername);
  1733.             m_CurrentState = SMTPUPASSWORD;
  1734.  
  1735.             StringParser::Base64Encode("Password:", sResponse);
  1736.          }
  1737.          else
  1738.          {
  1739.             m_CurrentState = SMTPUSERNAME;
  1740.             StringParser::Base64Encode("Username:", sResponse);
  1741.          }
  1742.  
  1743.          _SendData("334 " + sResponse);
  1744.          return;
  1745.  
  1746.       }
  1747.       else if (sAuthenticationType == _T("PLAIN") &&
  1748.                m_SMTPConf->GetAuthAllowPlainText())
  1749.       {
  1750.          _requestedAuthenticationType = AUTH_PLAIN;
  1751.  
  1752.          // Stupid user has selected plain text authentication.
  1753.          if (vecParams.size() == 3)
  1754.          {
  1755.             // Fetch username and password directly from command.
  1756.             _AuthenticateUsingPLAIN(vecParams[2]);
  1757.          }
  1758.          else
  1759.          {
  1760.             _SendData("334 Log on");
  1761.             m_CurrentState = SMTPUSERNAME;
  1762.          }
  1763.  
  1764.          return;
  1765.       }
  1766.  
  1767.       _SendErrorResponse(504, "Authentication mechanism not supported.");
  1768.    }
  1769.  
  1770.    void
  1771.    SMTPConnection::_ProtocolETRN(const String &sRequest)
  1772.    {
  1773.       // RFC ETRN Codes
  1774.       //   250 OK, queuing for node <x> started
  1775.       //   251 OK, no messages waiting for node <x>
  1776.       //   252 OK, pending messages for node <x> started
  1777.       //   253 OK, <n> pending messages for node <x> started
  1778.       //   458 Unable to queue messages for node <x>
  1779.       //   459 Node <x> not allowed: <reason>
  1780.       //   500 Syntax Error
  1781.       //   501 Syntax Error in Parameters
  1782.  
  1783.  
  1784. // WE SHOULD ADD SOME LOGGING HERE
  1785.  
  1786.       std::vector<String> vecParams = StringParser::SplitString(sRequest,  " ");
  1787.  
  1788.       // We need at least 1 parameter. ETRN alone results in error
  1789.       if (vecParams.size() == 1)
  1790.       {
  1791.          _SendErrorResponse(500, "Syntax Error: No domain parameter included");
  1792.          LOG_SMTP(GetSessionID(), GetIPAddressString(), "SMTPDeliverer - ETRN - No domain parameter included");      
  1793.          return;
  1794.       }
  1795.      
  1796.       String sResponse;
  1797.       String sETRNDomain = vecParams[1];
  1798.       String sETRNDomain2 = sETRNDomain.ToLower();
  1799.       String sLogData;
  1800.  
  1801.       bool bIsRouteDomain = false;
  1802.       vector<shared_ptr<Route> > routes = Configuration::Instance()->GetSMTPConfiguration()->GetRoutes()->GetItemsByName(sETRNDomain.ToLower());
  1803.  
  1804.       // See if sender supplied param matches one of our domains
  1805.       if (routes.size() > 0)
  1806.        {
  1807.           boost_foreach(shared_ptr<Route> route, routes)
  1808.           {
  1809.              if (route->GetName() == sETRNDomain2)
  1810.              {
  1811.              bIsRouteDomain = true;
  1812.              break;
  1813.              }
  1814.           }
  1815.        }      
  1816.  
  1817.       if (bIsRouteDomain)
  1818.       {
  1819.          LOG_SMTP(GetSessionID(), GetIPAddressString(), "SMTPDeliverer - ETRN - Route found, continuing..");      
  1820.  
  1821.          shared_ptr<Routes> pRoutes = Configuration::Instance()->GetSMTPConfiguration()->GetRoutes();
  1822.          shared_ptr<Route> pRoute = pRoutes->GetItemByName(sETRNDomain.ToLower());
  1823.  
  1824.          if (pRoute)
  1825.          {
  1826.             __int64 iRouteID = pRoute->GetID();
  1827.  
  1828.             LOG_SMTP(GetSessionID(), GetIPAddressString(), "SMTPDeliverer - ETRN - Route settings read successfully.");      
  1829.  
  1830.             int lTmpNoOfRetries = pRoute->NumberOfTries();
  1831.             int lTmpMinutesBetween = pRoute->MinutesBetweenTry();
  1832.  
  1833.             // Here we change ID back to 0, type back to 1 & next try to ASAP for Route ID
  1834.             // Special 1901-01-01 00:00:01 tells admin it is HOLD
  1835.             SQLCommand command("update hm_messages set messageaccountid = 0, messagetype = 1, messagenexttrytime = '1901-01-01 00:00:00' where messagetype = 3 and messageaccountid = @ROUTEID");
  1836.             command.AddParameter("@ROUTEID", iRouteID);
  1837.             if (Application::Instance()->GetDBManager()->Execute(command))
  1838.             {
  1839.                // Need to tell hmail to reload the settings
  1840.                //Configuration::Instance()->Load();
  1841.                _SendData("250 OK, message queuing started for " + sETRNDomain.ToLower());
  1842.                LOG_SMTP(GetSessionID(), GetIPAddressString(), "SMTPDeliverer - ETRN - 250 OK, message queuing started.");      
  1843.             }
  1844.             else
  1845.             {
  1846.                _SendData("458 Unable to queue messages for " + sETRNDomain.ToLower());
  1847.                LOG_SMTP(GetSessionID(), GetIPAddressString(), "SMTPDeliverer - ETRN - 458 Unable to queue messages");      
  1848.             }
  1849.          return;
  1850.  
  1851.        }
  1852.        else
  1853.        {
  1854.           // Send that we don't accept ETRN for that domain or invalid param
  1855.           _SendData("458 Error getting info for " + sETRNDomain.ToLower());
  1856.           LOG_SMTP(GetSessionID(), GetIPAddressString(), "SMTPDeliverer - ETRN - Could not get Route values");      
  1857.           return;
  1858.        }
  1859.      }
  1860.      else
  1861.      {
  1862.          // Send that we don't accept ETRN for that domain or invalid param
  1863.          _SendData("501 ETRN not supported for " + sETRNDomain.ToLower());
  1864.          LOG_SMTP(GetSessionID(), GetIPAddressString(), "SMTPDeliverer - ETRN - Domain is not Route");      
  1865.          return;
  1866.      }
  1867.    }
  1868.    void
  1869.    SMTPConnection::_AuthenticateUsingPLAIN(const String &sLine)
  1870.    {
  1871.       String sAuthentication;
  1872.       StringParser::Base64Decode(sLine, sAuthentication);
  1873.  
  1874.       // Extract the username and password from the decoded string.
  1875.       int iSecondTab = sAuthentication.Find(_T("\t"),1);
  1876.       if (iSecondTab < 0)
  1877.       {
  1878.          _RestartAuthentication();
  1879.          return;
  1880.       }
  1881.  
  1882.       m_sUsername = sAuthentication.Mid(1, iSecondTab-1);
  1883.       m_sPassword = sAuthentication.Mid(iSecondTab+1);
  1884.  
  1885.       // Authenticate the user.
  1886.       _Authenticate();      
  1887.    }
  1888.  
  1889.    void
  1890.    SMTPConnection::_Authenticate()
  1891.    {
  1892.       AccountLogon accountLogon;
  1893.       bool disconnect;
  1894.  
  1895.       shared_ptr<const Account> pAccount = accountLogon.Logon(GetIPAddress(), m_sUsername, m_sPassword, disconnect);
  1896.          
  1897.       if (disconnect)
  1898.       {
  1899.          _SendErrorResponse(535, "Authentication failed. Too many invalid logon attempts.");
  1900.          m_bPendingDisconnect = true;
  1901.          PostDisconnect();
  1902.          return;
  1903.       }
  1904.      
  1905.       if (pAccount)
  1906.       {
  1907.          _SendData("235 authenticated.");
  1908.  
  1909.          _isAuthenticated = true;
  1910.          m_CurrentState = HEADER;
  1911.       }
  1912.       else
  1913.       {
  1914.          _RestartAuthentication();
  1915.       }
  1916.    }
  1917.  
  1918.    void
  1919.    SMTPConnection::_RestartAuthentication()
  1920.    {
  1921.       _ResetLoginCredentials();
  1922.      
  1923.       _SendErrorResponse(535, "Authentication failed. Restarting authentication process.");
  1924.    }
  1925.  
  1926.    void
  1927.    SMTPConnection::_ResetLoginCredentials()
  1928.    {
  1929.       _requestedAuthenticationType = AUTH_NONE;
  1930.       _isAuthenticated = false;
  1931.  
  1932.       m_CurrentState = HEADER;
  1933.       m_sUsername = "";
  1934.       m_bReAuthenticateUser = false;
  1935.    }
  1936.  
  1937.  
  1938.    int
  1939.    SMTPConnection::_GetMaxMessageSize(shared_ptr<const Domain> pDomain)
  1940.    {
  1941.       int iMaxMessageSizeKB = m_SMTPConf->GetMaxMessageSize();
  1942.      
  1943.       if (pDomain)
  1944.       {
  1945.          int iDomainMaxSizeKB = pDomain->GetMaxMessageSize();
  1946.          if (iDomainMaxSizeKB > 0)
  1947.          {
  1948.             if (iMaxMessageSizeKB == 0 || iMaxMessageSizeKB > iDomainMaxSizeKB)
  1949.                iMaxMessageSizeKB = iDomainMaxSizeKB;
  1950.          }
  1951.       }
  1952.  
  1953.       return iMaxMessageSizeKB;
  1954.    }
  1955.  
  1956.    void
  1957.    SMTPConnection::_SendErrorResponse(int iErrorCode, const String &sResponse)
  1958.    {
  1959.       String sData;
  1960.       sData.Format(_T("%d %s"), iErrorCode, sResponse);
  1961.      
  1962.       _SendData(sData);
  1963.  
  1964.       if (iErrorCode >= 500 && iErrorCode <= 599)
  1965.          m_iCurNoOfInvalidCommands++;  
  1966.    }
  1967.  
  1968.    bool
  1969.    SMTPConnection::_DoPreAcceptSpamProtection()
  1970.    {
  1971.       if (m_bRejectedByDelayedGreyListing)
  1972.       {
  1973.          _SendErrorResponse(450, "Please try again later.");
  1974.          // Don't log to awstats here, since we tell the client to try again later.
  1975.          return false;
  1976.       }
  1977.  
  1978.       // Check if we should do pre-transmissions tests after transmission. This
  1979.       // happens if the message is delivered from a forwarding relay server.
  1980.       if (m_spType == SPPostTransmission)
  1981.       {
  1982.          // Do all spam proteciton now. It has been delayed since we trust the
  1983.          // server which has forwarded to us.
  1984.          // Retrieve the IP address from the message headers.
  1985.          IPAddress iIPAddress;
  1986.          String hostName;
  1987.          
  1988.          MessageUtilities::RetrieveOriginatingAddress(m_pCurrentMessage, hostName, iIPAddress);
  1989.      
  1990.          // Do spam protection now using the IP address in the header.
  1991.          if (!_DoSpamProtection(SPPreTransmission, m_pCurrentMessage->GetFromAddress(), hostName, iIPAddress))
  1992.          {
  1993.             // We should stop the message delivery.
  1994.             return false;
  1995.          }
  1996.  
  1997.          if (!_DoSpamProtection(SPPostTransmission, m_pCurrentMessage->GetFromAddress(), hostName, iIPAddress))
  1998.          {
  1999.             // We should stop the message delivery.
  2000.             return false;
  2001.          }
  2002.          
  2003.       }
  2004.       else
  2005.       {
  2006.          // Do normal post transmission spam protection. (typically SURBL)
  2007.          if (!_DoSpamProtection(SPPostTransmission, m_pCurrentMessage->GetFromAddress(), m_sHeloHost, GetIPAddress()))
  2008.          {
  2009.             // We should stop message delivery
  2010.             return false;
  2011.          }
  2012.       }
  2013.  
  2014.       // The message should be delivered.
  2015.       return true;
  2016.    }
  2017.  
  2018.  
  2019.    bool
  2020.    SMTPConnection::_GetDoSpamProtection() const
  2021.    {
  2022.       if (_isAuthenticated)
  2023.          return false;
  2024.  
  2025.       if (!GetSecurityRange()->GetSpamProtection())
  2026.          return false;
  2027.  
  2028.       if (m_pCurrentMessage)
  2029.       {
  2030.          if (SpamProtection::IsWhiteListed(m_pCurrentMessage->GetFromAddress(), GetIPAddress()))
  2031.             return false;
  2032.       }
  2033.  
  2034.       return true;
  2035.    }
  2036.  
  2037.    /*
  2038.       Returns true if
  2039.       - the domain-part of the email matches an active local domain.
  2040.       - the sender address matches a route address.
  2041.    */
  2042.    bool
  2043.    SMTPConnection::_GetIsLocalSender()
  2044.    {
  2045.        if (m_pSenderDomain && m_pSenderDomain->GetIsActive())
  2046.           return true;
  2047.  
  2048.        const String senderAddress = m_pCurrentMessage->GetFromAddress();
  2049.  
  2050.        String senderDomainName = StringParser::ExtractDomain(senderAddress);
  2051.        vector<shared_ptr<Route> > routes = Configuration::Instance()->GetSMTPConfiguration()->GetRoutes()->GetItemsByName(senderDomainName);
  2052.  
  2053.        if (routes.size() > 0)
  2054.        {
  2055.           boost_foreach(shared_ptr<Route> route, routes)
  2056.           {
  2057.              if (route->ToAllAddresses() || route->GetAddresses()->GetItemByName(senderAddress))
  2058.              {
  2059.                 if (route->GetTreatSenderAsLocalDomain())
  2060.                    return true;
  2061.              }
  2062.           }
  2063.        }      
  2064.  
  2065.        // Does not match a local domain or route.
  2066.        return false;
  2067.    }
  2068.  
  2069.    bool
  2070.    SMTPConnection::_TryExtractAddress(const String &mailFromParameter, String& address)
  2071.    {
  2072.       // Start of by removing any leading and trailing space.
  2073.       address = mailFromParameter;
  2074.       address = address.TrimLeft();
  2075.       address = address.TrimRight();
  2076.  
  2077.       // Empty address is OK
  2078.       if (address.GetLength() == 0)
  2079.          return true;
  2080.  
  2081.       // If the user is supplying a <, the address must end with a >
  2082.       if (address.StartsWith(_T("<")))
  2083.       {
  2084.          if (!address.EndsWith(_T(">")))
  2085.             return false;
  2086.  
  2087.          address.TrimLeft('<');
  2088.          address.TrimRight('>');
  2089.  
  2090.          address.TrimLeft();
  2091.          address.TrimRight();
  2092.       }
  2093.       else if (address.EndsWith(_T(">")))
  2094.       {
  2095.          // The address starts with something other than < but ands with >: Syntax error
  2096.          return false;
  2097.       }
  2098.  
  2099.       return true;
  2100.    }
  2101. }
Add Comment
Please, Sign In to add comment