E-MailRelay

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

gsmtpserver.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2018 Graeme Walker <graeme_walker@users.sourceforge.net>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gsmtpserver.cpp
19 //
20
21 #include "gdef.h"
22 #include "gsmtp.h"
23 #include "gsmtpserver.h"
24 #include "gresolver.h"
25 #include "gprotocolmessagestore.h"
26 #include "gprotocolmessageforward.h"
27 #include "gfilterfactory.h"
28 #include "gverifierfactory.h"
29 #include "glocal.h"
30 #include "glog.h"
31 #include "gdebug.h"
32 #include "gassert.h"
33 #include "gtest.h"
34 #include <string>
35 #include <functional>
36
37 namespace
38 {
39 struct AnonymousText : public GSmtp::ServerProtocol::Text
40 {
41 explicit AnonymousText( const std::string & = std::string() ) ;
42 virtual std::string greeting() const ;
43 virtual std::string hello( const std::string & peer_name ) const ;
44 virtual std::string received( const std::string & smtp_peer_name , bool , bool ) const ;
45 std::string m_thishost ;
46 } ;
47 }
48
49 AnonymousText::AnonymousText( const std::string & thishost ) :
50 m_thishost(thishost)
51 {
52 if( m_thishost.empty() )
53 m_thishost = "smtp" ;
54 }
55
56 std::string AnonymousText::greeting() const
57 {
58 return "ready" ;
59 }
60
61 std::string AnonymousText::hello( const std::string & ) const
62 {
63 return m_thishost + " says hello" ;
64 }
65
66 std::string AnonymousText::received( const std::string & smtp_peer_name , bool authenticated , bool secure ) const
67 {
68 return std::string() ; // no Received line
69 }
70
71 // ===
72
73 GSmtp::ServerPeer::ServerPeer( GNet::Server::PeerInfo peer_info , Server & server ,
74 const GAuth::Secrets & server_secrets , const Server::Config & server_config ,
75 unique_ptr<ServerProtocol::Text> ptext ) :
76 GNet::ServerPeer(peer_info) ,
77 m_server(server) ,
78 m_verifier(VerifierFactory::newVerifier(*this,server_config.verifier_address,server_config.verifier_timeout,server_config.verifier_compatibility)) ,
79 m_pmessage(server.newProtocolMessage(*this)) ,
80 m_ptext(ptext.release()) ,
81 m_line_buffer(GNet::LineBufferConfig::smtp()) ,
82 m_protocol(*this,*this,*m_verifier.get(),*m_pmessage.get(),server_secrets,*m_ptext.get(),
83 peer_info.m_address,server_config.protocol_config)
84 {
85 G_LOG_S( "GSmtp::ServerPeer: smtp connection from " << peer_info.m_address.displayString() ) ;
86 m_protocol.init() ;
87 }
88
89 void GSmtp::ServerPeer::onDelete( const std::string & reason )
90 {
91 G_LOG_S( "GSmtp::ServerPeer: smtp connection closed: " << reason << (reason.empty()?"":": ")
92 << peerAddress().second.displayString() ) ;
93
94 m_server.eventSignal().emit( "done" , reason ) ;
95 }
96
97 void GSmtp::ServerPeer::onSendComplete()
98 {
99 // never gets here -- see protocolSend()
100 }
101
102 namespace
103 {
104 struct Adaptor
105 {
106 GSmtp::ServerProtocol & m_protocol ;
107 Adaptor( GSmtp::ServerProtocol & protocol ) : m_protocol(protocol) {}
108 bool operator()( const char * p , size_t n , size_t e )
109 {
110 return m_protocol.apply( p , n , e ) ;
111 }
112 } ;
113 }
114
115 void GSmtp::ServerPeer::onData( const char * line_data , size_t line_size )
116 {
117 G_ASSERT( line_size != 0U ) ; if( line_size == 0U ) return ;
118 Adaptor a( m_protocol ) ;
119 m_line_buffer.apply( line_data , line_size , a ) ;
120 }
121
122 void GSmtp::ServerPeer::onSecure( const std::string & certificate )
123 {
124 m_protocol.secure( certificate ) ;
125 }
126
127 void GSmtp::ServerPeer::protocolSend( const std::string & line , bool go_secure )
128 {
129 if( !send( line , 0U ) ) // GNet::ServerPeer::send()
130 throw SendError() ; // we only send short responses, so treat flow control as fatal
131
132 if( go_secure )
133 secureAccept() ;
134 }
135
136 void GSmtp::ServerPeer::protocolShutdown()
137 {
138 socket().shutdown() ; // fwiw
139 }
140
141 // ===
142
143 GSmtp::Server::Server( GNet::ExceptionHandler & eh , MessageStore & store ,
144 const GAuth::Secrets & client_secrets , const GAuth::Secrets & server_secrets ,
145 Config server_config , std::string forward_to , GSmtp::Client::Config client_config ) :
146 GNet::MultiServer( eh , GNet::MultiServer::addressList(server_config.interfaces,server_config.port) ) ,
147 m_store(store) ,
148 m_server_config(server_config) ,
149 m_client_config(client_config) ,
150 m_server_secrets(server_secrets) ,
151 m_forward_to(forward_to) ,
152 m_client_secrets(client_secrets)
153 {
154 }
155
156 GSmtp::Server::~Server()
157 {
158 // early cleanup -- not really required
159 serverCleanup() ; // base class
160 }
161
162 G::Slot::Signal2<std::string,std::string> & GSmtp::Server::eventSignal()
163 {
164 return m_event_signal ;
165 }
166
167 void GSmtp::Server::report() const
168 {
169 serverReport( "smtp" ) ; // base class
170 }
171
172 GNet::ServerPeer * GSmtp::Server::newPeer( GNet::Server::PeerInfo peer_info , GNet::MultiServer::ServerInfo )
173 {
174 try
175 {
176 std::string reason ;
177 if( ! m_server_config.allow_remote && ! GNet::Local::isLocal(peer_info.m_address,reason) )
178 {
179 G_WARNING( "GSmtp::Server: configured to reject non-local smtp connection: " << reason ) ;
180 return nullptr ;
181 }
182
183 return new ServerPeer( peer_info , *this ,
184 m_server_secrets , m_server_config ,
185 unique_ptr<ServerProtocol::Text>(newProtocolText(m_server_config.anonymous,peer_info.m_address)) ) ;
186 }
187 catch( std::exception & e ) // newPeer()
188 {
189 G_WARNING( "GSmtp::Server: exception from new connection: " << e.what() ) ;
190 return nullptr ;
191 }
192 }
193
194 unique_ptr<GSmtp::ServerProtocol::Text> GSmtp::Server::newProtocolText( bool anonymous , const GNet::Address & peer_address ) const
195 {
196 if( anonymous )
197 return unique_ptr<ServerProtocol::Text>( new AnonymousText ) ;
198 else
199 return unique_ptr<ServerProtocol::Text>( new ServerProtocolText( m_server_config.ident , GNet::Local::canonicalName() , peer_address ) ) ;
200 }
201
202 unique_ptr<GSmtp::Filter> GSmtp::Server::newFilter( ServerPeer & server_peer )
203 {
204 return FilterFactory::newFilter( server_peer , true , m_server_config.filter_address , m_server_config.filter_timeout ) ;
205 }
206
207 unique_ptr<GSmtp::ProtocolMessage> GSmtp::Server::newProtocolMessageStore( unique_ptr<Filter> filter )
208 {
209 return unique_ptr<ProtocolMessage>( new ProtocolMessageStore( m_store , unique_ptr<Filter>(filter.release()) ) ) ;
210 }
211
212 unique_ptr<GSmtp::ProtocolMessage> GSmtp::Server::newProtocolMessageForward( unique_ptr<ProtocolMessage> pm )
213 {
214 // wrap the given 'store' object in a 'forward' one
215 return unique_ptr<ProtocolMessage>( new ProtocolMessageForward( m_store , unique_ptr<ProtocolMessage>(pm.release()) ,
216 m_client_config , m_client_secrets , m_forward_to ) ) ;
217 }
218
219 unique_ptr<GSmtp::ProtocolMessage> GSmtp::Server::newProtocolMessage( ServerPeer & server_peer )
220 {
221 const bool do_forward = ! m_forward_to.empty() ;
222 return do_forward ?
223 newProtocolMessageForward( newProtocolMessageStore(newFilter(server_peer)) ) :
224 newProtocolMessageStore( newFilter(server_peer) ) ;
225 }
226
227 // ===
228
229 GSmtp::Server::Config::Config( bool allow_remote_ , unsigned int port_ , const AddressList & interfaces_ ,
230 const std::string & ident_ , bool anonymous_ ,
231 const std::string & filter_address_ ,
232 unsigned int filter_timeout_ ,
233 const std::string & verifier_address_ ,
234 unsigned int verifier_timeout_ ,
235 bool verifier_compatibility_ ,
236 ServerProtocol::Config protocol_config_ ) :
237 allow_remote(allow_remote_) ,
238 port(port_) ,
239 interfaces(interfaces_) ,
240 ident(ident_) ,
241 anonymous(anonymous_) ,
242 filter_address(filter_address_) ,
243 filter_timeout(filter_timeout_) ,
244 verifier_address(verifier_address_) ,
245 verifier_timeout(verifier_timeout_) ,
246 verifier_compatibility(verifier_compatibility_) ,
247 protocol_config(protocol_config_)
248 {
249 }
250
251 /// \file gsmtpserver.cpp
gprotocolmessagestore.h
GSmtp::Server::~Server
virtual ~Server()
Destructor.
Definition: gsmtpserver.cpp:156
GNet::ServerPeer
An abstract base class for the GNet::Server's connection to a remote client.
Definition: gserver.h:173
GSmtp::ServerPeer::ServerPeer
ServerPeer(GNet::Server::PeerInfo peer_info, Server &server, const GAuth::Secrets &server_secrets, const Server::Config &server_config, unique_ptr< ServerProtocol::Text > ptext)
Constructor.
Definition: gsmtpserver.cpp:73
GSmtp::Server::newProtocolMessage
unique_ptr< ProtocolMessage > newProtocolMessage(ServerPeer &)
Called by GSmtp::ServerPeer to construct a ProtocolMessage.
Definition: gsmtpserver.cpp:219
GNet::Local::canonicalName
static std::string canonicalName()
Returns the canonical network name assiciated with hostname().
Definition: glocal.cpp:54
GSmtp::ServerPeer
Handles a connection from a remote SMTP client.
Definition: gsmtpserver.h:121
gsmtpserver.h
gfilterfactory.h
GNet
Network classes.
Definition: gaddress.h:29
GSmtp::ServerProtocol::Text
An interface used by ServerProtocol to provide response text strings.
Definition: gserverprotocol.h:76
glog.h
GSmtp::ServerPeer::onSecure
virtual void onSecure(const std::string &) override
Override from GNet::SocketProtocolSink.
Definition: gsmtpserver.cpp:122
G::Slot::Signal2< std::string, std::string >
GNet::Address
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:54
GSmtp::ServerPeer::onDelete
virtual void onDelete(const std::string &reason) override
Override from GNet::ServerPeer.
Definition: gsmtpserver.cpp:89
GSmtp::ServerProtocol
Implements the SMTP server-side protocol.
Definition: gserverprotocol.h:58
GSmtp::Server::Server
Server(GNet::ExceptionHandler &eh, MessageStore &store, const GAuth::Secrets &client_secrets, const GAuth::Secrets &server_secrets, Config server_config, std::string forward_to, GSmtp::Client::Config client_config)
Constructor.
Definition: gsmtpserver.cpp:143
GSmtp::Server::report
void report() const
Generates helpful diagnostics after construction.
Definition: gsmtpserver.cpp:167
gtest.h
GSmtp::ServerPeer::onData
virtual void onData(const char *, size_t) override
Override from GNet::SocketProtocolSink.
Definition: gsmtpserver.cpp:115
GNet::ExceptionHandler
An abstract interface for handling exceptions thrown out of event-loop callbacks (socket events...
Definition: gexceptionhandler.h:44
GSmtp::ServerProtocol::init
void init()
Starts the protocol. Use only once after construction.
Definition: gserverprotocol.cpp:105
GSmtp::Server::Config
A structure containing GSmtp::Server configuration parameters.
Definition: gsmtpserver.h:55
gassert.h
GSmtp::MessageStore
A class which allows SMTP messages to be stored and retrieved.
Definition: gmessagestore.h:43
GAuth::Secrets
A simple interface for a store of secrets used in authentication.
Definition: gsecrets.h:40
GSmtp::FilterFactory::newFilter
static unique_ptr< Filter > newFilter(GNet::ExceptionHandler &, bool server_side, const std::string &identifier, unsigned int timeout)
Returns a Filter on the heap.
Definition: gfilterfactory.cpp:37
GSmtp::Server
An SMTP server class.
Definition: gsmtpserver.h:49
GNet::MultiServer::ServerInfo
A structure used in GNet::MultiServer::newPeer().
Definition: gmultiserver.h:100
GNet::Local::isLocal
static bool isLocal(const Address &, std::string &reason)
Returns true if the given address appears to be associated with the local host, or a helpful error me...
Definition: glocal.cpp:65
GSmtp::Client::Config
A structure containing GSmtp::Client configuration parameters.
Definition: gsmtpclient.h:55
GSmtp::VerifierFactory
A factory for addresss verifiers.
Definition: gverifierfactory.h:39
GSmtp::ServerProtocol::Config
A structure containing configuration parameters for ServerProtocol.
Definition: gserverprotocol.h:84
glocal.h
gverifierfactory.h
GSmtp::Server::eventSignal
G::Slot::Signal2< std::string, std::string > & eventSignal()
Returns a signal that indicates that something has happened.
Definition: gsmtpserver.cpp:162
gsmtp.h
gprotocolmessageforward.h
GSmtp::ServerProtocol::apply
bool apply(const char *line_data, size_t line_size, size_t eolsize)
Called on receipt of a line of text from the remote client Returns true.
Definition: gserverprotocol.cpp:148
GSmtp::ServerPeer::onSendComplete
virtual void onSendComplete() override
Override from GNet::ServerPeer.
Definition: gsmtpserver.cpp:97
GNet::Server::PeerInfo
A structure used in GNet::Server::newPeer().
Definition: gserver.h:85
GNet::Address::displayString
std::string displayString() const
Returns a string which represents the transport address for debugging and diagnostics purposes...
Definition: gaddress_ipv4.cpp:129
gdebug.h
gresolver.h