summaryrefslogtreecommitdiffstats
path: root/network/emailrelay/patches/4b0a67b55cec24f99d4842fe8ac980327beed0cb.patch
blob: 08cbd27dbee292fa895ba6d44822f4420fedb85a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
From 4b0a67b55cec24f99d4842fe8ac980327beed0cb Mon Sep 17 00:00:00 2001
From: Andrew Clemons <andrew.clemons@gmail.com>
Date: Wed, 2 Aug 2017 21:22:53 +1200
Subject: [PATCH] Add support for XOAUTH2 auth

I have thus far only tested this with gmail and using node-xoauth2 for
generating the tokens.

Emailrelay still requires a client auth configuration file with four
values. The id value here can be anything since it is ignored.

I am using:

client XOAUTH2 ignored <generated token>
---
 src/gauth/gsaslclient.h          |  5 +++++
 src/gauth/gsaslclient_native.cpp | 32 +++++++++++++++++++++++++++++++-
 src/gsmtp/gclientprotocol.cpp    | 18 ++++++++++++++++--
 3 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/src/gauth/gsaslclient.h b/src/gauth/gsaslclient.h
index ea12e05..d74b56d 100644
--- a/src/gauth/gsaslclient.h
+++ b/src/gauth/gsaslclient.h
@@ -67,6 +67,11 @@ class GAuth::SaslClient
 		///< Returns true if the constructor's secrets object
 		///< is valid.
 
+	std::string initial_response( const std::string & mechanism ,
+		bool & done , bool & error , bool & sensitive ) const ;
+			///< Returns an initial_response for authentication.
+			///< Returns various boolean flags by reference.
+
 	std::string response( const std::string & mechanism , const std::string & challenge , 
 		bool & done , bool & error , bool & sensitive ) const ;
 			///< Returns a response to the given challenge.
diff --git a/src/gauth/gsaslclient_native.cpp b/src/gauth/gsaslclient_native.cpp
index d0bded2..924772a 100644
--- a/src/gauth/gsaslclient_native.cpp
+++ b/src/gauth/gsaslclient_native.cpp
@@ -101,6 +101,33 @@ bool GAuth::SaslClient::active() const
 	return m_imp->m_secrets.valid() ;
 }
 
+std::string GAuth::SaslClient::initial_response( const std::string & mechanism , bool & done ,
+	bool & error , bool & sensitive ) const
+{
+	done = false ;
+	error = false ;
+	sensitive = false ;
+
+	std::string auth("AUTH") ;
+	std::string sep(" ") ;
+
+	std::string rsp ;
+	if( mechanism == "XOAUTH2" )
+	{
+		std::string secret = m_imp->m_secrets.secret(mechanism) ;
+		rsp = auth + sep + mechanism + sep + secret ;
+		error = secret.empty() ;
+		done = true ;
+		sensitive = true ;
+	}
+	else
+	{
+		rsp = auth + sep + mechanism ;
+	}
+
+	return rsp ;
+}
+
 std::string GAuth::SaslClient::response( const std::string & mechanism , const std::string & challenge , 
 	bool & done , bool & error , bool & sensitive ) const
 {
@@ -175,6 +202,7 @@ std::string GAuth::SaslClient::preferred( const G::Strings & mechanism_list ) co
 
 	const std::string login( "LOGIN" ) ;
 	const std::string plain( "PLAIN" ) ;
+	const std::string xoauth2( "XOAUTH2" ) ;
 	const std::string cram( "CRAM-MD5" ) ;
 
 	// create a them set
@@ -186,15 +214,17 @@ std::string GAuth::SaslClient::preferred( const G::Strings & mechanism_list ) co
 	std::set<std::string> us ;
 	if( !m_imp->m_secrets.id(login).empty() ) us.insert(login) ;
 	if( !m_imp->m_secrets.id(plain).empty() ) us.insert(plain) ;
+	if( !m_imp->m_secrets.id(xoauth2).empty() ) us.insert(xoauth2) ;
 	if( !m_imp->m_secrets.id(cram).empty() ) us.insert(cram) ;
 
 	// get the intersection
 	std::set<std::string> both ;
 	std::set_intersection( them.begin() , them.end() , us.begin() , us.end() , std::inserter(both,both.end()) ) ;
 
-	// preferred order: cram, plain, login
+	// preferred order: cram, xoauth2, plain, login
 	std::string m ;
 	if( m.empty() && both.find(cram) != both.end() ) m = cram ;
+	if( m.empty() && both.find(xoauth2) != both.end() ) m = xoauth2 ;
 	if( m.empty() && both.find(plain) != both.end() ) m = plain ;
 	if( m.empty() && both.find(login) != both.end() ) m = login ;
 	G_DEBUG( "GAuth::SaslClient::preferred: we prefer \"" << m << "\"" ) ;
diff --git a/src/gsmtp/gclientprotocol.cpp b/src/gsmtp/gclientprotocol.cpp
index 3ebc0c7..bbd8aca 100644
--- a/src/gsmtp/gclientprotocol.cpp
+++ b/src/gsmtp/gclientprotocol.cpp
@@ -303,8 +303,22 @@ bool GSmtp::ClientProtocol::applyEvent( const Reply & reply , bool is_start_even
 		}
 		else if( m_server_has_auth && m_sasl->active() )
 		{
-			m_state = sAuth1 ;
-			send( "AUTH " , m_auth_mechanism ) ;
+			bool done = true ;
+			bool error = false ;
+			bool sensitive = false ;
+			std::string rsp = m_sasl->initial_response( m_auth_mechanism ,
+				done , error , sensitive ) ;
+
+			if( error )
+			{
+				m_state = sAuth2 ;
+				send( "*" ) ; // ie. cancel authentication
+			}
+			else
+			{
+				m_state = done ? sAuth2 : sAuth1 ;
+				send( rsp , false , sensitive ) ;
+			}
 		}
 		else if( !m_server_has_auth && m_sasl->active() && m_must_authenticate )
 		{