blob: 0456eeaa1c370c0062c4250addd7f3f14363f0e2 [file] [log] [blame]
deadbeeff137e972017-03-23 15:45:49 -07001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include <time.h>
12
13#if defined(WEBRTC_WIN)
deadbeeff137e972017-03-23 15:45:49 -070014#include <windows.h>
15#include <winsock2.h>
16#include <ws2tcpip.h>
Yves Gerey3e707812018-11-28 16:47:49 +010017
deadbeeff137e972017-03-23 15:45:49 -070018#define SECURITY_WIN32
19#include <security.h>
20#endif
21
Yves Gerey2e00abc2018-10-05 15:39:24 +020022#include <ctype.h> // for isspace
23#include <stdio.h> // for sprintf
Yves Gerey2e00abc2018-10-05 15:39:24 +020024#include <utility> // for pair
25#include <vector>
deadbeeff137e972017-03-23 15:45:49 -070026
Niels Möller3c7d5992018-10-19 15:29:54 +020027#include "absl/strings/match.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "rtc_base/crypt_string.h" // for CryptString
29#include "rtc_base/http_common.h"
Yves Gerey2e00abc2018-10-05 15:39:24 +020030#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "rtc_base/message_digest.h"
32#include "rtc_base/socket_address.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020033#include "rtc_base/strings/string_builder.h"
Yves Gerey2e00abc2018-10-05 15:39:24 +020034#include "rtc_base/third_party/base64/base64.h" // for Base64
35#include "rtc_base/zero_memory.h" // for ExplicitZeroMemory
deadbeeff137e972017-03-23 15:45:49 -070036
37namespace rtc {
Tommie51a0a82018-02-27 15:30:29 +010038namespace {
Robin Raymondce1b1402018-11-22 20:10:11 -050039#if defined(WEBRTC_WIN) && !defined(WINUWP)
Tommie51a0a82018-02-27 15:30:29 +010040///////////////////////////////////////////////////////////////////////////////
41// ConstantToLabel can be used to easily generate string names from constant
42// values. This can be useful for logging descriptive names of error messages.
43// Usage:
44// const ConstantToLabel LIBRARY_ERRORS[] = {
45// KLABEL(SOME_ERROR),
46// KLABEL(SOME_OTHER_ERROR),
47// ...
48// LASTLABEL
49// }
50//
51// int err = LibraryFunc();
52// LOG(LS_ERROR) << "LibraryFunc returned: "
53// << GetErrorName(err, LIBRARY_ERRORS);
Yves Gerey665174f2018-06-19 15:03:05 +020054struct ConstantToLabel {
55 int value;
56 const char* label;
57};
Tommie51a0a82018-02-27 15:30:29 +010058
59const char* LookupLabel(int value, const ConstantToLabel entries[]) {
60 for (int i = 0; entries[i].label; ++i) {
61 if (value == entries[i].value) {
62 return entries[i].label;
63 }
64 }
65 return 0;
66}
67
68std::string GetErrorName(int err, const ConstantToLabel* err_table) {
69 if (err == 0)
70 return "No error";
71
72 if (err_table != 0) {
73 if (const char* value = LookupLabel(err, err_table))
74 return value;
75 }
76
77 char buffer[16];
78 snprintf(buffer, sizeof(buffer), "0x%08x", err);
79 return buffer;
80}
81
Yves Gerey665174f2018-06-19 15:03:05 +020082#define KLABEL(x) \
83 { x, #x }
84#define LASTLABEL \
85 { 0, 0 }
Tommie51a0a82018-02-27 15:30:29 +010086
87const ConstantToLabel SECURITY_ERRORS[] = {
Yves Gerey665174f2018-06-19 15:03:05 +020088 KLABEL(SEC_I_COMPLETE_AND_CONTINUE),
89 KLABEL(SEC_I_COMPLETE_NEEDED),
90 KLABEL(SEC_I_CONTEXT_EXPIRED),
91 KLABEL(SEC_I_CONTINUE_NEEDED),
92 KLABEL(SEC_I_INCOMPLETE_CREDENTIALS),
93 KLABEL(SEC_I_RENEGOTIATE),
94 KLABEL(SEC_E_CERT_EXPIRED),
95 KLABEL(SEC_E_INCOMPLETE_MESSAGE),
96 KLABEL(SEC_E_INSUFFICIENT_MEMORY),
97 KLABEL(SEC_E_INTERNAL_ERROR),
98 KLABEL(SEC_E_INVALID_HANDLE),
99 KLABEL(SEC_E_INVALID_TOKEN),
100 KLABEL(SEC_E_LOGON_DENIED),
101 KLABEL(SEC_E_NO_AUTHENTICATING_AUTHORITY),
102 KLABEL(SEC_E_NO_CREDENTIALS),
103 KLABEL(SEC_E_NOT_OWNER),
104 KLABEL(SEC_E_OK),
105 KLABEL(SEC_E_SECPKG_NOT_FOUND),
106 KLABEL(SEC_E_TARGET_UNKNOWN),
107 KLABEL(SEC_E_UNKNOWN_CREDENTIALS),
108 KLABEL(SEC_E_UNSUPPORTED_FUNCTION),
109 KLABEL(SEC_E_UNTRUSTED_ROOT),
110 KLABEL(SEC_E_WRONG_PRINCIPAL),
111 LASTLABEL};
Tommie51a0a82018-02-27 15:30:29 +0100112#undef KLABEL
113#undef LASTLABEL
Robin Raymondce1b1402018-11-22 20:10:11 -0500114#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
deadbeeff137e972017-03-23 15:45:49 -0700115
Niels Möller83da5522018-09-26 16:18:38 +0200116typedef std::pair<std::string, std::string> HttpAttribute;
117typedef std::vector<HttpAttribute> HttpAttributeList;
deadbeeff137e972017-03-23 15:45:49 -0700118
Yves Gerey665174f2018-06-19 15:03:05 +0200119inline bool IsEndOfAttributeName(size_t pos, size_t len, const char* data) {
deadbeeff137e972017-03-23 15:45:49 -0700120 if (pos >= len)
121 return true;
122 if (isspace(static_cast<unsigned char>(data[pos])))
123 return true;
124 // The reason for this complexity is that some attributes may contain trailing
125 // equal signs (like base64 tokens in Negotiate auth headers)
Yves Gerey665174f2018-06-19 15:03:05 +0200126 if ((pos + 1 < len) && (data[pos] == '=') &&
127 !isspace(static_cast<unsigned char>(data[pos + 1])) &&
128 (data[pos + 1] != '=')) {
deadbeeff137e972017-03-23 15:45:49 -0700129 return true;
130 }
131 return false;
132}
133
Yves Gerey665174f2018-06-19 15:03:05 +0200134void HttpParseAttributes(const char* data,
135 size_t len,
deadbeeff137e972017-03-23 15:45:49 -0700136 HttpAttributeList& attributes) {
137 size_t pos = 0;
138 while (true) {
139 // Skip leading whitespace
140 while ((pos < len) && isspace(static_cast<unsigned char>(data[pos]))) {
141 ++pos;
142 }
143
144 // End of attributes?
145 if (pos >= len)
146 return;
147
148 // Find end of attribute name
149 size_t start = pos;
150 while (!IsEndOfAttributeName(pos, len, data)) {
151 ++pos;
152 }
153
154 HttpAttribute attribute;
155 attribute.first.assign(data + start, data + pos);
156
157 // Attribute has value?
158 if ((pos < len) && (data[pos] == '=')) {
Yves Gerey665174f2018-06-19 15:03:05 +0200159 ++pos; // Skip '='
deadbeeff137e972017-03-23 15:45:49 -0700160 // Check if quoted value
161 if ((pos < len) && (data[pos] == '"')) {
162 while (++pos < len) {
163 if (data[pos] == '"') {
164 ++pos;
165 break;
166 }
167 if ((data[pos] == '\\') && (pos + 1 < len))
168 ++pos;
169 attribute.second.append(1, data[pos]);
170 }
171 } else {
Yves Gerey665174f2018-06-19 15:03:05 +0200172 while ((pos < len) && !isspace(static_cast<unsigned char>(data[pos])) &&
173 (data[pos] != ',')) {
deadbeeff137e972017-03-23 15:45:49 -0700174 attribute.second.append(1, data[pos++]);
175 }
176 }
177 }
178
179 attributes.push_back(attribute);
Yves Gerey665174f2018-06-19 15:03:05 +0200180 if ((pos < len) && (data[pos] == ','))
181 ++pos; // Skip ','
deadbeeff137e972017-03-23 15:45:49 -0700182 }
183}
184
185bool HttpHasAttribute(const HttpAttributeList& attributes,
186 const std::string& name,
187 std::string* value) {
188 for (HttpAttributeList::const_iterator it = attributes.begin();
189 it != attributes.end(); ++it) {
190 if (it->first == name) {
191 if (value) {
192 *value = it->second;
193 }
194 return true;
195 }
196 }
197 return false;
198}
199
200bool HttpHasNthAttribute(HttpAttributeList& attributes,
201 size_t index,
202 std::string* name,
203 std::string* value) {
204 if (index >= attributes.size())
205 return false;
206
207 if (name)
208 *name = attributes[index].first;
209 if (value)
210 *value = attributes[index].second;
211 return true;
212}
213
deadbeeff137e972017-03-23 15:45:49 -0700214std::string quote(const std::string& str) {
215 std::string result;
216 result.push_back('"');
Yves Gerey665174f2018-06-19 15:03:05 +0200217 for (size_t i = 0; i < str.size(); ++i) {
deadbeeff137e972017-03-23 15:45:49 -0700218 if ((str[i] == '"') || (str[i] == '\\'))
219 result.push_back('\\');
220 result.push_back(str[i]);
221 }
222 result.push_back('"');
223 return result;
224}
225
Robin Raymondce1b1402018-11-22 20:10:11 -0500226#if defined(WEBRTC_WIN) && !defined(WINUWP)
deadbeeff137e972017-03-23 15:45:49 -0700227struct NegotiateAuthContext : public HttpAuthContext {
228 CredHandle cred;
229 CtxtHandle ctx;
230 size_t steps;
231 bool specified_credentials;
232
233 NegotiateAuthContext(const std::string& auth, CredHandle c1, CtxtHandle c2)
Yves Gerey665174f2018-06-19 15:03:05 +0200234 : HttpAuthContext(auth),
235 cred(c1),
236 ctx(c2),
237 steps(0),
238 specified_credentials(false) {}
deadbeeff137e972017-03-23 15:45:49 -0700239
Steve Anton9de3aac2017-10-24 10:08:26 -0700240 ~NegotiateAuthContext() override {
deadbeeff137e972017-03-23 15:45:49 -0700241 DeleteSecurityContext(&ctx);
242 FreeCredentialsHandle(&cred);
243 }
244};
Robin Raymondce1b1402018-11-22 20:10:11 -0500245#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
deadbeeff137e972017-03-23 15:45:49 -0700246
Niels Möller83da5522018-09-26 16:18:38 +0200247} // anonymous namespace
248
Yves Gerey665174f2018-06-19 15:03:05 +0200249HttpAuthResult HttpAuthenticate(const char* challenge,
250 size_t len,
251 const SocketAddress& server,
252 const std::string& method,
253 const std::string& uri,
254 const std::string& username,
255 const CryptString& password,
256 HttpAuthContext*& context,
257 std::string& response,
258 std::string& auth_method) {
deadbeeff137e972017-03-23 15:45:49 -0700259 HttpAttributeList args;
260 HttpParseAttributes(challenge, len, args);
261 HttpHasNthAttribute(args, 0, &auth_method, nullptr);
262
263 if (context && (context->auth_method != auth_method))
264 return HAR_IGNORE;
265
266 // BASIC
Niels Möller3c7d5992018-10-19 15:29:54 +0200267 if (absl::EqualsIgnoreCase(auth_method, "basic")) {
deadbeeff137e972017-03-23 15:45:49 -0700268 if (context)
Yves Gerey665174f2018-06-19 15:03:05 +0200269 return HAR_CREDENTIALS; // Bad credentials
deadbeeff137e972017-03-23 15:45:49 -0700270 if (username.empty())
Yves Gerey665174f2018-06-19 15:03:05 +0200271 return HAR_CREDENTIALS; // Missing credentials
deadbeeff137e972017-03-23 15:45:49 -0700272
273 context = new HttpAuthContext(auth_method);
274
Joachim Bauch5b32f232018-03-07 20:02:26 +0100275 // TODO(bugs.webrtc.org/8905): Convert sensitive to a CryptString and also
276 // return response as CryptString so contents get securely deleted
277 // automatically.
278 // std::string decoded = username + ":" + password;
deadbeeff137e972017-03-23 15:45:49 -0700279 size_t len = username.size() + password.GetLength() + 2;
Yves Gerey665174f2018-06-19 15:03:05 +0200280 char* sensitive = new char[len];
deadbeeff137e972017-03-23 15:45:49 -0700281 size_t pos = strcpyn(sensitive, len, username.data(), username.size());
282 pos += strcpyn(sensitive + pos, len - pos, ":");
283 password.CopyTo(sensitive + pos, true);
284
285 response = auth_method;
286 response.append(" ");
287 // TODO: create a sensitive-source version of Base64::encode
288 response.append(Base64::Encode(sensitive));
Joachim Bauch5b32f232018-03-07 20:02:26 +0100289 ExplicitZeroMemory(sensitive, len);
Yves Gerey665174f2018-06-19 15:03:05 +0200290 delete[] sensitive;
deadbeeff137e972017-03-23 15:45:49 -0700291 return HAR_RESPONSE;
292 }
293
294 // DIGEST
Niels Möller3c7d5992018-10-19 15:29:54 +0200295 if (absl::EqualsIgnoreCase(auth_method, "digest")) {
deadbeeff137e972017-03-23 15:45:49 -0700296 if (context)
Yves Gerey665174f2018-06-19 15:03:05 +0200297 return HAR_CREDENTIALS; // Bad credentials
deadbeeff137e972017-03-23 15:45:49 -0700298 if (username.empty())
Yves Gerey665174f2018-06-19 15:03:05 +0200299 return HAR_CREDENTIALS; // Missing credentials
deadbeeff137e972017-03-23 15:45:49 -0700300
301 context = new HttpAuthContext(auth_method);
302
303 std::string cnonce, ncount;
304 char buffer[256];
305 sprintf(buffer, "%d", static_cast<int>(time(0)));
306 cnonce = MD5(buffer);
307 ncount = "00000001";
308
309 std::string realm, nonce, qop, opaque;
310 HttpHasAttribute(args, "realm", &realm);
311 HttpHasAttribute(args, "nonce", &nonce);
312 bool has_qop = HttpHasAttribute(args, "qop", &qop);
313 bool has_opaque = HttpHasAttribute(args, "opaque", &opaque);
314
Joachim Bauch5b32f232018-03-07 20:02:26 +0100315 // TODO(bugs.webrtc.org/8905): Convert sensitive to a CryptString and also
316 // return response as CryptString so contents get securely deleted
317 // automatically.
318 // std::string A1 = username + ":" + realm + ":" + password;
deadbeeff137e972017-03-23 15:45:49 -0700319 size_t len = username.size() + realm.size() + password.GetLength() + 3;
Yves Gerey665174f2018-06-19 15:03:05 +0200320 char* sensitive = new char[len]; // A1
deadbeeff137e972017-03-23 15:45:49 -0700321 size_t pos = strcpyn(sensitive, len, username.data(), username.size());
322 pos += strcpyn(sensitive + pos, len - pos, ":");
323 pos += strcpyn(sensitive + pos, len - pos, realm.c_str());
324 pos += strcpyn(sensitive + pos, len - pos, ":");
325 password.CopyTo(sensitive + pos, true);
326
327 std::string A2 = method + ":" + uri;
328 std::string middle;
329 if (has_qop) {
330 qop = "auth";
331 middle = nonce + ":" + ncount + ":" + cnonce + ":" + qop;
332 } else {
333 middle = nonce;
334 }
335 std::string HA1 = MD5(sensitive);
Joachim Bauch5b32f232018-03-07 20:02:26 +0100336 ExplicitZeroMemory(sensitive, len);
Yves Gerey665174f2018-06-19 15:03:05 +0200337 delete[] sensitive;
deadbeeff137e972017-03-23 15:45:49 -0700338 std::string HA2 = MD5(A2);
339 std::string dig_response = MD5(HA1 + ":" + middle + ":" + HA2);
340
Jonas Olsson366a50c2018-09-06 13:41:30 +0200341 rtc::StringBuilder ss;
deadbeeff137e972017-03-23 15:45:49 -0700342 ss << auth_method;
343 ss << " username=" << quote(username);
344 ss << ", realm=" << quote(realm);
345 ss << ", nonce=" << quote(nonce);
346 ss << ", uri=" << quote(uri);
347 if (has_qop) {
348 ss << ", qop=" << qop;
Yves Gerey665174f2018-06-19 15:03:05 +0200349 ss << ", nc=" << ncount;
deadbeeff137e972017-03-23 15:45:49 -0700350 ss << ", cnonce=" << quote(cnonce);
351 }
352 ss << ", response=\"" << dig_response << "\"";
353 if (has_opaque) {
354 ss << ", opaque=" << quote(opaque);
355 }
356 response = ss.str();
357 return HAR_RESPONSE;
358 }
359
Robin Raymondce1b1402018-11-22 20:10:11 -0500360#if defined(WEBRTC_WIN) && !defined(WINUWP)
deadbeeff137e972017-03-23 15:45:49 -0700361#if 1
Niels Möller3c7d5992018-10-19 15:29:54 +0200362 bool want_negotiate = absl::EqualsIgnoreCase(auth_method, "negotiate");
363 bool want_ntlm = absl::EqualsIgnoreCase(auth_method, "ntlm");
deadbeeff137e972017-03-23 15:45:49 -0700364 // SPNEGO & NTLM
365 if (want_negotiate || want_ntlm) {
366 const size_t MAX_MESSAGE = 12000, MAX_SPN = 256;
367 char out_buf[MAX_MESSAGE], spn[MAX_SPN];
368
Yves Gerey665174f2018-06-19 15:03:05 +0200369#if 0 // Requires funky windows versions
deadbeeff137e972017-03-23 15:45:49 -0700370 DWORD len = MAX_SPN;
371 if (DsMakeSpn("HTTP", server.HostAsURIString().c_str(), nullptr,
372 server.port(),
373 0, &len, spn) != ERROR_SUCCESS) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100374 RTC_LOG_F(WARNING) << "(Negotiate) - DsMakeSpn failed";
deadbeeff137e972017-03-23 15:45:49 -0700375 return HAR_IGNORE;
376 }
377#else
Niels Mölleraba06332018-10-16 15:14:15 +0200378 snprintf(spn, MAX_SPN, "HTTP/%s", server.ToString().c_str());
deadbeeff137e972017-03-23 15:45:49 -0700379#endif
380
381 SecBuffer out_sec;
Yves Gerey665174f2018-06-19 15:03:05 +0200382 out_sec.pvBuffer = out_buf;
383 out_sec.cbBuffer = sizeof(out_buf);
deadbeeff137e972017-03-23 15:45:49 -0700384 out_sec.BufferType = SECBUFFER_TOKEN;
385
386 SecBufferDesc out_buf_desc;
387 out_buf_desc.ulVersion = 0;
Yves Gerey665174f2018-06-19 15:03:05 +0200388 out_buf_desc.cBuffers = 1;
389 out_buf_desc.pBuffers = &out_sec;
deadbeeff137e972017-03-23 15:45:49 -0700390
391 const ULONG NEG_FLAGS_DEFAULT =
Yves Gerey665174f2018-06-19 15:03:05 +0200392 // ISC_REQ_ALLOCATE_MEMORY
393 ISC_REQ_CONFIDENTIALITY
394 //| ISC_REQ_EXTENDED_ERROR
395 //| ISC_REQ_INTEGRITY
396 | ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT
397 //| ISC_REQ_STREAM
398 //| ISC_REQ_USE_SUPPLIED_CREDS
399 ;
deadbeeff137e972017-03-23 15:45:49 -0700400
401 ::TimeStamp lifetime;
402 SECURITY_STATUS ret = S_OK;
403 ULONG ret_flags = 0, flags = NEG_FLAGS_DEFAULT;
404
405 bool specify_credentials = !username.empty();
406 size_t steps = 0;
407
408 // uint32_t now = Time();
409
Yves Gerey665174f2018-06-19 15:03:05 +0200410 NegotiateAuthContext* neg = static_cast<NegotiateAuthContext*>(context);
deadbeeff137e972017-03-23 15:45:49 -0700411 if (neg) {
412 const size_t max_steps = 10;
413 if (++neg->steps >= max_steps) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100414 RTC_LOG(WARNING) << "AsyncHttpsProxySocket::Authenticate(Negotiate) "
415 "too many retries";
deadbeeff137e972017-03-23 15:45:49 -0700416 return HAR_ERROR;
417 }
418 steps = neg->steps;
419
420 std::string challenge, decoded_challenge;
421 if (HttpHasNthAttribute(args, 1, &challenge, nullptr) &&
422 Base64::Decode(challenge, Base64::DO_STRICT, &decoded_challenge,
423 nullptr)) {
424 SecBuffer in_sec;
Yves Gerey665174f2018-06-19 15:03:05 +0200425 in_sec.pvBuffer = const_cast<char*>(decoded_challenge.data());
426 in_sec.cbBuffer = static_cast<unsigned long>(decoded_challenge.size());
deadbeeff137e972017-03-23 15:45:49 -0700427 in_sec.BufferType = SECBUFFER_TOKEN;
428
429 SecBufferDesc in_buf_desc;
430 in_buf_desc.ulVersion = 0;
Yves Gerey665174f2018-06-19 15:03:05 +0200431 in_buf_desc.cBuffers = 1;
432 in_buf_desc.pBuffers = &in_sec;
deadbeeff137e972017-03-23 15:45:49 -0700433
Yves Gerey665174f2018-06-19 15:03:05 +0200434 ret = InitializeSecurityContextA(
435 &neg->cred, &neg->ctx, spn, flags, 0, SECURITY_NATIVE_DREP,
436 &in_buf_desc, 0, &neg->ctx, &out_buf_desc, &ret_flags, &lifetime);
deadbeeff137e972017-03-23 15:45:49 -0700437 if (FAILED(ret)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100438 RTC_LOG(LS_ERROR) << "InitializeSecurityContext returned: "
Tommie51a0a82018-02-27 15:30:29 +0100439 << GetErrorName(ret, SECURITY_ERRORS);
deadbeeff137e972017-03-23 15:45:49 -0700440 return HAR_ERROR;
441 }
442 } else if (neg->specified_credentials) {
443 // Try again with default credentials
444 specify_credentials = false;
445 delete context;
446 context = neg = 0;
447 } else {
448 return HAR_CREDENTIALS;
449 }
450 }
451
452 if (!neg) {
453 unsigned char userbuf[256], passbuf[256], domainbuf[16];
Yves Gerey665174f2018-06-19 15:03:05 +0200454 SEC_WINNT_AUTH_IDENTITY_A auth_id, *pauth_id = 0;
deadbeeff137e972017-03-23 15:45:49 -0700455 if (specify_credentials) {
456 memset(&auth_id, 0, sizeof(auth_id));
Yves Gerey665174f2018-06-19 15:03:05 +0200457 size_t len = password.GetLength() + 1;
458 char* sensitive = new char[len];
deadbeeff137e972017-03-23 15:45:49 -0700459 password.CopyTo(sensitive, true);
460 std::string::size_type pos = username.find('\\');
461 if (pos == std::string::npos) {
462 auth_id.UserLength = static_cast<unsigned long>(
463 std::min(sizeof(userbuf) - 1, username.size()));
464 memcpy(userbuf, username.c_str(), auth_id.UserLength);
465 userbuf[auth_id.UserLength] = 0;
466 auth_id.DomainLength = 0;
467 domainbuf[auth_id.DomainLength] = 0;
468 auth_id.PasswordLength = static_cast<unsigned long>(
469 std::min(sizeof(passbuf) - 1, password.GetLength()));
470 memcpy(passbuf, sensitive, auth_id.PasswordLength);
471 passbuf[auth_id.PasswordLength] = 0;
472 } else {
473 auth_id.UserLength = static_cast<unsigned long>(
474 std::min(sizeof(userbuf) - 1, username.size() - pos - 1));
475 memcpy(userbuf, username.c_str() + pos + 1, auth_id.UserLength);
476 userbuf[auth_id.UserLength] = 0;
477 auth_id.DomainLength =
478 static_cast<unsigned long>(std::min(sizeof(domainbuf) - 1, pos));
479 memcpy(domainbuf, username.c_str(), auth_id.DomainLength);
480 domainbuf[auth_id.DomainLength] = 0;
481 auth_id.PasswordLength = static_cast<unsigned long>(
482 std::min(sizeof(passbuf) - 1, password.GetLength()));
483 memcpy(passbuf, sensitive, auth_id.PasswordLength);
484 passbuf[auth_id.PasswordLength] = 0;
485 }
Joachim Bauch5b32f232018-03-07 20:02:26 +0100486 ExplicitZeroMemory(sensitive, len);
Yves Gerey665174f2018-06-19 15:03:05 +0200487 delete[] sensitive;
deadbeeff137e972017-03-23 15:45:49 -0700488 auth_id.User = userbuf;
489 auth_id.Domain = domainbuf;
490 auth_id.Password = passbuf;
491 auth_id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
492 pauth_id = &auth_id;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100493 RTC_LOG(LS_VERBOSE)
494 << "Negotiate protocol: Using specified credentials";
deadbeeff137e972017-03-23 15:45:49 -0700495 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100496 RTC_LOG(LS_VERBOSE) << "Negotiate protocol: Using default credentials";
deadbeeff137e972017-03-23 15:45:49 -0700497 }
498
499 CredHandle cred;
500 ret = AcquireCredentialsHandleA(
501 0, const_cast<char*>(want_negotiate ? NEGOSSP_NAME_A : NTLMSP_NAME_A),
502 SECPKG_CRED_OUTBOUND, 0, pauth_id, 0, 0, &cred, &lifetime);
deadbeeff137e972017-03-23 15:45:49 -0700503 if (ret != SEC_E_OK) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100504 RTC_LOG(LS_ERROR) << "AcquireCredentialsHandle error: "
Tommie51a0a82018-02-27 15:30:29 +0100505 << GetErrorName(ret, SECURITY_ERRORS);
deadbeeff137e972017-03-23 15:45:49 -0700506 return HAR_IGNORE;
507 }
508
Yves Gerey665174f2018-06-19 15:03:05 +0200509 // CSecBufferBundle<5, CSecBufferBase::FreeSSPI> sb_out;
deadbeeff137e972017-03-23 15:45:49 -0700510
511 CtxtHandle ctx;
Yves Gerey665174f2018-06-19 15:03:05 +0200512 ret = InitializeSecurityContextA(&cred, 0, spn, flags, 0,
513 SECURITY_NATIVE_DREP, 0, 0, &ctx,
514 &out_buf_desc, &ret_flags, &lifetime);
deadbeeff137e972017-03-23 15:45:49 -0700515 if (FAILED(ret)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100516 RTC_LOG(LS_ERROR) << "InitializeSecurityContext returned: "
Tommie51a0a82018-02-27 15:30:29 +0100517 << GetErrorName(ret, SECURITY_ERRORS);
deadbeeff137e972017-03-23 15:45:49 -0700518 FreeCredentialsHandle(&cred);
519 return HAR_IGNORE;
520 }
521
522 RTC_DCHECK(!context);
523 context = neg = new NegotiateAuthContext(auth_method, cred, ctx);
524 neg->specified_credentials = specify_credentials;
525 neg->steps = steps;
526 }
527
Yves Gerey665174f2018-06-19 15:03:05 +0200528 if ((ret == SEC_I_COMPLETE_NEEDED) ||
529 (ret == SEC_I_COMPLETE_AND_CONTINUE)) {
deadbeeff137e972017-03-23 15:45:49 -0700530 ret = CompleteAuthToken(&neg->ctx, &out_buf_desc);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100531 RTC_LOG(LS_VERBOSE) << "CompleteAuthToken returned: "
Tommie51a0a82018-02-27 15:30:29 +0100532 << GetErrorName(ret, SECURITY_ERRORS);
deadbeeff137e972017-03-23 15:45:49 -0700533 if (FAILED(ret)) {
534 return HAR_ERROR;
535 }
536 }
537
deadbeeff137e972017-03-23 15:45:49 -0700538 std::string decoded(out_buf, out_buf + out_sec.cbBuffer);
539 response = auth_method;
540 response.append(" ");
541 response.append(Base64::Encode(decoded));
542 return HAR_RESPONSE;
543 }
544#endif
Robin Raymondce1b1402018-11-22 20:10:11 -0500545#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
deadbeeff137e972017-03-23 15:45:49 -0700546
547 return HAR_IGNORE;
548}
549
550//////////////////////////////////////////////////////////////////////
551
Yves Gerey665174f2018-06-19 15:03:05 +0200552} // namespace rtc