- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

gsmtpserver.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2013 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 "gprocessorfactory.h"
28 #include "gverifierfactory.h"
29 #include "gmemory.h"
30 #include "glocal.h"
31 #include "glog.h"
32 #include "gdebug.h"
33 #include "gassert.h"
34 #include "gtest.h"
35 #include <string>
36
37 namespace
38 {
39 struct AnonymousText : public GSmtp::ServerProtocol::Text
40 {
41 AnonymousText( const std::string & thishost , const GNet::Address & peer_address , const std::string & peer_socket_name ) ;
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 ) const ;
45 std::string m_thishost ;
46 GNet::Address m_peer_address ;
47 std::string m_peer_socket_name ;
48 } ;
49 }
50
51 AnonymousText::AnonymousText( const std::string & thishost , const GNet::Address & peer_address , const std::string & peer_socket_name ) :
52 m_thishost(thishost) ,
53 m_peer_address(peer_address) ,
54 m_peer_socket_name(peer_socket_name)
55 {
56 }
57
58 std::string AnonymousText::greeting() const
59 {
60 return "ready" ;
61 }
62
63 std::string AnonymousText::hello( const std::string & ) const
64 {
65 return "hello" ;
66 }
67
68 std::string AnonymousText::received( const std::string & smtp_peer_name ) const
69 {
70 return
71 m_thishost.length() ?
72 GSmtp::ServerProtocolText::receivedLine( smtp_peer_name , m_peer_address.displayString(false) , m_peer_socket_name , m_thishost ) :
73 std::string() ; // no Received line at all if no hostname
74 }
75
76 // ===
77
78 GSmtp::ServerPeer::ServerPeer( GNet::Server::PeerInfo peer_info ,
79 Server & server , std::auto_ptr<ProtocolMessage> pmessage , const GAuth::Secrets & server_secrets ,
80 const std::string & verifier_address , unsigned int verifier_timeout ,
81 std::auto_ptr<ServerProtocol::Text> ptext ,
82 ServerProtocol::Config protocol_config ) :
83 GNet::BufferedServerPeer( peer_info , crlf() ) ,
84 m_server( server ) ,
85 m_verifier( VerifierFactory::newVerifier(verifier_address,verifier_timeout) ) ,
86 m_pmessage( pmessage ) ,
87 m_ptext( ptext ) ,
88 m_protocol( *this , *m_verifier.get() , *m_pmessage.get() , server_secrets , *m_ptext.get() ,
89 peer_info.m_address , peer_info.m_name , protocol_config )
90 {
91 G_LOG_S( "GSmtp::ServerPeer: smtp connection from " << peer_info.m_address.displayString()
92 << (peer_info.m_name.empty()?"":" ") << peer_info.m_name ) ;
93 m_protocol.init() ;
94 }
95
96 const std::string & GSmtp::ServerPeer::crlf()
97 {
98 static const std::string s( "\015\012" ) ;
99 return s ;
100 }
101
102 void GSmtp::ServerPeer::onDelete( const std::string & reason )
103 {
104 G_LOG_S( "GSmtp::ServerPeer: smtp connection closed: " << reason << (reason.empty()?"":": ")
105 << peerAddress().second.displayString() ) ;
106
107 m_server.eventSignal().emit( "done" , reason ) ;
108 }
109
110 void GSmtp::ServerPeer::onSendComplete()
111 {
112 // never gets here -- see GNet::Sender ctor
113 }
114
115 bool GSmtp::ServerPeer::onReceive( const std::string & line )
116 {
117 // apply the line to the protocol
118 m_protocol.apply( line ) ;
119 return true ;
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 send( line , 0U ) ; // GNet::Sender -- may throw SendError
130 if( go_secure )
131 sslAccept() ;
132 }
133
134 // ===
135
136 GSmtp::Server::Server( MessageStore & store , const GAuth::Secrets & client_secrets ,
137 const GAuth::Secrets & server_secrets , Config config , std::string smtp_server_address ,
138 unsigned int smtp_connection_timeout , GSmtp::Client::Config client_config ) :
139 GNet::MultiServer( GNet::MultiServer::addressList(config.interfaces,config.port) , config.use_connection_lookup ) ,
140 m_store(store) ,
141 m_processor_address(config.processor_address) ,
142 m_processor_timeout(config.processor_timeout) ,
143 m_client_config(client_config) ,
144 m_ident(config.ident) ,
145 m_allow_remote(config.allow_remote) ,
146 m_server_secrets(server_secrets) ,
147 m_smtp_server(smtp_server_address) ,
148 m_smtp_connection_timeout(smtp_connection_timeout) ,
149 m_client_secrets(client_secrets) ,
150 m_verifier_address(config.verifier_address) ,
151 m_verifier_timeout(config.verifier_timeout) ,
152 m_anonymous(config.anonymous)
153 {
154 }
155
156 GSmtp::Server::~Server()
157 {
158 // early cleanup -- not really required
159 serverCleanup() ; // base class
160 }
161
162 G::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 )
173 {
174 try
175 {
176 std::string reason ;
177 if( ! m_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 NULL ;
181 }
182
183 std::auto_ptr<ServerProtocol::Text> ptext( newProtocolText(m_anonymous,peer_info.m_address,peer_info.m_name) ) ;
184 std::auto_ptr<ProtocolMessage> pmessage( newProtocolMessage() ) ;
185 return new ServerPeer( peer_info , *this , pmessage , m_server_secrets ,
186 m_verifier_address , m_verifier_timeout ,
187 ptext , ServerProtocol::Config(!m_anonymous,m_processor_timeout) ) ;
188 }
189 catch( std::exception & e ) // newPeer()
190 {
191 G_WARNING( "GSmtp::Server: exception from new connection: " << e.what() ) ;
192 return NULL ;
193 }
194 }
195
196 GSmtp::ServerProtocol::Text * GSmtp::Server::newProtocolText( bool anonymous , GNet::Address peer_address , const std::string & peer_socket_name ) const
197 {
198 if( anonymous )
199 return new AnonymousText( GNet::Local::fqdn() , peer_address , peer_socket_name ) ;
200 else
201 return new ServerProtocolText( m_ident , GNet::Local::fqdn() , peer_address , peer_socket_name ) ;
202 }
203
204 GSmtp::ProtocolMessage * GSmtp::Server::newProtocolMessageStore( std::auto_ptr<Processor> processor )
205 {
206 return new ProtocolMessageStore( m_store , processor ) ;
207 }
208
209 GSmtp::ProtocolMessage * GSmtp::Server::newProtocolMessageForward( std::auto_ptr<ProtocolMessage> pm )
210 {
211 #ifdef USE_NO_PROXY
212 throw G::Exception( "proxying disabled at build time" ) ;
213 #else
214 return new ProtocolMessageForward( m_store , pm ,
215 m_client_config , m_client_secrets , m_smtp_server , m_smtp_connection_timeout ) ;
216 #endif
217 }
218
219 GSmtp::ProtocolMessage * GSmtp::Server::newProtocolMessage()
220 {
221 // dependency injection...
222 std::auto_ptr<Processor> store_processor( ProcessorFactory::newProcessor(m_processor_address,m_processor_timeout) );
223 std::auto_ptr<ProtocolMessage> pmstore( newProtocolMessageStore(store_processor) ) ;
224 const bool do_forward = ! m_smtp_server.empty() ;
225 if( do_forward )
226 {
227 std::auto_ptr<ProtocolMessage> forward( newProtocolMessageForward(pmstore) ) ;
228 return forward.release() ;
229 }
230 else
231 {
232 return pmstore.release() ;
233 }
234 }
235
236 // ===
237
238 GSmtp::Server::Config::Config( bool allow_remote_ , unsigned int port_ , const AddressList & interfaces_ ,
239 const std::string & ident_ , bool anonymous_ ,
240 const std::string & processor_address_ ,
241 unsigned int processor_timeout_ ,
242 const std::string & verifier_address_ ,
243 unsigned int verifier_timeout_ ,
244 bool use_connection_lookup_ ) :
245 allow_remote(allow_remote_) ,
246 port(port_) ,
247 interfaces(interfaces_) ,
248 ident(ident_) ,
249 anonymous(anonymous_) ,
250 processor_address(processor_address_) ,
251 processor_timeout(processor_timeout_) ,
252 verifier_address(verifier_address_) ,
253 verifier_timeout(verifier_timeout_) ,
254 use_connection_lookup(use_connection_lookup_)
255 {
256 }
257
gprotocolmessagestore.h
GSmtp::Server::~Server
virtual ~Server()
Destructor.
Definition: gsmtpserver.cpp:156
G_LOG_S
#define G_LOG_S(expr)
Definition: glog.h:103
GSmtp::Server::newPeer
GNet::ServerPeer * newPeer(GNet::Server::PeerInfo)
From MultiServer.
Definition: gsmtpserver.cpp:172
GNet::ServerPeer
An abstract base class for the GNet::Server's connection to a remote client.
Definition: gserver.h:191
G::Signal2< std::string, std::string >
GSmtp::ServerPeer
Represents a connection from an SMTP client.
Definition: gsmtpserver.h:54
gsmtpserver.h
GNet
Network classes.
GSmtp::ServerProtocol::Text
An interface used by ServerProtocol to provide response text strings.
Definition: gserverprotocol.h:70
glog.h
GSmtp::ProcessorFactory::newProcessor
static Processor * newProcessor(const std::string &address, unsigned int timeout)
Returns a Processor on the heap.
Definition: gprocessorfactory_exec_enabled.cpp:37
GSmtp::ServerProtocol::Text::greeting
virtual std::string greeting() const =0
GNet::Address
The Address class encapsulates an IP transport address.
Definition: gaddress.h:48
GNet::Local::isLocal
static bool isLocal(const Address &)
Returns true if the given address appears to be local.
Definition: glocal.cpp:82
GNet::Local::fqdn
static std::string fqdn()
Returns the fully-qualified-domain-name.
Definition: glocal.cpp:67
GSmtp::Server::Server
Server(MessageStore &store, const GAuth::Secrets &client_secrets, const GAuth::Secrets &server_secrets, Config server_config, std::string smtp_server_address, unsigned int smtp_connection_timeout, GSmtp::Client::Config client_config)
Constructor.
Definition: gsmtpserver.cpp:136
GNet::Server::PeerInfo::m_address
Address m_address
Definition: gserver.h:94
GSmtp::Server::report
void report() const
Generates helpful diagnostics after construction.
Definition: gsmtpserver.cpp:167
gtest.h
GSmtp::ServerProtocol::Text::received
virtual std::string received(const std::string &smtp_peer_name) const =0
GSmtp::Server::eventSignal
G::Signal2< std::string, std::string > & eventSignal()
Returns a signal that indicates that something has happened.
Definition: gsmtpserver.cpp:162
GSmtp::ServerProtocol::init
void init()
Starts the protocol. Use only once after construction.
Definition: gserverprotocol.cpp:107
GSmtp::Server::Config
A structure containing GSmtp::Server configuration parameters.
Definition: gsmtpserver.h:99
GSmtp::ServerPeer::onReceive
virtual bool onReceive(const std::string &line)
Final override from GNet::BufferedServerPeer.
Definition: gsmtpserver.cpp:115
GNet::Server::PeerInfo::m_name
std::string m_name
Definition: gserver.h:95
GNet::Address::displayString
std::string displayString(bool with_port=true, bool with_scope_id=false) const
Returns a string which represents the address for debugging and diagnostics purposes.
Definition: gaddress_ipv4.cpp:581
gassert.h
GSmtp::MessageStore
A class which allows SMTP messages (envelope+content) to be stored and retrieved. ...
Definition: gmessagestore.h:45
GAuth::Secrets
A simple interface to a store of secrets as used in authentication.
Definition: gsecrets.h:44
GSmtp::ServerPeer::onDelete
virtual void onDelete(const std::string &reason)
Final override from GNet::ServerPeer.
Definition: gsmtpserver.cpp:102
GSmtp::ServerPeer::onSecure
virtual void onSecure(const std::string &)
Final override from GNet::SocketProtocolSink.
Definition: gsmtpserver.cpp:122
GSmtp::Server
An SMTP server class.
Definition: gsmtpserver.h:92
GSmtp::ServerProtocolText
A default implementation for the ServerProtocol::Text interface.
Definition: gserverprotocol.h:274
GSmtp::Client::Config
A structure containing GSmtp::Client configuration parameters.
Definition: gsmtpclient.h:61
GSmtp::VerifierFactory
A factory for addresss verifiers.
Definition: gverifierfactory.h:39
GSmtp::ServerProtocol::Config
A structure containing configuration parameters for ServerProtocol.
Definition: gserverprotocol.h:79
gprocessorfactory.h
G::Exception
A general-purpose exception class derived from std::exception and containing a std::string.
Definition: gexception.h:44
GSmtp::ServerPeer::onSendComplete
virtual void onSendComplete()
Final override from GNet::BufferedServerPeer.
Definition: gsmtpserver.cpp:110
GSmtp::ProtocolMessage
An interface used by the ServerProtocol class to assemble and process an incoming message...
Definition: gprotocolmessage.h:64
GSmtp::Server::Config::Config
Config(bool, unsigned int, const AddressList &, const std::string &, bool, const std::string &, unsigned int, const std::string &, unsigned int, bool)
Definition: gsmtpserver.cpp:238
glocal.h
GSmtp::ServerPeer::ServerPeer
ServerPeer(GNet::Server::PeerInfo, Server &server, std::auto_ptr< ProtocolMessage > pmessage, const GAuth::Secrets &, const std::string &verifier_address, unsigned int verifier_timeout, std::auto_ptr< ServerProtocol::Text > ptext, ServerProtocol::Config)
Constructor.
Definition: gsmtpserver.cpp:78
GSmtp::ServerProtocol::Text::hello
virtual std::string hello(const std::string &smtp_peer_name) const =0
gverifierfactory.h
GNet::MultiServer::AddressList
std::list< Address > AddressList
Definition: gmultiserver.h:105
gsmtp.h
gprotocolmessageforward.h
gmemory.h
GNet::Server::PeerInfo
A structure used in GNet::Server::newPeer().
Definition: gserver.h:91
GSmtp::ServerProtocolText::receivedLine
static std::string receivedLine(const std::string &smtp_peer_name_from_helo, const std::string &peer_address, const std::string &peer_socket_name, const std::string &thishost)
Returns a standard "Received:" line.
Definition: gserverprotocol.cpp:865
G_WARNING
#define G_WARNING(expr)
Definition: glog.h:107
gdebug.h
gresolver.h