summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp')
-rw-r--r--Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp194
1 files changed, 194 insertions, 0 deletions
diff --git a/Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp b/Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp
new file mode 100644
index 0000000..7423243
--- /dev/null
+++ b/Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp
@@ -0,0 +1,194 @@
1/*
2 * Copyright (c) 2015 Isode Limited.
3 * All rights reserved.
4 * See the COPYING file for more information.
5 */
6
7#include <Swiften/SASL/WindowsGSSAPIClientAuthenticator.h>
8
9#include <Swiften/Base/Log.h>
10#include <Swiften/SASL/WindowsAuthentication.h>
11#include <Swiften/SASL/WindowsServicePrincipalName.h>
12
13#define SECURITY_LAYER_NONE 1
14
15namespace Swift {
16
17WindowsGSSAPIClientAuthenticator::WindowsGSSAPIClientAuthenticator(const std::string& hostname, const std::string& domainname) : ClientAuthenticator("GSSAPI"), step_(BuildingSecurityContext), error_(false), haveCredentialsHandle_(false), haveContextHandle_(false), haveCompleteContext_(false) {
18 WindowsServicePrincipalName servicePrincipalName(domainname);
19 servicePrincipalName.setInstanceName(hostname);
20 servicePrincipalNameString_ = servicePrincipalName.toString();
21
22 errorCode_ = acquireCredentialsHandle(&credentialsHandle_);
23 if (isError()) {
24 return;
25 }
26 else {
27 haveCredentialsHandle_ = true;
28 }
29
30 buildSecurityContext(NULL);
31}
32
33WindowsGSSAPIClientAuthenticator::~WindowsGSSAPIClientAuthenticator() {
34 if (haveContextHandle_) {
35 deleteSecurityContext(&contextHandle_);
36 }
37
38 if (haveCredentialsHandle_) {
39 freeCredentialsHandle(&credentialsHandle_);
40 }
41}
42
43boost::optional<SafeByteArray> WindowsGSSAPIClientAuthenticator::getResponse() const {
44 SWIFT_LOG(debug) << "response_.size(): " << response_.size() << std::endl;
45 return response_;
46}
47
48bool WindowsGSSAPIClientAuthenticator::setChallenge(const boost::optional<ByteArray>& challengeData) {
49 /* Following http://tools.ietf.org/html/rfc4752, https://msdn.microsoft.com/en-us/library/windows/desktop/aa380496%28v=vs.85%29.aspx */
50
51 if (step_ == BuildingSecurityContext) {
52 buildSecurityContext(challengeData);
53 }
54 else if (step_ == SecurityLayerNegotiation) {
55 if (!challengeData) {
56 SWIFT_LOG(debug) << "Empty message received from the server" << std::endl;
57 error_ = true;
58 return false;
59 }
60
61 SafeByteArray challenge;
62 errorCode_ = decryptMessage(&contextHandle_, challengeData.get(), challenge);
63 if (isError()) {
64 return false;
65 }
66
67 if (challenge.size() != 4) {
68 SWIFT_LOG(debug) << "Token received from the server of incorrect length: " << challenge.size() << std::endl;
69 error_ = true;
70 return false;
71 }
72
73 unsigned char* challengePointer = vecptr(challenge);
74
75 unsigned char serverSecurityLayer = challengePointer[0];
76 if (serverSecurityLayer == 0) {
77 SWIFT_LOG(debug) << "Server supports unknown security layer, assuming no security layer" << std::endl;
78 serverSecurityLayer = SECURITY_LAYER_NONE;
79 }
80 else if (serverSecurityLayer == SECURITY_LAYER_NONE) {
81 SWIFT_LOG(debug) << "Server supports no security layer" << std::endl;
82 }
83 else {
84 SWIFT_LOG(debug) << "Server supports security layer" << std::endl;
85 }
86
87 unsigned int serverMaximumBuffer = (challengePointer[1] << 16) |
88 (challengePointer[2] << 8) |
89 (challengePointer[3] << 0);
90
91 if ((serverSecurityLayer == SECURITY_LAYER_NONE) && (serverMaximumBuffer != 0)) {
92 SWIFT_LOG(debug) << "Server supports no security layer but has maximum buffer size" << serverMaximumBuffer << std::endl;
93 error_ = true;
94 return false;
95 }
96
97 SafeByteArray message(4);
98
99 /* Commenting this out as streamSizes was not obtained before
100 if (message.size() > streamSizes_.cbMaximumMessage) {
101 error_ = true;
102 return false;
103 } */
104
105 unsigned char* messagePointer = vecptr(message);
106 messagePointer[0] = SECURITY_LAYER_NONE;
107
108 /* The next 3 bytes indicate the client's maximum size buffer which is set to 0 as we do not support a security layer */
109 messagePointer[1] = 0;
110 messagePointer[2] = 0;
111 messagePointer[3] = 0;
112
113 /* The authorization identity is omitted as it is the same as the authentication identity */
114
115 errorCode_ = encryptMessage(&contextHandle_, sizes_, message, response_);
116 if (isError()) {
117 return false;
118 }
119
120 step_ = ServerAuthenticated;
121 }
122
123 if (isError()) {
124 return false;
125 }
126
127 return true;
128}
129
130bool WindowsGSSAPIClientAuthenticator::isError() {
131 if (error_) {
132 return true;
133 }
134
135 if (!errorCode_) {
136 return false;
137 }
138
139 return true;
140}
141
142void WindowsGSSAPIClientAuthenticator::buildSecurityContext(const boost::optional<ByteArray>& inputToken) {
143 ULONG contextSupported;
144
145 /* An XMPP server may not support Kerberos encryption or SASL security layer so not requesting integrity or confidentiality */
146 errorCode_ = initializeSecurityContext(inputToken, servicePrincipalNameString_, &credentialsHandle_, haveContextHandle_, &contextHandle_, ISC_REQ_MUTUAL_AUTH, &contextSupported, &haveCompleteContext_, response_);
147 if (isError()) {
148 return;
149 }
150
151 haveContextHandle_ = true;
152
153 if (!haveCompleteContext_) {
154 return;
155 }
156
157 if (contextSupported & ISC_REQ_MUTUAL_AUTH == 0) {
158 SWIFT_LOG(debug) << "Mutual authentication not supported" << std::endl;
159 error_ = true;
160 return;
161 }
162
163 errorCode_ = queryContextAttributes(&contextHandle_, SECPKG_ATTR_SIZES, &sizes_);
164 if (isError()) {
165 return;
166 }
167
168 /* Commenting this out as it gives the error code 0x80090302: The function requested is not supported
169 errorCode_ = queryContextAttributes(&contextHandle_, SECPKG_ATTR_STREAM_SIZES, &streamSizes_);
170 if (isError()) {
171 return;
172 }*/
173
174 SecPkgContext_Names names;
175 errorCode_ = queryContextAttributes(&contextHandle_, SECPKG_ATTR_NAMES, &names);
176 if (isError()) {
177 return;
178 }
179
180 userName_ = names.sUserName;
181 SWIFT_LOG(debug) << "User name: " << userName_ << std::endl;
182
183 std::size_t position = userName_.find("\\");
184 clientName_ = userName_.substr(position + 1);
185 SWIFT_LOG(debug) << "Client name: " << clientName_ << std::endl;
186
187 serverName_ = userName_.substr(0, position);
188 SWIFT_LOG(debug) << "Server name: " << serverName_ << std::endl;
189
190 freeContextBuffer(names.sUserName);
191 step_ = SecurityLayerNegotiation;
192}
193
194}