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"
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 
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 
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 
157 {
158  // early cleanup -- not really required
159  serverCleanup() ; // base class
160 }
161 
163 {
164  return m_event_signal ;
165 }
166 
168 {
169  serverReport( "smtp" ) ; // base class
170 }
171 
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 
virtual ~Server()
Destructor.
#define G_LOG_S(expr)
Definition: glog.h:103
GNet::ServerPeer * newPeer(GNet::Server::PeerInfo)
From MultiServer.
An abstract base class for the GNet::Server's connection to a remote client.
Definition: gserver.h:191
Represents a connection from an SMTP client.
Definition: gsmtpserver.h:54
Network classes.
An interface used by ServerProtocol to provide response text strings.
static Processor * newProcessor(const std::string &address, unsigned int timeout)
Returns a Processor on the heap.
virtual std::string greeting() const =0
The Address class encapsulates an IP transport address.
Definition: gaddress.h:48
static bool isLocal(const Address &)
Returns true if the given address appears to be local.
Definition: glocal.cpp:82
static std::string fqdn()
Returns the fully-qualified-domain-name.
Definition: glocal.cpp:67
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.
void report() const
Generates helpful diagnostics after construction.
virtual std::string received(const std::string &smtp_peer_name) const =0
G::Signal2< std::string, std::string > & eventSignal()
Returns a signal that indicates that something has happened.
void init()
Starts the protocol. Use only once after construction.
A structure containing GSmtp::Server configuration parameters.
Definition: gsmtpserver.h:99
virtual bool onReceive(const std::string &line)
Final override from GNet::BufferedServerPeer.
std::string m_name
Definition: gserver.h:95
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.
A class which allows SMTP messages (envelope+content) to be stored and retrieved. ...
Definition: gmessagestore.h:45
A simple interface to a store of secrets as used in authentication.
Definition: gsecrets.h:44
virtual void onDelete(const std::string &reason)
Final override from GNet::ServerPeer.
virtual void onSecure(const std::string &)
Final override from GNet::SocketProtocolSink.
An SMTP server class.
Definition: gsmtpserver.h:92
A default implementation for the ServerProtocol::Text interface.
A structure containing GSmtp::Client configuration parameters.
Definition: gsmtpclient.h:61
A factory for addresss verifiers.
A structure containing configuration parameters for ServerProtocol.
A general-purpose exception class derived from std::exception and containing a std::string.
Definition: gexception.h:44
virtual void onSendComplete()
Final override from GNet::BufferedServerPeer.
An interface used by the ServerProtocol class to assemble and process an incoming message...
Config(bool, unsigned int, const AddressList &, const std::string &, bool, const std::string &, unsigned int, const std::string &, unsigned int, bool)
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
virtual std::string hello(const std::string &smtp_peer_name) const =0
std::list< Address > AddressList
Definition: gmultiserver.h:105
A structure used in GNet::Server::newPeer().
Definition: gserver.h:91
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.
#define G_WARNING(expr)
Definition: glog.h:107