E-MailRelay
guserverifier.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2023 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 guserverifier.cpp
19///
20
21#include "gdef.h"
22#include "guserverifier.h"
23#include "gidentity.h"
24#include "grange.h"
25#include "gstr.h"
26#include "gstringtoken.h"
27#include "glog.h"
28#include <sstream>
29
31 const GSmtp::Verifier::Config & config , const std::string & spec ) :
32 m_command(Command::RCPT) ,
33 m_config(config) ,
34 m_timer(*this,&UserVerifier::onTimeout,es) ,
35 m_result(GSmtp::VerifierStatus::invalid({})) ,
36 m_range(G::Range::range(1000,32767))
37{
38 G::string_view spec_view( spec ) ;
39 for( G::StringTokenView t( spec_view , ";" , 1U ) ; t ; ++t )
40 {
41 if( !t().empty() && G::Str::isNumeric(t().substr(0U,1U)) )
42 m_range = G::Range::range( t() ) ;
43 else if( ( t().size() <= 3U && t().find('l') != std::string::npos ) || t() == "lowercase"_sv )
44 m_config_lc = true ;
45 else if( ( t().size() <= 3U && t().find('r') != std::string::npos ) || t() == "remote"_sv )
46 m_config_remote = true ;
47 else if( ( t().size() <= 3U && t().find('c') != std::string::npos ) || t() == "check"_sv )
48 m_config_check = true ;
49 }
50 G_DEBUG( "GVerifiers::UserVerifier: uid range " << G::Range::str(m_range) ) ;
51}
52
53void GVerifiers::UserVerifier::verify( Command command , const std::string & rcpt_to_parameter ,
54 const GSmtp::Verifier::Info & )
55{
56 using namespace G::Range ; // within()
57 m_command = command ;
58
59 std::string user = dequote( G::Str::head( dequote(rcpt_to_parameter) , "@" , false ) ) ;
60 std::string domain = G::Str::tail( dequote(rcpt_to_parameter) , "@" ) ;
61 std::string reason ;
62 std::string mailbox ;
63
64 if( user == "postmaster" && domain.empty() )
65 m_result = GSmtp::VerifierStatus::local( rcpt_to_parameter , {} , "postmaster" ) ;
66 else if( lookup(user,domain,&reason,&mailbox) )
67 m_result =
68 m_config_remote ?
69 GSmtp::VerifierStatus::remote( rcpt_to_parameter ) :
70 GSmtp::VerifierStatus::local( rcpt_to_parameter , {} , m_config_lc?G::Str::lower(mailbox):mailbox ) ;
71 else if( m_config_check )
72 m_result = GSmtp::VerifierStatus::remote( rcpt_to_parameter ) ;
73 else
74 m_result = GSmtp::VerifierStatus::invalid( rcpt_to_parameter , false , "rejected" , reason ) ;
75
76 m_timer.startTimer( 0U ) ;
77}
78
79bool GVerifiers::UserVerifier::lookup( const std::string & user , const std::string & domain ,
80 std::string * reason_p , std::string * mailbox_p ) const
81{
82 bool result = false ;
83 std::ostringstream ss ;
84 if( !G::Str::imatch( domain , m_config.domain ) )
85 {
86 ss << "[" << domain << "] does not match [" << m_config.domain << "]" ;
87 }
88 else
89 {
90 auto pair = G::Identity::lookup( user , std::nothrow ) ;
91
92 if( pair.first == G::Identity::invalid() && G::Str::isPrintableAscii(user) && !G::is_windows() )
93 pair = G::Identity::lookup( G::Str::lower(user) , std::nothrow ) ;
94
95 if( pair.first == G::Identity::invalid() || pair.second.empty() )
96 {
97 ss << "[" << user << "] is not a valid account name" ;
98 }
99 else if( !pair.first.match( m_range ) )
100 {
101 ss << "uid " << pair.first.userid() << " is not in the range " << G::Range::str(m_range) ;
102 }
103 else
104 {
105 if( mailbox_p )
106 *mailbox_p = pair.second ;
107 result = true ;
108 }
109 }
110 if( !result && reason_p ) *reason_p = ss.str() ;
111 return result ;
112}
113
114GVerifiers::UserVerifier::Signal & GVerifiers::UserVerifier::doneSignal()
115{
116 return m_done_signal ;
117}
118
119void GVerifiers::UserVerifier::cancel()
120{
121 m_timer.cancelTimer() ;
122}
123
124void GVerifiers::UserVerifier::onTimeout()
125{
126 m_done_signal.emit( m_command , m_result ) ;
127}
128
129std::string GVerifiers::UserVerifier::dequote( const std::string & s )
130{
131 if( s.size() >= 2U && s.at(0) == '"' && s.at(s.size()-1U) == '"' )
132 return s.substr( 1U , s.size()-2U ) ;
133 else
134 return s ;
135}
136
A tuple containing an ExceptionHandler interface pointer and a bound 'exception source' pointer.
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 concrete Verifier class that verifies against the password database (ie.
Definition: guserverifier.h:56
UserVerifier(GNet::ExceptionSink es, const GSmtp::Verifier::Config &config, const std::string &spec)
Constructor.
static Identity invalid() noexcept
Returns an invalid identity.
static std::pair< Identity, std::string > lookup(const std::string &user)
Does a username lookup returning the identity and the canonical name.
static bool isPrintableAscii(string_view s) noexcept
Returns true if every character is a 7-bit, non-control character (ie.
Definition: gstr.cpp:416
static bool isNumeric(string_view s, bool allow_minus_sign=false) noexcept
Returns true if every character is a decimal digit.
Definition: gstr.cpp:403
static bool imatch(char, char) noexcept
Returns true if the two characters are the same, ignoring seven-bit case.
Definition: gstr.cpp:1418
static std::string lower(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:827
static std::string tail(string_view in, std::size_t pos, string_view default_={})
Returns the last part of the string after the given position.
Definition: gstr.cpp:1325
static std::string head(string_view in, std::size_t pos, string_view default_={})
Returns the first part of the string up to just before the given position.
Definition: gstr.cpp:1297
A zero-copy string token iterator where the token separators are runs of whitespace characters,...
Definition: gstringtoken.h:54
A class like c++17's std::string_view.
Definition: gstringview.h:51
SMTP classes.
Definition: gadminserver.h:42
Utility functions for pair-of-integer ranges.
Definition: grange.h:32
Configuration passed to address verifier constructors.
Definition: gverifier.h:55
Extra information passed to GSmtp::Verifier::verify().
Definition: gverifier.h:47