E-MailRelay
gsecrets.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 gsecrets.cpp
19///
20
21#include "gdef.h"
22#include "gsecrets.h"
23#include "gsecretsfile.h"
24#include "gbase64.h"
25#include "gassert.h"
26#include "glog.h"
27
28namespace GAuth
29{
30 namespace SecretsImp
31 {
32 bool pam( const std::string & s )
33 {
34 return !G::is_windows() && ( s == "pam:" || s == "/pam" ) ;
35 }
36 bool plain( const std::string & s )
37 {
38 return G::Str::headMatch( s , "plain:" ) ;
39 }
40 bool parse( const std::string & s , std::string & id , std::string & pwd )
41 {
42 std::string spec = G::Str::tail( s , ":" ) ;
43 id = G::Str::head( spec , ":" , false ) ;
44 pwd = G::Str::tail( spec , ":" , true ) ;
45 return G::Base64::valid(id) && G::Base64::valid(pwd) ;
46 }
47 void check( const std::string & s )
48 {
49 if( plain(s) ) // account on the command-line, no secrets file
50 {
51 std::string id ;
52 std::string pwd ;
53 if( !parse( s , id , pwd ) )
54 throw Secrets::ClientAccountError() ;
55 }
56 else
57 {
58 SecretsFile::check( s , true ) ;
59 }
60 }
61 }
62}
63
64void GAuth::Secrets::check( const std::string & c , const std::string & s , const std::string & p )
65{
66 namespace imp = SecretsImp ;
67 if( !c.empty() ) imp::check( c ) ;
68 if( !s.empty() && !imp::pam(s) && s != c ) SecretsFile::check( s , true ) ;
69 if( !p.empty() && !imp::pam(p) && p != s && p != c ) SecretsFile::check( p , true ) ;
70}
71
72std::unique_ptr<GAuth::SaslServerSecrets> GAuth::Secrets::newServerSecrets( const std::string & path ,
73 const std::string & log_name )
74{
75 return std::make_unique<SecretsFileServer>( path , log_name ) ;
76}
77
78std::unique_ptr<GAuth::SaslClientSecrets> GAuth::Secrets::newClientSecrets( const std::string & path ,
79 const std::string & log_name )
80{
81 return std::make_unique<SecretsFileClient>( path , log_name ) ;
82}
83
84// ==
85
86GAuth::SecretsFileClient::SecretsFileClient( const std::string & path , const std::string & log_name ) :
87 m_id_pwd(SecretsImp::plain(path)) ,
88 m_file(m_id_pwd?std::string():path,true,log_name)
89{
90 if( m_id_pwd )
91 SecretsImp::parse( path , m_id , m_pwd ) ;
92}
93
95= default ;
96
97bool GAuth::SecretsFileClient::validSelector( std::string_view selector ) const
98{
99 if( m_id_pwd )
100 return selector.empty() ;
101 else if( !m_file.valid() )
102 return selector.empty() ;
103 else
104 return m_file.containsClientSelector( selector ) ;
105}
106
107bool GAuth::SecretsFileClient::mustAuthenticate( std::string_view selector ) const
108{
109 if( m_id_pwd )
110 return true ;
111 else if( !m_file.valid() )
112 return false ;
113 else
114 return m_file.containsClientSecret( selector ) ;
115}
116
117GAuth::Secret GAuth::SecretsFileClient::clientSecret( std::string_view type , std::string_view selector ) const
118{
119 if( m_id_pwd && type == "plain"_sv )
120 {
121 return { {m_id,"base64"} , {m_pwd,"base64"} } ;
122 }
123 else if( m_id_pwd )
124 {
125 return GAuth::Secret::none() ;
126 }
127 else
128 {
129 return m_file.clientSecret( type , selector ) ;
130 }
131}
132
133// ==
134
135GAuth::SecretsFileServer::SecretsFileServer( const std::string & spec , const std::string & log_name ) :
136 m_pam(SecretsImp::pam(spec)) ,
137 m_file(m_pam?std::string():spec,true,log_name)
138{
139}
140
142= default ;
143
144std::string GAuth::SecretsFileServer::source() const
145{
146 return m_pam ? std::string("pam:") : m_file.path() ;
147}
148
149bool GAuth::SecretsFileServer::valid() const
150{
151 return m_pam || m_file.valid() ;
152}
153
154GAuth::Secret GAuth::SecretsFileServer::serverSecret( std::string_view type , std::string_view id ) const
155{
156 G_ASSERT( !m_pam ) ;
157 return m_file.serverSecret( type , id ) ;
158}
159
160std::pair<std::string,std::string> GAuth::SecretsFileServer::serverTrust( const std::string & address_range ) const
161{
162 G_ASSERT( !m_pam ) ;
163 return m_file.serverTrust( address_range ) ;
164}
165
166bool GAuth::SecretsFileServer::contains( std::string_view type , std::string_view id ) const
167{
168 G_ASSERT( !m_pam ) ;
169 return m_file.containsServerSecret( type , id ) ;
170}
171
Encapsulates a userid/shared-secret/hash-function tuple from the secrets file.
Definition: gsecret.h:44
static Secret none()
Factory function that returns a secret that is not valid().
Definition: gsecret.cpp:75
~SecretsFileClient() override
Destructor.
SecretsFileClient(const std::string &path_spec, const std::string &log_name)
Constructor. See GAuth::Secrets::newClientSecrets().
Definition: gsecrets.cpp:86
~SecretsFileServer() override
Destructor.
SecretsFileServer(const std::string &path, const std::string &log_name)
Constructor. See GAuth::Secrets::newServerSecrets().
Definition: gsecrets.cpp:135
static void check(const std::string &path, bool with_warnings)
Checks the given file.
static std::unique_ptr< SaslServerSecrets > newServerSecrets(const std::string &spec, const std::string &log_name)
Factory function for server secrets.
Definition: gsecrets.cpp:72
static void check(const std::string &client, const std::string &server, const std::string &pop)
Checks the given secret sources.
Definition: gsecrets.cpp:64
static std::unique_ptr< SaslClientSecrets > newClientSecrets(const std::string &spec, const std::string &log_name)
Factory function for client secrets.
Definition: gsecrets.cpp:78
static bool valid(std::string_view, bool strict=true)
Returns true if the string is a valid base64 encoding, possibly allowing for embedded newlines,...
Definition: gbase64.cpp:89
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 std::string tail(std::string_view in, std::size_t pos, std::string_view default_={})
Returns the last part of the string after the given position.
Definition: gstr.cpp:1322
static std::string head(std::string_view in, std::size_t pos, std::string_view default_={})
Returns the first part of the string up to just before the given position.
Definition: gstr.cpp:1294
SASL authentication classes.
Definition: gcram.cpp:38
STL namespace.