E-MailRelay
gexecutableverifier.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 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/// \file gexecutableverifier.cpp
19///
20
21#include "gdef.h"
22#include "gexecutableverifier.h"
23#include "gexecutablecommand.h"
24#include "gprocess.h"
25#include "gnewprocess.h"
26#include "gfile.h"
27#include "groot.h"
28#include "gstr.h"
29#include "glocal.h"
30#include "glog.h"
31
33 m_timer(*this,&ExecutableVerifier::onTimeout,es) ,
34 m_config(config) ,
35 m_path(path) ,
36 m_task(*this,es,"<<verifier exec error: __strerror__>>",G::Root::nobody())
37{
38}
39
40void GVerifiers::ExecutableVerifier::verify( const GSmtp::Verifier::Request & request )
41{
42 G_ASSERT( !m_config.domain.empty() ) ;
43 G_ASSERT( !request.address.empty() ) ; // etc
44 G_DEBUG( "GVerifiers::ExecutableVerifier::verify: to=[" << request.address << "]" ) ;
45 m_command = request.command ;
46
47 G::ExecutableCommand commandline( m_path.str() , G::StringArray() ) ;
48 commandline.add( request.address ) ;
49 commandline.add( request.from_address ) ;
50 commandline.add( request.client_ip.displayString() ) ;
51 commandline.add( m_config.domain ) ;
52 commandline.add( G::Str::lower(request.auth_mechanism) ) ;
53 commandline.add( request.auth_extra ) ;
54
55 G_LOG( "GVerifiers::ExecutableVerifier: address verifier: executing " << commandline.displayString() ) ;
56 m_to_address = request.address ;
57 m_task.start( commandline ) ;
58 if( m_config.timeout )
59 m_timer.startTimer( m_config.timeout ) ;
60}
61
62void GVerifiers::ExecutableVerifier::onTimeout()
63{
64 m_task.stop() ;
65
66 auto result = GSmtp::VerifierStatus::invalid( m_to_address , true , "timeout" , "timeout" ) ;
67
68 m_done_signal.emit( m_command , result ) ;
69}
70
71void GVerifiers::ExecutableVerifier::onTaskDone( int exit_code , const std::string & result_in )
72{
73 m_timer.cancelTimer() ;
74 auto status = GSmtp::VerifierStatus::invalid( m_to_address ) ;
75 if( exit_code == 127 && G::Str::headMatch(result_in,"<<verifier exec error") )
76 {
77 G_WARNING( "GVerifiers::ExecutableVerifier: address verifier: exec error" ) ;
78 status = GSmtp::VerifierStatus::invalid( m_to_address , false , "error" , "exec error" ) ;
79 }
80 else
81 {
82 std::string result( result_in ) ;
83 G::Str::trimRight( result , {" \n\t",3U} ) ;
84 G::Str::replaceAll( result , "\r\n" , "\n" ) ;
85 G::Str::replaceAll( result , "\r" , "" ) ;
86
87 G::StringArray result_parts ;
88 result_parts.reserve( 2U ) ;
89 G::Str::splitIntoFields( result , result_parts , '\n' ) ;
90 std::size_t parts = result_parts.size() ;
91 result_parts.resize( 2U ) ;
92
93 G_LOG( "GVerifiers::ExecutableVerifier: address verifier: exit code " << exit_code << ": "
94 << "[" << G::Str::printable(result_parts[0]) << "] [" << G::Str::printable(result_parts[1]) << "]" ) ;
95
96 if( exit_code == 0 && parts >= 2 )
97 {
98 std::string full_name = G::Str::printable( result_parts.at(0U) ) ;
99 std::string mbox = G::Str::printable( result_parts.at(1U) ) ;
100 status = GSmtp::VerifierStatus::local( m_to_address , full_name , mbox ) ;
101 }
102 else if( exit_code == 1 && parts >= 2 )
103 {
104 std::string address = G::Str::printable( result_parts.at(1U) ) ;
105 status = GSmtp::VerifierStatus::remote( m_to_address , address ) ;
106 }
107 else if( exit_code == 100 )
108 {
109 status.abort = true ;
110 }
111 else
112 {
113 bool temporary = exit_code == 3 ;
114
115 std::string response = parts > 0U ?
116 G::Str::printable(result_parts.at(0U)) :
117 std::string("mailbox unavailable") ;
118
119 std::string reason = parts > 1U ?
120 G::Str::printable(result_parts.at(1U)) :
121 ( "exit code " + G::Str::fromInt(exit_code) ) ;
122
123 status = GSmtp::VerifierStatus::invalid( m_to_address ,
124 temporary , response , reason ) ;
125 }
126 }
127 doneSignal().emit( m_command , status ) ;
128}
129
130G::Slot::Signal<GSmtp::Verifier::Command,const GSmtp::VerifierStatus&> & GVerifiers::ExecutableVerifier::doneSignal()
131{
132 return m_done_signal ;
133}
134
135void GVerifiers::ExecutableVerifier::cancel()
136{
137}
138
A lightweight object containing an ExceptionHandler pointer, optional ExceptionSource pointer and opt...
Definition: geventstate.h:131
static VerifierStatus local(const std::string &recipient, const std::string &full_name, const std::string &mbox)
Constructor for a valid local mailbox.
static VerifierStatus invalid(const std::string &recipient, bool temporary=false, const std::string &response={}, const std::string &reason={})
Factory function for an invalid address.
static VerifierStatus remote(const std::string &recipient, const std::string &address={})
Constructor for a valid remote mailbox.
A Verifier that runs an executable.
ExecutableVerifier(GNet::EventState, const GSmtp::Verifier::Config &, const G::Path &)
Constructor.
std::string displayString() const
Returns a printable string that represents the transport address.
Definition: gbasicaddress.h:57
A structure representing an external program, holding a path and a set of arguments.
A Path object represents a file system path.
Definition: gpath.h:82
static std::string & trimRight(std::string &s, std::string_view ws, std::size_t limit=0U)
Trims the rhs of s, taking off up to 'limit' of the 'ws' characters.
Definition: gstr.cpp:313
static std::string lower(std::string_view)
Returns a copy of 's' in which all seven-bit upper-case characters have been replaced by lower-case c...
Definition: gstr.cpp:824
static bool headMatch(std::string_view in, std::string_view head) noexcept
Returns true if the string has the given start (or head is empty).
Definition: gstr.cpp:1359
static void splitIntoFields(std::string_view in, StringArray &out, char sep, char escape='\0', bool remove_escapes=true)
Splits the string into fields.
Definition: gstr.cpp:1191
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 ...
Definition: gstr.cpp:913
static unsigned int replaceAll(std::string &s, std::string_view from, std::string_view to)
Does a global replace on string 's', replacing all occurrences of sub-string 'from' with 'to'.
Definition: gstr.cpp:247
Low-level classes.
Definition: garg.h:36
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstringarray.h:30
STL namespace.
Configuration passed to address verifier constructors.
Definition: gverifier.h:57
Verification request passed to various GSmtp::Verifier::verify() overrides.
Definition: gverifier.h:47