42 m_verifier(verifier) ,
45 m_sasl(
GAuth::SaslServerFactory::newSaslServer(secrets,sasl_server_config,false)) ,
47 m_fsm(State::sStart,State::sEnd,State::s_Same,State::s_Any) ,
48 m_with_starttls(false) ,
49 m_peer_address(peer_address) ,
51 m_bad_client_count(0U) ,
52 m_bad_client_limit(8U) ,
53 m_session_authenticated(false)
60 m_fsm( Event::eQuit , State::sProcessing , State::s_Same , &ServerProtocol::doEagerQuit ) ;
61 m_fsm( Event::eQuit , State::s_Any , State::sEnd , &ServerProtocol::doQuit ) ;
62 m_fsm( Event::eUnknown , State::sProcessing , State::s_Same , &ServerProtocol::doIgnore ) ;
63 m_fsm( Event::eUnknown , State::s_Any , State::s_Same , &ServerProtocol::doUnknown ) ;
64 m_fsm( Event::eRset , State::sStart , State::s_Same , &ServerProtocol::doNoop ) ;
65 m_fsm( Event::eRset , State::s_Any , State::sIdle , &ServerProtocol::doRset ) ;
66 m_fsm( Event::eNoop , State::s_Any , State::s_Same , &ServerProtocol::doNoop ) ;
67 m_fsm( Event::eHelp , State::s_Any , State::s_Same , &ServerProtocol::doHelp ) ;
68 m_fsm( Event::eExpn , State::s_Any , State::s_Same , &ServerProtocol::doExpn ) ;
69 m_fsm( Event::eVrfy , State::sStart , State::sVrfyStart , &ServerProtocol::doVrfy , State::s_Same ) ;
70 m_fsm( Event::eVrfyReply , State::sVrfyStart , State::sStart , &ServerProtocol::doVrfyReply ) ;
71 m_fsm( Event::eVrfy , State::sIdle , State::sVrfyIdle , &ServerProtocol::doVrfy , State::s_Same ) ;
72 m_fsm( Event::eVrfyReply , State::sVrfyIdle , State::sIdle , &ServerProtocol::doVrfyReply ) ;
73 m_fsm( Event::eVrfy , State::sGotMail , State::sVrfyGotMail, &ServerProtocol::doVrfy , State::s_Same ) ;
74 m_fsm( Event::eVrfyReply , State::sVrfyGotMail, State::sGotMail , &ServerProtocol::doVrfyReply ) ;
75 m_fsm( Event::eVrfy , State::sGotRcpt , State::sVrfyGotRcpt, &ServerProtocol::doVrfy , State::s_Same ) ;
76 m_fsm( Event::eVrfyReply , State::sVrfyGotRcpt, State::sGotRcpt , &ServerProtocol::doVrfyReply ) ;
77 m_fsm( Event::eEhlo , State::s_Any , State::sIdle , &ServerProtocol::doEhlo , State::s_Same ) ;
78 m_fsm( Event::eHelo , State::s_Any , State::sIdle , &ServerProtocol::doHelo , State::s_Same ) ;
79 m_fsm( Event::eMail , State::sIdle , State::sGotMail , &ServerProtocol::doMail , State::sIdle ) ;
80 m_fsm( Event::eRcpt , State::sGotMail , State::sVrfyTo1 , &ServerProtocol::doRcpt , State::s_Same ) ;
81 m_fsm( Event::eVrfyReply , State::sVrfyTo1 , State::sGotRcpt , &ServerProtocol::doVrfyToReply , State::sGotMail ) ;
82 m_fsm( Event::eRcpt , State::sGotRcpt , State::sVrfyTo2 , &ServerProtocol::doRcpt , State::s_Same ) ;
83 m_fsm( Event::eVrfyReply , State::sVrfyTo2 , State::sGotRcpt , &ServerProtocol::doVrfyToReply ) ;
84 m_fsm( Event::eData , State::sGotMail , State::sIdle , &ServerProtocol::doNoRecipients ) ;
85 m_fsm( Event::eData , State::sGotRcpt , State::sData , &ServerProtocol::doData ) ;
86 m_fsm( Event::eContent , State::sData , State::sData , &ServerProtocol::doContent , State::sDiscarding ) ;
87 m_fsm( Event::eEot , State::sData , State::sProcessing , &ServerProtocol::doEot ) ;
88 m_fsm( Event::eDone , State::sProcessing , State::sIdle , &ServerProtocol::doComplete ) ;
89 m_fsm( Event::eContent , State::sDiscarding , State::sDiscarding , &ServerProtocol::doDiscard ) ;
90 m_fsm( Event::eEot , State::sDiscarding , State::sIdle , &ServerProtocol::doDiscarded ) ;
92 if( m_sasl->active() )
94 m_fsm( Event::eAuth , State::sIdle , State::sAuth , &ServerProtocol::doAuth , State::sIdle ) ;
95 m_fsm( Event::eAuthData, State::sAuth , State::sAuth , &ServerProtocol::doAuthData , State::sIdle ) ;
99 m_fsm( Event::eAuth , State::sIdle , State::sIdle , &ServerProtocol::doAuthInvalid ) ;
104 m_with_starttls = true ;
105 m_fsm( Event::eStartTls , State::sIdle , State::sStartingTls , &ServerProtocol::doStartTls , State::sIdle ) ;
106 m_fsm( Event::eSecure , State::sStartingTls , State::sIdle , &ServerProtocol::doSecure ) ;
108 else if( m_config.tls_connection )
110 m_fsm.
reset( State::sStartingTls ) ;
111 m_fsm( Event::eSecure , State::sStartingTls , State::sStart , &ServerProtocol::doSecureGreeting ) ;
117 if( m_config.tls_connection )
118 m_sender.protocolSend( std::string() ,
true ) ;
120 sendGreeting( m_text.greeting() ) ;
125 m_message.doneSignal().disconnect() ;
126 m_verifier.doneSignal().disconnect() ;
130 const std::string & protocol ,
const std::string & cipher )
132 m_certificate = certificate ;
133 m_protocol = protocol ;
136 State new_state = m_fsm.apply( *
this , Event::eSecure , EventData(
"",0U) ) ;
137 if( new_state == State::s_Any )
138 throw ProtocolDone(
"protocol error" ) ;
141void GSmtp::ServerProtocol::doSecure( EventData ,
bool & )
143 G_DEBUG(
"GSmtp::ServerProtocol::doSecure" ) ;
147void GSmtp::ServerProtocol::doSecureGreeting( EventData ,
bool & )
150 sendGreeting( m_text.greeting() ) ;
153void GSmtp::ServerProtocol::doStartTls( EventData ,
bool & ok )
157 sendOutOfSequence() ;
169 m_fsm.state() == State::sData ||
170 m_fsm.state() == State::sDiscarding ;
175 return halfDuplexBusy() ;
181 m_config.allow_pipelining && (
182 m_fsm.state() == State::sProcessing ||
183 m_fsm.state() == State::sVrfyStart ||
184 m_fsm.state() == State::sVrfyIdle ||
185 m_fsm.state() == State::sVrfyGotMail ||
186 m_fsm.state() == State::sVrfyGotRcpt ||
187 m_fsm.state() == State::sVrfyTo1 ||
188 m_fsm.state() == State::sVrfyTo2 ) ;
192 std::size_t eolsize , std::size_t linesize ,
char c0 )
194 G_ASSERT( eolsize == 2U || ( inDataState() && eolsize == 0U ) ) ;
197 EventData event_data( line_data , line_data_size , eolsize , linesize , c0 ) ;
200 Event
event = Event::eUnknown ;
201 State state = m_fsm.state() ;
202 if( (state == State::sData || state == State::sDiscarding) && isEndOfText(event_data) )
204 event = Event::eEot ;
206 else if( state == State::sData || state == State::sDiscarding )
208 event = Event::eContent ;
210 else if( state == State::sAuth )
212 event = Event::eAuthData ;
216 std::string line( line_data , line_data_size ) ;
218 event = commandEvent( commandWord(line) ) ;
219 m_buffer = commandLine( line ) ;
220 event_data = EventData( m_buffer.data() , m_buffer.size() ) ;
224 State new_state = m_fsm.apply( *
this , event , event_data ) ;
225 if( new_state == State::s_Any )
226 sendOutOfSequence() ;
230 return !halfDuplexBusy() ;
233void GSmtp::ServerProtocol::doContent( EventData event_data ,
bool & ok )
235 if( isEscaped(event_data) )
236 ok = m_message.addText( event_data.ptr+1 , event_data.size+event_data.eolsize-1U ) ;
238 ok = m_message.addText( event_data.ptr , event_data.size+event_data.eolsize ) ;
241 if( !ok && m_config.disconnect_on_max_size )
245void GSmtp::ServerProtocol::doEot( EventData ,
bool & )
247 G_LOG(
"GSmtp::ServerProtocol: rx<<: [message content not logged]" ) ;
248 G_LOG(
"GSmtp::ServerProtocol: rx<<: \".\"" ) ;
249 m_message.process( m_sasl->id() , m_peer_address.hostPartString() , m_certificate ) ;
252void GSmtp::ServerProtocol::processDone(
bool success ,
const MessageId &
id ,
253 const std::string & response ,
const std::string & reason )
255 GDEF_IGNORE_PARAMS( success ,
id , reason ) ;
256 G_DEBUG(
"GSmtp::ServerProtocol::processDone: " << (success?1:0) <<
" " <<
id.str()
257 <<
" [" << response <<
"] [" << reason <<
"]" ) ;
258 G_ASSERT( success == response.empty() ) ;
260 State new_state = m_fsm.apply( *
this , Event::eDone , EventData(response.data(),response.size()) ) ;
261 if( new_state == State::s_Any )
262 throw ProtocolDone(
"protocol error" ) ;
265void GSmtp::ServerProtocol::doComplete( EventData event_data ,
bool & )
268 const bool empty = event_data.size == 0U ;
269 sendCompletionReply( empty , std::string(event_data.ptr,event_data.size) ) ;
272void GSmtp::ServerProtocol::doEagerQuit( EventData ,
bool & )
277 if( m_config.ignore_eager_quit )
278 G_WARNING(
"GSmtp::ServerProtocol::doEagerQuit: ignoring out-of-sequence quit" ) ;
280 throw ProtocolDone(
"protocol error: out-of-sequence quit" ) ;
283void GSmtp::ServerProtocol::doQuit( EventData ,
bool & )
287 throw ProtocolDone() ;
290void GSmtp::ServerProtocol::doDiscard( EventData ,
bool & )
292 if( m_config.disconnect_on_max_size )
296 throw ProtocolDone() ;
300void GSmtp::ServerProtocol::doIgnore( EventData ,
bool & )
304void GSmtp::ServerProtocol::doNoop( EventData ,
bool & )
309void GSmtp::ServerProtocol::doNothing( EventData ,
bool & )
313void GSmtp::ServerProtocol::doDiscarded( EventData ,
bool & )
319void GSmtp::ServerProtocol::doExpn( EventData ,
bool & )
321 sendNotImplemented() ;
324void GSmtp::ServerProtocol::doHelp( EventData ,
bool & )
326 sendNotImplemented() ;
329void GSmtp::ServerProtocol::doVrfy( EventData event_data ,
bool & predicate )
331 std::string line( event_data.ptr , event_data.size ) ;
332 if( m_config.with_vrfy )
334 std::string to = parseRcptParameter( line ) ;
338 sendNotVerified(
"invalid mailbox" ,
false ) ;
348 sendNotImplemented() ;
352void GSmtp::ServerProtocol::verify(
const std::string & to ,
const std::string & from )
354 std::string mechanism = m_sasl->active() ? m_sasl->mechanism() : std::string() ;
355 std::string
id = m_sasl->active() ? m_sasl->id() : std::string() ;
356 if( m_sasl->active() && !m_session_authenticated )
358 m_verifier.verify( to , from , m_peer_address , mechanism ,
id ) ;
361void GSmtp::ServerProtocol::verifyDone(
const VerifierStatus & status )
363 G_DEBUG(
"GSmtp::ServerProtocol::verifyDone: verify done: [" << status.str() <<
"]" ) ;
365 throw ProtocolDone(
"address verifier abort" ) ;
367 std::string status_str = status.str() ;
368 State new_state = m_fsm.apply( *
this , Event::eVrfyReply , EventData(status_str.data(),status_str.size()) ) ;
369 if( new_state == State::s_Any )
370 throw ProtocolDone(
"protocol error" ) ;
373void GSmtp::ServerProtocol::doVrfyReply( EventData event_data ,
bool & )
375 std::string line( event_data.ptr , event_data.size ) ;
378 if( status.is_valid && status.is_local )
379 sendVerified( status.full_name ) ;
380 else if( status.is_valid )
381 sendWillAccept( status.recipient ) ;
383 sendNotVerified( status.response , status.temporary ) ;
386std::string GSmtp::ServerProtocol::parseRcptParameter(
const std::string & line )
const
389 std::size_t pos = line.find_first_of(
" \t" ) ;
390 if( pos != std::string::npos )
391 to = line.substr(pos) ;
397void GSmtp::ServerProtocol::doEhlo( EventData event_data ,
bool & predicate )
399 std::string line( event_data.ptr , event_data.size ) ;
400 std::string smtp_peer_name = parsePeerName( line ) ;
401 if( smtp_peer_name.empty() )
404 sendMissingParameter() ;
408 m_session_peer_name = smtp_peer_name ;
409 m_session_authenticated = false ;
415void GSmtp::ServerProtocol::doHelo( EventData event_data ,
bool & predicate )
417 std::string line( event_data.ptr , event_data.size ) ;
418 std::string smtp_peer_name = parsePeerName( line ) ;
419 if( smtp_peer_name.empty() )
422 sendMissingParameter() ;
426 m_session_peer_name = smtp_peer_name ;
432bool GSmtp::ServerProtocol::authenticationRequiresEncryption()
const
434 bool encryption_required_by_user = m_config.authentication_requires_encryption ;
435 bool encryption_required_by_sasl = m_sasl->active() && m_sasl->requiresEncryption() ;
436 return encryption_required_by_user || encryption_required_by_sasl ;
439void GSmtp::ServerProtocol::doAuthInvalid( EventData ,
bool & )
442 G_WARNING(
"GSmtp::ServerProtocol: client protocol error: AUTH requested but not advertised" ) ;
443 sendNotImplemented() ;
446void GSmtp::ServerProtocol::doAuth( EventData event_data ,
bool & predicate )
451 std::string mechanism = word_array.size() > 1U ?
G::Str::upper(word_array[1U]) : std::string() ;
452 std::string initial_response = word_array.size() > 2U ? word_array[2U] : std::string() ;
453 bool got_initial_response = word_array.size() > 2U ;
455 G_DEBUG(
"ServerProtocol::doAuth: [" << mechanism <<
"], [" << initial_response <<
"]" ) ;
457 if( !m_secure && authenticationRequiresEncryption() )
459 G_WARNING(
"GSmtp::ServerProtocol: rejecting authentication attempt without encryption" ) ;
463 else if( m_session_authenticated )
465 G_WARNING(
"GSmtp::ServerProtocol: too many AUTH requests" ) ;
467 sendOutOfSequence() ;
469 else if( ! m_sasl->init(mechanism) )
471 G_WARNING(
"GSmtp::ServerProtocol: request for unsupported server AUTH mechanism: " << mechanism ) ;
475 else if( got_initial_response && m_sasl->mustChallenge() )
477 G_WARNING(
"GSmtp::ServerProtocol: unexpected initial-response with a server-first AUTH mechanism" ) ;
479 sendInvalidArgument() ;
481 else if( got_initial_response && ( initial_response !=
"=" && !
G::Base64::valid(initial_response) ) )
483 G_WARNING(
"GSmtp::ServerProtocol: invalid base64 encoding of AUTH parameter" ) ;
485 sendInvalidArgument() ;
487 else if( got_initial_response )
489 std::string s = initial_response ==
"=" ? std::string() :
G::Base64::decode(initial_response) ;
491 std::string next_challenge = m_sasl->apply( s , done ) ;
495 m_session_authenticated = m_sasl->authenticated() ;
496 sendAuthDone( m_sasl->authenticated() ) ;
500 sendChallenge( next_challenge ) ;
505 sendChallenge( m_sasl->initialChallenge() ) ;
509void GSmtp::ServerProtocol::doAuthData( EventData event_data ,
bool & predicate )
511 G_LOG(
"GSmtp::ServerProtocol: rx<<: [authentication response not logged]" ) ;
512 std::string line( event_data.ptr , event_data.size ) ;
516 sendAuthenticationCancelled() ;
520 G_WARNING(
"GSmtp::ServerProtocol: invalid base64 encoding of authentication response" ) ;
522 sendAuthDone(
false ) ;
531 m_session_authenticated = m_sasl->authenticated() ;
532 send(
"535-more info at\r\n535 http://example.com" ) ;
537 m_session_authenticated = m_sasl->authenticated() ;
538 sendAuthDone( m_sasl->authenticated() ) ;
542 sendChallenge( next_challenge ) ;
547void GSmtp::ServerProtocol::doMail( EventData event_data ,
bool & predicate )
549 std::string line( event_data.ptr , event_data.size ) ;
550 if( !m_session_authenticated && m_sasl->active() && !m_sasl->trusted(m_peer_address) )
552 G_LOG(
"GSmtp::ServerProtocol::doMail: server authentication enabled "
553 "but not a trusted address: " << m_peer_address.hostPartString() ) ;
557 else if( !m_secure && m_config.mail_requires_encryption )
560 sendEncryptionRequired() ;
562 else if( m_config.max_size && parseMailSize(line) > m_config.max_size )
570 std::string from_address ;
571 std::string from_error_response ;
572 std::tie(from_address,from_error_response) = parseMailFrom( line ) ;
573 bool ok = from_error_response.empty() ;
574 m_message.setFrom( from_address , parseMailAuth(line) ) ;
582 sendBadFrom( from_error_response ) ;
587void GSmtp::ServerProtocol::doRcpt( EventData event_data ,
bool & predicate )
589 std::string to_address ;
590 std::string to_error_response ;
591 std::tie(to_address,to_error_response) = parseRcptTo( std::string(event_data.ptr,event_data.size) ) ;
592 bool ok = to_error_response.empty() ;
595 verify( to_address , m_message.from() ) ;
600 sendBadTo( to_error_response ,
false ) ;
604void GSmtp::ServerProtocol::doVrfyToReply( EventData event_data ,
bool & predicate )
608 bool ok = m_message.addTo( status ) ;
620void GSmtp::ServerProtocol::doUnknown( EventData event_data ,
bool & )
622 sendUnrecognised( std::string(event_data.ptr,event_data.size) ) ;
625void GSmtp::ServerProtocol::reset()
629 m_verifier.cancel() ;
632void GSmtp::ServerProtocol::doRset( EventData ,
bool & )
639void GSmtp::ServerProtocol::doNoRecipients( EventData ,
bool & )
644void GSmtp::ServerProtocol::doData( EventData ,
bool & )
646 std::string received_line = m_text.received( m_session_peer_name , m_session_authenticated ,
647 m_secure , m_protocol , m_cipher ) ;
649 if( received_line.length() )
650 m_message.addReceived( received_line ) ;
655bool GSmtp::ServerProtocol::isEndOfText(
const EventData & e )
const
657 return e.linesize == 1U && e.eolsize == 2U && e.c0 ==
'.' ;
660bool GSmtp::ServerProtocol::isEscaped(
const EventData & e )
const
662 return e.size > 1U && e.size == e.linesize && e.c0 ==
'.' ;
665std::string GSmtp::ServerProtocol::commandWord(
const std::string & line_in )
const
667 std::string line( line_in ) ;
670 std::size_t pos = line.find_first_of(
" \t" ) ;
671 std::string command = line.substr( 0U , pos ) ;
677std::string GSmtp::ServerProtocol::commandLine(
const std::string & line_in )
const
679 std::string line( line_in ) ;
684GSmtp::ServerProtocol::Event GSmtp::ServerProtocol::commandEvent(
const std::string & command )
const
686 if( command ==
"QUIT" )
return Event::eQuit ;
687 if( command ==
"HELO" )
return Event::eHelo ;
688 if( command ==
"EHLO" )
return Event::eEhlo ;
689 if( command ==
"RSET" )
return Event::eRset ;
690 if( command ==
"DATA" )
return Event::eData ;
691 if( command ==
"RCPT" )
return Event::eRcpt ;
692 if( command ==
"MAIL" )
return Event::eMail ;
693 if( command ==
"VRFY" )
return Event::eVrfy ;
694 if( command ==
"NOOP" )
return Event::eNoop ;
695 if( command ==
"EXPN" )
return Event::eExpn ;
696 if( command ==
"HELP" )
return Event::eHelp ;
697 if( command ==
"STARTTLS" && m_with_starttls )
return Event::eStartTls ;
698 if( command ==
"AUTH" )
return Event::eAuth ;
699 return Event::eUnknown ;
702const std::string & GSmtp::ServerProtocol::crlf()
704 static const std::string s(
"\015\012" ) ;
708void GSmtp::ServerProtocol::sendChallenge(
const std::string & challenge )
713void GSmtp::ServerProtocol::sendGreeting(
const std::string & text )
715 send(
"220 " + text ) ;
718void GSmtp::ServerProtocol::sendReadyForTls()
720 send(
"220 ready to start tls" ,
true ) ;
723void GSmtp::ServerProtocol::sendInvalidArgument()
725 send(
"501 invalid argument" ) ;
728void GSmtp::ServerProtocol::sendAuthenticationCancelled()
730 send(
"501 authentication cancelled" ) ;
733void GSmtp::ServerProtocol::sendBadMechanism()
735 send(
"504 unsupported authentication mechanism" ) ;
738void GSmtp::ServerProtocol::sendAuthDone(
bool ok )
741 send(
"235 authentication successful" ) ;
743 send(
"535 authentication failed" ) ;
746void GSmtp::ServerProtocol::sendOutOfSequence()
748 send(
"503 command out of sequence -- use RSET to resynchronise" ) ;
752void GSmtp::ServerProtocol::sendMissingParameter()
754 send(
"501 parameter required" ) ;
757void GSmtp::ServerProtocol::sendQuitOk()
760 m_sender.protocolShutdown() ;
763void GSmtp::ServerProtocol::sendClosing()
765 send(
"221 closing connection" ) ;
766 m_sender.protocolShutdown() ;
769void GSmtp::ServerProtocol::sendVerified(
const std::string & user )
771 send(
"250 " + user ) ;
774void GSmtp::ServerProtocol::sendNotVerified(
const std::string & response ,
bool temporary )
776 send( (temporary?
"450":
"550") + std::string(1U,
' ') + response ) ;
779void GSmtp::ServerProtocol::sendWillAccept(
const std::string & user )
784void GSmtp::ServerProtocol::sendUnrecognised(
const std::string & line_in )
786 std::string line = line_in.substr( 0U , 80U ) ;
787 if( line.size() >= 80U ) line.append(
" ..." ) ;
788 send(
"500 command unrecognized: \"" +
G::Str::printable(line) + std::string(1U,
'\"') ) ;
792void GSmtp::ServerProtocol::sendNotImplemented()
794 send(
"502 command not implemented" ) ;
797void GSmtp::ServerProtocol::sendAuthRequired()
799 std::string more_help = authenticationRequiresEncryption() && !m_secure ?
": use starttls" :
"" ;
800 send(
"530 authentication required" + more_help ) ;
803void GSmtp::ServerProtocol::sendEncryptionRequired()
805 send(
"538 encryption required: use starttls" ) ;
808void GSmtp::ServerProtocol::sendNoRecipients()
810 send(
"554 no valid recipients" ) ;
813void GSmtp::ServerProtocol::sendTooBig(
bool disconnecting )
815 std::string s =
"552 message exceeds fixed maximum message size" ;
816 if( disconnecting ) s.append(
", disconnecting" ) ;
820void GSmtp::ServerProtocol::sendDataReply()
822 send(
"354 start mail input -- end with <CRLF>.<CRLF>" ) ;
825void GSmtp::ServerProtocol::sendRsetReply()
827 send(
"250 state reset" ) ;
830void GSmtp::ServerProtocol::sendMailReply()
835void GSmtp::ServerProtocol::sendCompletionReply(
bool ok ,
const std::string & response )
841 send(
"452 " + response ) ;
844void GSmtp::ServerProtocol::sendRcptReply()
849void GSmtp::ServerProtocol::sendBadFrom(
const std::string & response_extra )
851 std::string response =
"553 mailbox name not allowed" ;
852 if( ! response_extra.empty() )
854 response.append(
": " ) ;
855 response.append( response_extra ) ;
860void GSmtp::ServerProtocol::sendBadTo(
const std::string & text ,
bool temporary )
862 send( (temporary?
"450":
"550") + std::string(text.empty()?
"":
" ") + text ) ;
865void GSmtp::ServerProtocol::sendEhloReply()
867 std::ostringstream ss ;
868 ss <<
"250-" << m_text.hello(m_session_peer_name) << crlf() ;
870 if( m_config.max_size != 0U )
871 ss <<
"250-SIZE " << m_config.max_size << crlf() ;
873 if( m_sasl->active() && !( authenticationRequiresEncryption() && !m_secure ) )
874 ss <<
"250-AUTH " << m_sasl->mechanisms(
' ') << crlf() ;
876 if( m_with_starttls && !m_secure )
877 ss <<
"250-STARTTLS" << crlf() ;
879 if( m_config.with_vrfy )
880 ss <<
"250-VRFY" << crlf() ;
882 ss <<
"250 8BITMIME" ;
886void GSmtp::ServerProtocol::sendHeloReply()
891void GSmtp::ServerProtocol::sendOk()
896void GSmtp::ServerProtocol::send(
const char * line )
898 send( std::string(line) ) ;
901void GSmtp::ServerProtocol::send( std::string line ,
bool go_secure )
904 line.append( crlf() ) ;
905 m_sender.protocolSend( line , go_secure ) ;
908void GSmtp::ServerProtocol::badClientEvent()
910 m_bad_client_count++ ;
911 if( m_bad_client_limit && m_bad_client_count >= m_bad_client_limit )
913 std::string reason =
"too many protocol errors from the client" ;
914 G_DEBUG(
"GSmtp::ServerProtocol::badClientEvent: " << reason <<
": dropping the connection" ) ;
915 throw ProtocolDone( reason ) ;
919std::size_t GSmtp::ServerProtocol::parseMailSize(
const std::string & line )
const
921 std::string parameter = parseMailParameter( line ,
"SIZE=" ) ;
928std::string GSmtp::ServerProtocol::parseMailAuth(
const std::string & line )
const
930 return parseMailParameter( line ,
"AUTH=" ) ;
933std::string GSmtp::ServerProtocol::parseMailParameter(
const std::string & line ,
const std::string & key )
const
936 std::size_t end = line.find(
'>' ) ;
937 if( end != std::string::npos )
940 for(
const auto & parameter : parameters )
943 if( pos == 0U && parameter.length() > key.size() )
954std::pair<std::string,std::string> GSmtp::ServerProtocol::parseMailFrom(
const std::string & line )
const
957 return parseAddress( line ) ;
960std::pair<std::string,std::string> GSmtp::ServerProtocol::parseRcptTo(
const std::string & line )
const
964 return parseAddress( line ) ;
967std::pair<std::string,std::string> GSmtp::ServerProtocol::parseAddress(
const std::string & line )
const
969 std::size_t start = line.find(
'<' ) ;
970 std::size_t end = line.find(
'>' ) ;
971 if( start == std::string::npos || end == std::string::npos || end < start )
973 std::string response(
"missing or invalid angle brackets in mailbox name" ) ;
974 return std::make_pair(std::string(),response) ;
977 std::string s = line.substr( start + 1U , end - start - 1U ) ;
981 if( s.length() > 0U && s.at(0U) ==
'@' )
983 std::size_t colon_pos = s.find(
':' ) ;
984 if( colon_pos == std::string::npos )
986 std::string response(
"invalid mailbox name: no colon after leading at character" ) ;
987 return std::make_pair(std::string(),response) ;
989 s = s.substr( colon_pos + 1U ) ;
992 return std::make_pair(s,std::string()) ;
995std::string GSmtp::ServerProtocol::parsePeerName(
const std::string & line )
const
997 std::size_t pos = line.find_first_of(
" \t" ) ;
998 if( pos == std::string::npos )
999 return std::string() ;
1001 std::string smtp_peer_name = line.substr( pos + 1U ) ;
1003 return smtp_peer_name ;
1010 m_code_ident(code_ident) ,
1011 m_thishost(thishost) ,
1012 m_peer_address(peer_address)
1016std::string GSmtp::ServerProtocolText::greeting()
const
1018 return m_thishost +
" -- " + m_code_ident +
" -- Service ready" ;
1021std::string GSmtp::ServerProtocolText::hello(
const std::string & )
const
1023 return m_thishost +
" says hello" ;
1026std::string GSmtp::ServerProtocolText::received(
const std::string & smtp_peer_name ,
1027 bool authenticated ,
bool secure ,
const std::string & protocol ,
const std::string & cipher )
const
1029 return receivedLine( smtp_peer_name , m_peer_address.hostPartString() , m_thishost ,
1030 authenticated , secure , protocol , cipher ) ;
1034 const std::string & peer_address ,
const std::string & thishost ,
1035 bool authenticated ,
bool secure ,
const std::string & ,
const std::string & cipher_in )
1042 const std::string esmtp = std::string(
"ESMTP") + (secure?
"S":
"") + (authenticated?
"A":
"") ;
1045 std::string cipher = secure ?
1050 std::ostringstream ss ;
1052 <<
"Received: from " << peer_name
1054 <<
"[" << peer_address <<
"]"
1055 <<
") by " << thishost <<
" with " << esmtp
1056 << (cipher.empty()?
"":
" tls ") << cipher
1061 << date.
yyyy() <<
" "
1062 << time.
hhmmss(
":") <<
" "
1069GSmtp::ServerProtocol::Config::Config()
1072GSmtp::ServerProtocol::Config::Config(
bool with_vrfy_in ,
unsigned int filter_timeout_in ,
1073 std::size_t max_size_in ,
bool authentication_requires_encryption_in ,
bool mail_requires_encryption_in ,
1074 bool tls_starttls_in ,
bool tls_connection_in ) :
1075 with_vrfy(with_vrfy_in) ,
1076 filter_timeout(filter_timeout_in) ,
1077 max_size(max_size_in) ,
1078 authentication_requires_encryption(authentication_requires_encryption_in) ,
1079 mail_requires_encryption(mail_requires_encryption_in) ,
1080 tls_starttls(tls_starttls_in) ,
1081 tls_connection(tls_connection_in)
1087GSmtp::ServerProtocol::EventData::EventData(
const char * ptr_ , std::size_t size_ ) :
1096GSmtp::ServerProtocol::EventData::EventData(
const char * ptr_ , std::size_t size_ ,
1097 std::size_t eolsize_ , std::size_t linesize_ ,
char c0_ ) :
1101 linesize(linesize_) ,
An interface used by GAuth::SaslServer to obtain authentication secrets.
The GNet::Address class encapsulates a TCP/UDP transport address.
static bool secureAcceptCapable()
Returns true if the implementation supports TLS/SSL and a "server" profile has been configured.
An interface used by the ServerProtocol class to assemble and process an incoming message.
virtual DoneSignal & doneSignal()=0
Returns a signal which is raised once process() has completed.
ServerProtocolText(const std::string &code_ident, const std::string &thishost, const GNet::Address &peer_address)
Constructor.
static std::string receivedLine(const std::string &smtp_peer_name_from_helo, const std::string &peer_address, const std::string &thishost, bool authenticated, bool secure, const std::string &secure_protocol, const std::string &secure_cipher)
Returns a standard "Received:" line.
An interface used by ServerProtocol to send protocol replies.
An interface used by ServerProtocol to provide response text strings.
bool apply(const char *line_data, std::size_t line_size, std::size_t eolsize, std::size_t linesize, char c0)
Called on receipt of a line of text from the remote client.
void init()
Starts the protocol.
void secure(const std::string &certificate, const std::string &protocol, const std::string &cipher)
To be called when the transport protocol goes into secure mode.
bool inDataState() const
Returns true if currently in the data-transfer state.
ServerProtocol(Sender &, Verifier &, ProtocolMessage &, const GAuth::SaslServerSecrets &secrets, const std::string &sasl_server_config, Text &text, const GNet::Address &peer_address, const Config &config)
Constructor.
bool halfDuplexBusy() const
Returns true if the protocol has received a command but not yet sent a response.
virtual ~ServerProtocol()
Destructor.
static VerifierStatus parse(const std::string &str)
Parses a str() string into a structure.
An asynchronous interface that verifies recipient 'to' addresses.
virtual G::Slot::Signal< const VerifierStatus & > & doneSignal()=0
Returns a signal that is emit()ed when the verify() request is complete.
static std::string decode(const std::string &, bool throw_on_invalid=false, bool strict=true)
Decodes the given string.
static std::string encode(const std::string &s, const std::string &line_break=std::string())
Encodes the given string, optionally inserting line-breaks to limit the line length.
static bool valid(const std::string &, bool strict=true)
Returns true if the string is a valid base64 encoding, possibly allowing for embedded newlines,...
An encapsulation of 'struct std::tm'.
static Offset offset(SystemTime)
Returns the offset in seconds between UTC and localtime as at the given system time.
static std::string offsetString(Offset offset)
Converts the given utc/localtime offset into a five-character "+/-hhmm" string.
A day-month-year date class.
std::string monthName(bool brief=false) const
Returns the month as a string (in english).
std::string weekdayName(bool brief=false) const
Returns an english string representation of the day of the week.
int monthday() const
Returns the day of the month.
std::string yyyy() const
Returns the year as a four-digit decimal string.
State reset(State new_state)
Sets the current state. Returns the old state.
static string_view alnum()
Returns a string of seven-bit alphanumeric characters, ie A-Z, a-z and 0-9.
static std::string replaced(const std::string &s, char from, char to)
Returns the string 's' with all occurrences of 'from' replaced by 'to'.
static std::string & trimLeft(std::string &s, string_view ws, std::size_t limit=0U)
Trims the lhs of s, taking off up to 'limit' of the 'ws' characters.
static void splitIntoTokens(const std::string &in, StringArray &out, string_view ws, char esc='\0')
Splits the string into 'ws'-delimited tokens.
static std::string toPrintableAscii(const std::string &in, char escape='\\')
Returns a 7-bit printable representation of the given input string.
static bool isULong(const std::string &s)
Returns true if the string can be converted into an unsigned long without throwing an exception.
static std::string upper(const std::string &s)
Returns a copy of 's' in which all Latin-1 lower-case characters have been replaced by upper-case cha...
static std::string printable(const std::string &in, char escape='\\')
Returns a printable representation of the given input string, using chacter code ranges 0x20 to 0x7e ...
static std::string only(const std::string &allow_chars, const std::string &s)
Returns the 's' with all occurrences of the characters not appearing in the fist string deleted.
static void toUpper(std::string &s)
Replaces all Latin-1 lower-case characters in string 's' by upper-case characters.
static unsigned long toULong(const std::string &s, Limited)
Converts string 's' to an unsigned long.
static std::string & trim(std::string &s, string_view ws)
Trims both ends of s, taking off any of the 'ws' characters.
Represents a unix-epoch time with microsecond resolution.
static SystemTime now()
Factory function for the current time.
BrokenDownTime local() const
Returns the locale-dependent local broken-down time.
static bool enabled() noexcept
Returns true if test features are enabled.
A simple time-of-day (hh/mm/ss) class.
std::string hhmmss(const char *sep=nullptr) const
Returns the hhmmss string.
static std::string decode(const std::string &)
Decodes the given string.
static std::string encode(const std::string &)
Encodes the given string.
SASL authentication classes.
Slot< Args... > slot(TSink &sink, void(TSink::*method)(Args...))
A factory function for Slot objects.
std::vector< std::string > StringArray
A std::vector of std::strings.
A structure containing configuration parameters for ServerProtocol.
Overload discrimiator for G::Str::toUWhatever() requesting a range-limited result.