1 /**
2  * WinPR: Windows Portable Runtime
3  * NTLM Security Package
4  *
5  * Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include <winpr/crt.h>
25 #include <winpr/sspi.h>
26 #include <winpr/print.h>
27 #include <winpr/tchar.h>
28 #include <winpr/sysinfo.h>
29 #include <winpr/registry.h>
30 #include <winpr/endian.h>
31 #include <freerdp/build-config.h>
32 
33 #include "ntlm.h"
34 #include "../sspi.h"
35 
36 #include "ntlm_message.h"
37 
38 #include "../../log.h"
39 #define TAG WINPR_TAG("sspi.NTLM")
40 
41 #define WINPR_KEY "Software\\" FREERDP_VENDOR_STRING "\\" FREERDP_PRODUCT_STRING "\\WinPR\\NTLM"
42 
43 static const char* NTLM_PACKAGE_NAME = "NTLM";
44 
ntlm_SetContextWorkstation(NTLM_CONTEXT * context,char * Workstation)45 static int ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation)
46 {
47 	int status;
48 	char* ws = Workstation;
49 	DWORD nSize = 0;
50 	CHAR* computerName;
51 
52 	if (!Workstation)
53 	{
54 		if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) ||
55 		    GetLastError() != ERROR_MORE_DATA)
56 			return -1;
57 
58 		computerName = calloc(nSize, sizeof(CHAR));
59 
60 		if (!computerName)
61 			return -1;
62 
63 		if (!GetComputerNameExA(ComputerNameNetBIOS, computerName, &nSize))
64 		{
65 			free(computerName);
66 			return -1;
67 		}
68 
69 		if (nSize > MAX_COMPUTERNAME_LENGTH)
70 			computerName[MAX_COMPUTERNAME_LENGTH] = '\0';
71 
72 		ws = computerName;
73 
74 		if (!ws)
75 			return -1;
76 	}
77 
78 	context->Workstation.Buffer = NULL;
79 	status = ConvertToUnicode(CP_UTF8, 0, ws, -1, &context->Workstation.Buffer, 0);
80 
81 	if (!Workstation)
82 		free(ws);
83 
84 	if (status <= 0)
85 		return -1;
86 
87 	context->Workstation.Length = (USHORT)(status - 1);
88 	context->Workstation.Length *= 2;
89 	return 1;
90 }
91 
ntlm_SetContextServicePrincipalNameW(NTLM_CONTEXT * context,LPWSTR ServicePrincipalName)92 static int ntlm_SetContextServicePrincipalNameW(NTLM_CONTEXT* context, LPWSTR ServicePrincipalName)
93 {
94 	if (!ServicePrincipalName)
95 	{
96 		context->ServicePrincipalName.Buffer = NULL;
97 		context->ServicePrincipalName.Length = 0;
98 		return 1;
99 	}
100 
101 	context->ServicePrincipalName.Length = (USHORT)(_wcslen(ServicePrincipalName) * 2);
102 	context->ServicePrincipalName.Buffer = (PWSTR)malloc(context->ServicePrincipalName.Length + 2);
103 
104 	if (!context->ServicePrincipalName.Buffer)
105 		return -1;
106 
107 	CopyMemory(context->ServicePrincipalName.Buffer, ServicePrincipalName,
108 	           context->ServicePrincipalName.Length + 2);
109 	return 1;
110 }
111 
ntlm_SetContextTargetName(NTLM_CONTEXT * context,char * TargetName)112 static int ntlm_SetContextTargetName(NTLM_CONTEXT* context, char* TargetName)
113 {
114 	int status;
115 	char* name = TargetName;
116 	DWORD nSize = 0;
117 	CHAR* computerName = NULL;
118 
119 	if (!name)
120 	{
121 		if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) ||
122 		    GetLastError() != ERROR_MORE_DATA)
123 			return -1;
124 
125 		computerName = calloc(nSize, sizeof(CHAR));
126 
127 		if (!computerName)
128 			return -1;
129 
130 		if (!GetComputerNameExA(ComputerNameNetBIOS, computerName, &nSize))
131 		{
132 			free(computerName);
133 			return -1;
134 		}
135 
136 		if (nSize > MAX_COMPUTERNAME_LENGTH)
137 			computerName[MAX_COMPUTERNAME_LENGTH] = '\0';
138 
139 		name = computerName;
140 
141 		if (!name)
142 			return -1;
143 
144 		CharUpperA(name);
145 	}
146 
147 	context->TargetName.pvBuffer = NULL;
148 	status = ConvertToUnicode(CP_UTF8, 0, name, -1, (LPWSTR*)&context->TargetName.pvBuffer, 0);
149 
150 	if (status <= 0)
151 	{
152 		if (!TargetName)
153 			free(name);
154 
155 		return -1;
156 	}
157 
158 	context->TargetName.cbBuffer = (USHORT)((status - 1) * 2);
159 
160 	if (!TargetName)
161 		free(name);
162 
163 	return 1;
164 }
165 
ntlm_ContextNew(void)166 static NTLM_CONTEXT* ntlm_ContextNew(void)
167 {
168 	HKEY hKey;
169 	LONG status;
170 	DWORD dwType;
171 	DWORD dwSize;
172 	DWORD dwValue;
173 	NTLM_CONTEXT* context;
174 	context = (NTLM_CONTEXT*)calloc(1, sizeof(NTLM_CONTEXT));
175 
176 	if (!context)
177 		return NULL;
178 
179 	context->NTLMv2 = TRUE;
180 	context->UseMIC = FALSE;
181 	context->SendVersionInfo = TRUE;
182 	context->SendSingleHostData = FALSE;
183 	context->SendWorkstationName = TRUE;
184 	context->NegotiateKeyExchange = TRUE;
185 	context->UseSamFileDatabase = TRUE;
186 	status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, WINPR_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
187 
188 	if (status == ERROR_SUCCESS)
189 	{
190 		if (RegQueryValueEx(hKey, _T("NTLMv2"), NULL, &dwType, (BYTE*)&dwValue, &dwSize) ==
191 		    ERROR_SUCCESS)
192 			context->NTLMv2 = dwValue ? 1 : 0;
193 
194 		if (RegQueryValueEx(hKey, _T("UseMIC"), NULL, &dwType, (BYTE*)&dwValue, &dwSize) ==
195 		    ERROR_SUCCESS)
196 			context->UseMIC = dwValue ? 1 : 0;
197 
198 		if (RegQueryValueEx(hKey, _T("SendVersionInfo"), NULL, &dwType, (BYTE*)&dwValue, &dwSize) ==
199 		    ERROR_SUCCESS)
200 			context->SendVersionInfo = dwValue ? 1 : 0;
201 
202 		if (RegQueryValueEx(hKey, _T("SendSingleHostData"), NULL, &dwType, (BYTE*)&dwValue,
203 		                    &dwSize) == ERROR_SUCCESS)
204 			context->SendSingleHostData = dwValue ? 1 : 0;
205 
206 		if (RegQueryValueEx(hKey, _T("SendWorkstationName"), NULL, &dwType, (BYTE*)&dwValue,
207 		                    &dwSize) == ERROR_SUCCESS)
208 			context->SendWorkstationName = dwValue ? 1 : 0;
209 
210 		if (RegQueryValueEx(hKey, _T("WorkstationName"), NULL, &dwType, NULL, &dwSize) ==
211 		    ERROR_SUCCESS)
212 		{
213 			char* workstation = (char*)malloc(dwSize + 1);
214 
215 			if (!workstation)
216 			{
217 				free(context);
218 				return NULL;
219 			}
220 
221 			status = RegQueryValueExA(hKey, "WorkstationName", NULL, &dwType, (BYTE*)workstation,
222 			                          &dwSize);
223 			workstation[dwSize] = '\0';
224 
225 			if (ntlm_SetContextWorkstation(context, workstation) < 0)
226 			{
227 				free(workstation);
228 				free(context);
229 				return NULL;
230 			}
231 
232 			free(workstation);
233 		}
234 
235 		RegCloseKey(hKey);
236 	}
237 
238 	/*
239 	 * Extended Protection is enabled by default in Windows 7,
240 	 * but enabling it in WinPR breaks TS Gateway at this point
241 	 */
242 	context->SuppressExtendedProtection = FALSE;
243 	status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("System\\CurrentControlSet\\Control\\LSA"), 0,
244 	                      KEY_READ | KEY_WOW64_64KEY, &hKey);
245 
246 	if (status == ERROR_SUCCESS)
247 	{
248 		if (RegQueryValueEx(hKey, _T("SuppressExtendedProtection"), NULL, &dwType, (BYTE*)&dwValue,
249 		                    &dwSize) == ERROR_SUCCESS)
250 			context->SuppressExtendedProtection = dwValue ? 1 : 0;
251 
252 		RegCloseKey(hKey);
253 	}
254 
255 	context->NegotiateFlags = 0;
256 	context->LmCompatibilityLevel = 3;
257 	context->state = NTLM_STATE_INITIAL;
258 	FillMemory(context->MachineID, sizeof(context->MachineID), 0xAA);
259 
260 	if (context->NTLMv2)
261 		context->UseMIC = TRUE;
262 
263 	return context;
264 }
265 
ntlm_ContextFree(NTLM_CONTEXT * context)266 static void ntlm_ContextFree(NTLM_CONTEXT* context)
267 {
268 	if (!context)
269 		return;
270 
271 	winpr_RC4_Free(context->SendRc4Seal);
272 	winpr_RC4_Free(context->RecvRc4Seal);
273 	sspi_SecBufferFree(&context->NegotiateMessage);
274 	sspi_SecBufferFree(&context->ChallengeMessage);
275 	sspi_SecBufferFree(&context->AuthenticateMessage);
276 	sspi_SecBufferFree(&context->ChallengeTargetInfo);
277 	sspi_SecBufferFree(&context->TargetName);
278 	sspi_SecBufferFree(&context->NtChallengeResponse);
279 	sspi_SecBufferFree(&context->LmChallengeResponse);
280 	free(context->ServicePrincipalName.Buffer);
281 	free(context->Workstation.Buffer);
282 	free(context);
283 }
284 
ntlm_AcquireCredentialsHandleW(SEC_WCHAR * pszPrincipal,SEC_WCHAR * pszPackage,ULONG fCredentialUse,void * pvLogonID,void * pAuthData,SEC_GET_KEY_FN pGetKeyFn,void * pvGetKeyArgument,PCredHandle phCredential,PTimeStamp ptsExpiry)285 static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(
286     SEC_WCHAR* pszPrincipal, SEC_WCHAR* pszPackage, ULONG fCredentialUse, void* pvLogonID,
287     void* pAuthData, SEC_GET_KEY_FN pGetKeyFn, void* pvGetKeyArgument, PCredHandle phCredential,
288     PTimeStamp ptsExpiry)
289 {
290 	SSPI_CREDENTIALS* credentials;
291 	SEC_WINNT_AUTH_IDENTITY* identity;
292 
293 	if ((fCredentialUse != SECPKG_CRED_OUTBOUND) && (fCredentialUse != SECPKG_CRED_INBOUND) &&
294 	    (fCredentialUse != SECPKG_CRED_BOTH))
295 	{
296 		return SEC_E_INVALID_PARAMETER;
297 	}
298 
299 	credentials = sspi_CredentialsNew();
300 
301 	if (!credentials)
302 		return SEC_E_INTERNAL_ERROR;
303 
304 	credentials->fCredentialUse = fCredentialUse;
305 	credentials->pGetKeyFn = pGetKeyFn;
306 	credentials->pvGetKeyArgument = pvGetKeyArgument;
307 	identity = (SEC_WINNT_AUTH_IDENTITY*)pAuthData;
308 
309 	if (identity)
310 		sspi_CopyAuthIdentity(&(credentials->identity), identity);
311 
312 	sspi_SecureHandleSetLowerPointer(phCredential, (void*)credentials);
313 	sspi_SecureHandleSetUpperPointer(phCredential, (void*)NTLM_PACKAGE_NAME);
314 	return SEC_E_OK;
315 }
316 
ntlm_AcquireCredentialsHandleA(SEC_CHAR * pszPrincipal,SEC_CHAR * pszPackage,ULONG fCredentialUse,void * pvLogonID,void * pAuthData,SEC_GET_KEY_FN pGetKeyFn,void * pvGetKeyArgument,PCredHandle phCredential,PTimeStamp ptsExpiry)317 static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA(
318     SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage, ULONG fCredentialUse, void* pvLogonID,
319     void* pAuthData, SEC_GET_KEY_FN pGetKeyFn, void* pvGetKeyArgument, PCredHandle phCredential,
320     PTimeStamp ptsExpiry)
321 {
322 	SSPI_CREDENTIALS* credentials;
323 	SEC_WINNT_AUTH_IDENTITY* identity;
324 
325 	if ((fCredentialUse != SECPKG_CRED_OUTBOUND) && (fCredentialUse != SECPKG_CRED_INBOUND) &&
326 	    (fCredentialUse != SECPKG_CRED_BOTH))
327 	{
328 		return SEC_E_INVALID_PARAMETER;
329 	}
330 
331 	credentials = sspi_CredentialsNew();
332 
333 	if (!credentials)
334 		return SEC_E_INTERNAL_ERROR;
335 
336 	credentials->fCredentialUse = fCredentialUse;
337 	credentials->pGetKeyFn = pGetKeyFn;
338 	credentials->pvGetKeyArgument = pvGetKeyArgument;
339 	identity = (SEC_WINNT_AUTH_IDENTITY*)pAuthData;
340 
341 	if (identity)
342 		sspi_CopyAuthIdentity(&(credentials->identity), identity);
343 
344 	sspi_SecureHandleSetLowerPointer(phCredential, (void*)credentials);
345 	sspi_SecureHandleSetUpperPointer(phCredential, (void*)NTLM_PACKAGE_NAME);
346 	return SEC_E_OK;
347 }
348 
ntlm_FreeCredentialsHandle(PCredHandle phCredential)349 static SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(PCredHandle phCredential)
350 {
351 	SSPI_CREDENTIALS* credentials;
352 
353 	if (!phCredential)
354 		return SEC_E_INVALID_HANDLE;
355 
356 	credentials = (SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
357 
358 	if (!credentials)
359 		return SEC_E_INVALID_HANDLE;
360 
361 	sspi_CredentialsFree(credentials);
362 	return SEC_E_OK;
363 }
364 
ntlm_QueryCredentialsAttributesW(PCredHandle phCredential,ULONG ulAttribute,void * pBuffer)365 static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesW(PCredHandle phCredential,
366                                                                   ULONG ulAttribute, void* pBuffer)
367 {
368 	if (ulAttribute == SECPKG_CRED_ATTR_NAMES)
369 	{
370 		return SEC_E_OK;
371 	}
372 
373 	WLog_ERR(TAG, "[%s]: TODO: Implement", __FUNCTION__);
374 	return SEC_E_UNSUPPORTED_FUNCTION;
375 }
376 
ntlm_QueryCredentialsAttributesA(PCredHandle phCredential,ULONG ulAttribute,void * pBuffer)377 static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesA(PCredHandle phCredential,
378                                                                   ULONG ulAttribute, void* pBuffer)
379 {
380 	return ntlm_QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
381 }
382 
383 /**
384  * @see http://msdn.microsoft.com/en-us/library/windows/desktop/aa374707
385  */
386 static SECURITY_STATUS SEC_ENTRY
ntlm_AcceptSecurityContext(PCredHandle phCredential,PCtxtHandle phContext,PSecBufferDesc pInput,ULONG fContextReq,ULONG TargetDataRep,PCtxtHandle phNewContext,PSecBufferDesc pOutput,PULONG pfContextAttr,PTimeStamp ptsTimeStamp)387 ntlm_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput,
388                            ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext,
389                            PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsTimeStamp)
390 {
391 	NTLM_CONTEXT* context;
392 	SECURITY_STATUS status;
393 	SSPI_CREDENTIALS* credentials;
394 	PSecBuffer input_buffer;
395 	PSecBuffer output_buffer;
396 	context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
397 
398 	if (!context)
399 	{
400 		context = ntlm_ContextNew();
401 
402 		if (!context)
403 			return SEC_E_INSUFFICIENT_MEMORY;
404 
405 		context->server = TRUE;
406 
407 		if (fContextReq & ASC_REQ_CONFIDENTIALITY)
408 			context->confidentiality = TRUE;
409 
410 		credentials = (SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
411 		context->credentials = credentials;
412 		ntlm_SetContextTargetName(context, NULL);
413 		sspi_SecureHandleSetLowerPointer(phNewContext, context);
414 		sspi_SecureHandleSetUpperPointer(phNewContext, (void*)NTLM_PACKAGE_NAME);
415 	}
416 
417 	if (context->state == NTLM_STATE_INITIAL)
418 	{
419 		context->state = NTLM_STATE_NEGOTIATE;
420 
421 		if (!pInput)
422 			return SEC_E_INVALID_TOKEN;
423 
424 		if (pInput->cBuffers < 1)
425 			return SEC_E_INVALID_TOKEN;
426 
427 		input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
428 
429 		if (!input_buffer)
430 			return SEC_E_INVALID_TOKEN;
431 
432 		if (input_buffer->cbBuffer < 1)
433 			return SEC_E_INVALID_TOKEN;
434 
435 		status = ntlm_read_NegotiateMessage(context, input_buffer);
436 
437 		if (context->state == NTLM_STATE_CHALLENGE)
438 		{
439 			if (!pOutput)
440 				return SEC_E_INVALID_TOKEN;
441 
442 			if (pOutput->cBuffers < 1)
443 				return SEC_E_INVALID_TOKEN;
444 
445 			output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
446 
447 			if (!output_buffer->BufferType)
448 				return SEC_E_INVALID_TOKEN;
449 
450 			if (output_buffer->cbBuffer < 1)
451 				return SEC_E_INSUFFICIENT_MEMORY;
452 
453 			return ntlm_write_ChallengeMessage(context, output_buffer);
454 		}
455 
456 		return SEC_E_OUT_OF_SEQUENCE;
457 	}
458 	else if (context->state == NTLM_STATE_AUTHENTICATE)
459 	{
460 		if (!pInput)
461 			return SEC_E_INVALID_TOKEN;
462 
463 		if (pInput->cBuffers < 1)
464 			return SEC_E_INVALID_TOKEN;
465 
466 		input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
467 
468 		if (!input_buffer)
469 			return SEC_E_INVALID_TOKEN;
470 
471 		if (input_buffer->cbBuffer < 1)
472 			return SEC_E_INVALID_TOKEN;
473 
474 		status = ntlm_read_AuthenticateMessage(context, input_buffer);
475 
476 		if (pOutput)
477 		{
478 			ULONG i;
479 
480 			for (i = 0; i < pOutput->cBuffers; i++)
481 			{
482 				pOutput->pBuffers[i].cbBuffer = 0;
483 				pOutput->pBuffers[i].BufferType = SECBUFFER_TOKEN;
484 			}
485 		}
486 
487 		return status;
488 	}
489 
490 	return SEC_E_OUT_OF_SEQUENCE;
491 }
492 
ntlm_ImpersonateSecurityContext(PCtxtHandle phContext)493 static SECURITY_STATUS SEC_ENTRY ntlm_ImpersonateSecurityContext(PCtxtHandle phContext)
494 {
495 	return SEC_E_OK;
496 }
497 
ntlm_InitializeSecurityContextW(PCredHandle phCredential,PCtxtHandle phContext,SEC_WCHAR * pszTargetName,ULONG fContextReq,ULONG Reserved1,ULONG TargetDataRep,PSecBufferDesc pInput,ULONG Reserved2,PCtxtHandle phNewContext,PSecBufferDesc pOutput,PULONG pfContextAttr,PTimeStamp ptsExpiry)498 static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
499     PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR* pszTargetName, ULONG fContextReq,
500     ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2,
501     PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
502 {
503 	NTLM_CONTEXT* context;
504 	SECURITY_STATUS status;
505 	SSPI_CREDENTIALS* credentials;
506 	PSecBuffer input_buffer = NULL;
507 	PSecBuffer output_buffer = NULL;
508 	PSecBuffer channel_bindings = NULL;
509 	context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
510 
511 	if (!context)
512 	{
513 		context = ntlm_ContextNew();
514 
515 		if (!context)
516 			return SEC_E_INSUFFICIENT_MEMORY;
517 
518 		if (fContextReq & ISC_REQ_CONFIDENTIALITY)
519 			context->confidentiality = TRUE;
520 
521 		credentials = (SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
522 		context->credentials = credentials;
523 
524 		if (context->Workstation.Length < 1)
525 		{
526 			if (ntlm_SetContextWorkstation(context, NULL) < 0)
527 			{
528 				ntlm_ContextFree(context);
529 				return SEC_E_INTERNAL_ERROR;
530 			}
531 		}
532 
533 		if (ntlm_SetContextServicePrincipalNameW(context, pszTargetName) < 0)
534 		{
535 			ntlm_ContextFree(context);
536 			return SEC_E_INTERNAL_ERROR;
537 		}
538 
539 		sspi_SecureHandleSetLowerPointer(phNewContext, context);
540 		sspi_SecureHandleSetUpperPointer(phNewContext, (void*)NTLM_PACKAGE_NAME);
541 	}
542 
543 	if ((!pInput) || (context->state == NTLM_STATE_AUTHENTICATE))
544 	{
545 		if (!pOutput)
546 			return SEC_E_INVALID_TOKEN;
547 
548 		if (pOutput->cBuffers < 1)
549 			return SEC_E_INVALID_TOKEN;
550 
551 		output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
552 
553 		if (!output_buffer)
554 			return SEC_E_INVALID_TOKEN;
555 
556 		if (output_buffer->cbBuffer < 1)
557 			return SEC_E_INVALID_TOKEN;
558 
559 		if (context->state == NTLM_STATE_INITIAL)
560 			context->state = NTLM_STATE_NEGOTIATE;
561 
562 		if (context->state == NTLM_STATE_NEGOTIATE)
563 			return ntlm_write_NegotiateMessage(context, output_buffer);
564 
565 		return SEC_E_OUT_OF_SEQUENCE;
566 	}
567 	else
568 	{
569 		if (pInput->cBuffers < 1)
570 			return SEC_E_INVALID_TOKEN;
571 
572 		input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
573 
574 		if (!input_buffer)
575 			return SEC_E_INVALID_TOKEN;
576 
577 		if (input_buffer->cbBuffer < 1)
578 			return SEC_E_INVALID_TOKEN;
579 
580 		channel_bindings = sspi_FindSecBuffer(pInput, SECBUFFER_CHANNEL_BINDINGS);
581 
582 		if (channel_bindings)
583 		{
584 			context->Bindings.BindingsLength = channel_bindings->cbBuffer;
585 			context->Bindings.Bindings = (SEC_CHANNEL_BINDINGS*)channel_bindings->pvBuffer;
586 		}
587 
588 		if (context->state == NTLM_STATE_CHALLENGE)
589 		{
590 			status = ntlm_read_ChallengeMessage(context, input_buffer);
591 
592 			if (!pOutput)
593 				return SEC_E_INVALID_TOKEN;
594 
595 			if (pOutput->cBuffers < 1)
596 				return SEC_E_INVALID_TOKEN;
597 
598 			output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
599 
600 			if (!output_buffer)
601 				return SEC_E_INVALID_TOKEN;
602 
603 			if (output_buffer->cbBuffer < 1)
604 				return SEC_E_INSUFFICIENT_MEMORY;
605 
606 			if (context->state == NTLM_STATE_AUTHENTICATE)
607 				return ntlm_write_AuthenticateMessage(context, output_buffer);
608 		}
609 
610 		return SEC_E_OUT_OF_SEQUENCE;
611 	}
612 
613 	return SEC_E_OUT_OF_SEQUENCE;
614 }
615 
616 /**
617  * @see http://msdn.microsoft.com/en-us/library/windows/desktop/aa375512%28v=vs.85%29.aspx
618  */
ntlm_InitializeSecurityContextA(PCredHandle phCredential,PCtxtHandle phContext,SEC_CHAR * pszTargetName,ULONG fContextReq,ULONG Reserved1,ULONG TargetDataRep,PSecBufferDesc pInput,ULONG Reserved2,PCtxtHandle phNewContext,PSecBufferDesc pOutput,PULONG pfContextAttr,PTimeStamp ptsExpiry)619 static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA(
620     PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR* pszTargetName, ULONG fContextReq,
621     ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2,
622     PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
623 {
624 	SECURITY_STATUS status;
625 	SEC_WCHAR* pszTargetNameW = NULL;
626 
627 	if (pszTargetName)
628 	{
629 		if (ConvertToUnicode(CP_UTF8, 0, pszTargetName, -1, &pszTargetNameW, 0) <= 0)
630 			return SEC_E_INTERNAL_ERROR;
631 	}
632 
633 	status = ntlm_InitializeSecurityContextW(phCredential, phContext, pszTargetNameW, fContextReq,
634 	                                         Reserved1, TargetDataRep, pInput, Reserved2,
635 	                                         phNewContext, pOutput, pfContextAttr, ptsExpiry);
636 	free(pszTargetNameW);
637 	return status;
638 }
639 
ntlm_CompleteAuthToken(PCtxtHandle phContext,PSecBufferDesc pToken)640 static SECURITY_STATUS SEC_ENTRY ntlm_CompleteAuthToken(PCtxtHandle phContext,
641                                                         PSecBufferDesc pToken)
642 {
643 	NTLM_CONTEXT* context;
644 	SECURITY_STATUS status = SEC_E_OK;
645 	context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
646 
647 	if (!context)
648 		return SEC_E_INVALID_HANDLE;
649 
650 	if (context->server)
651 	{
652 		status = ntlm_server_AuthenticateComplete(context);
653 	}
654 
655 	return status;
656 }
657 
658 /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375354 */
659 
ntlm_DeleteSecurityContext(PCtxtHandle phContext)660 static SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext)
661 {
662 	NTLM_CONTEXT* context;
663 	context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
664 
665 	if (!context)
666 		return SEC_E_INVALID_HANDLE;
667 
668 	ntlm_ContextFree(context);
669 	return SEC_E_OK;
670 }
671 
ntlm_computeProofValue(NTLM_CONTEXT * ntlm,SecBuffer * ntproof)672 SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT* ntlm, SecBuffer* ntproof)
673 {
674 	BYTE* blob;
675 	SecBuffer* target = &ntlm->ChallengeTargetInfo;
676 
677 	if (!sspi_SecBufferAlloc(ntproof, 36 + target->cbBuffer))
678 		return SEC_E_INSUFFICIENT_MEMORY;
679 
680 	blob = (BYTE*)ntproof->pvBuffer;
681 	CopyMemory(blob, ntlm->ServerChallenge, 8); /* Server challenge. */
682 	blob[8] = 1;                                /* Response version. */
683 	blob[9] = 1; /* Highest response version understood by the client. */
684 	/* Reserved 6B. */
685 	CopyMemory(&blob[16], ntlm->Timestamp, 8);       /* Time. */
686 	CopyMemory(&blob[24], ntlm->ClientChallenge, 8); /* Client challenge. */
687 	/* Reserved 4B. */
688 	/* Server name. */
689 	CopyMemory(&blob[36], target->pvBuffer, target->cbBuffer);
690 	return SEC_E_OK;
691 }
692 
ntlm_computeMicValue(NTLM_CONTEXT * ntlm,SecBuffer * micvalue)693 SECURITY_STATUS ntlm_computeMicValue(NTLM_CONTEXT* ntlm, SecBuffer* micvalue)
694 {
695 	BYTE* blob;
696 	ULONG msgSize = ntlm->NegotiateMessage.cbBuffer + ntlm->ChallengeMessage.cbBuffer +
697 	                ntlm->AuthenticateMessage.cbBuffer;
698 
699 	if (!sspi_SecBufferAlloc(micvalue, msgSize))
700 		return SEC_E_INSUFFICIENT_MEMORY;
701 
702 	blob = (BYTE*)micvalue->pvBuffer;
703 	CopyMemory(blob, ntlm->NegotiateMessage.pvBuffer, ntlm->NegotiateMessage.cbBuffer);
704 	blob += ntlm->NegotiateMessage.cbBuffer;
705 	CopyMemory(blob, ntlm->ChallengeMessage.pvBuffer, ntlm->ChallengeMessage.cbBuffer);
706 	blob += ntlm->ChallengeMessage.cbBuffer;
707 	CopyMemory(blob, ntlm->AuthenticateMessage.pvBuffer, ntlm->AuthenticateMessage.cbBuffer);
708 	blob += ntlm->MessageIntegrityCheckOffset;
709 	ZeroMemory(blob, 16);
710 	return SEC_E_OK;
711 }
712 
713 /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa379337/ */
714 
ntlm_QueryContextAttributesW(PCtxtHandle phContext,ULONG ulAttribute,void * pBuffer)715 static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext,
716                                                               ULONG ulAttribute, void* pBuffer)
717 {
718 	NTLM_CONTEXT* context;
719 
720 	if (!phContext)
721 		return SEC_E_INVALID_HANDLE;
722 
723 	if (!pBuffer)
724 		return SEC_E_INSUFFICIENT_MEMORY;
725 
726 	context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
727 
728 	if (ulAttribute == SECPKG_ATTR_SIZES)
729 	{
730 		SecPkgContext_Sizes* ContextSizes = (SecPkgContext_Sizes*)pBuffer;
731 		ContextSizes->cbMaxToken = 2010;
732 		ContextSizes->cbMaxSignature = 16;    /* the size of expected signature is 16 bytes */
733 		ContextSizes->cbBlockSize = 0;        /* no padding */
734 		ContextSizes->cbSecurityTrailer = 16; /* no security trailer appended in NTLM
735 		                            contrary to Kerberos */
736 		return SEC_E_OK;
737 	}
738 	else if (ulAttribute == SECPKG_ATTR_AUTH_IDENTITY)
739 	{
740 		int status;
741 		char* UserA = NULL;
742 		char* DomainA = NULL;
743 		SSPI_CREDENTIALS* credentials;
744 		SecPkgContext_AuthIdentity* AuthIdentity = (SecPkgContext_AuthIdentity*)pBuffer;
745 		context->UseSamFileDatabase = FALSE;
746 		credentials = context->credentials;
747 		ZeroMemory(AuthIdentity, sizeof(SecPkgContext_AuthIdentity));
748 		UserA = AuthIdentity->User;
749 
750 		if (credentials->identity.UserLength > 0)
751 		{
752 			status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)credentials->identity.User,
753 			                            credentials->identity.UserLength, &UserA, 256, NULL, NULL);
754 
755 			if (status <= 0)
756 				return SEC_E_INTERNAL_ERROR;
757 		}
758 
759 		DomainA = AuthIdentity->Domain;
760 
761 		if (credentials->identity.DomainLength > 0)
762 		{
763 			status =
764 			    ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)credentials->identity.Domain,
765 			                       credentials->identity.DomainLength, &DomainA, 256, NULL, NULL);
766 
767 			if (status <= 0)
768 				return SEC_E_INTERNAL_ERROR;
769 		}
770 
771 		return SEC_E_OK;
772 	}
773 	else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_NTPROOF_VALUE)
774 	{
775 		return ntlm_computeProofValue(context, (SecBuffer*)pBuffer);
776 	}
777 	else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_RANDKEY)
778 	{
779 		SecBuffer* randkey;
780 		randkey = (SecBuffer*)pBuffer;
781 
782 		if (!sspi_SecBufferAlloc(randkey, 16))
783 			return (SEC_E_INSUFFICIENT_MEMORY);
784 
785 		CopyMemory(randkey->pvBuffer, context->EncryptedRandomSessionKey, 16);
786 		return (SEC_E_OK);
787 	}
788 	else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_MIC)
789 	{
790 		SecBuffer* mic;
791 		NTLM_AUTHENTICATE_MESSAGE* message;
792 		mic = (SecBuffer*)pBuffer;
793 		message = &context->AUTHENTICATE_MESSAGE;
794 
795 		if (!sspi_SecBufferAlloc(mic, 16))
796 			return (SEC_E_INSUFFICIENT_MEMORY);
797 
798 		CopyMemory(mic->pvBuffer, message->MessageIntegrityCheck, 16);
799 		return (SEC_E_OK);
800 	}
801 	else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_MIC_VALUE)
802 	{
803 		return ntlm_computeMicValue(context, (SecBuffer*)pBuffer);
804 	}
805 
806 	WLog_ERR(TAG, "[%s]: TODO: Implement ulAttribute%08" PRIx32, __FUNCTION__, ulAttribute);
807 	return SEC_E_UNSUPPORTED_FUNCTION;
808 }
809 
ntlm_QueryContextAttributesA(PCtxtHandle phContext,ULONG ulAttribute,void * pBuffer)810 static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(PCtxtHandle phContext,
811                                                               ULONG ulAttribute, void* pBuffer)
812 {
813 	return ntlm_QueryContextAttributesW(phContext, ulAttribute, pBuffer);
814 }
815 
ntlm_SetContextAttributesW(PCtxtHandle phContext,ULONG ulAttribute,void * pBuffer,ULONG cbBuffer)816 static SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesW(PCtxtHandle phContext,
817                                                             ULONG ulAttribute, void* pBuffer,
818                                                             ULONG cbBuffer)
819 {
820 	NTLM_CONTEXT* context;
821 
822 	if (!phContext)
823 		return SEC_E_INVALID_HANDLE;
824 
825 	if (!pBuffer)
826 		return SEC_E_INVALID_PARAMETER;
827 
828 	context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
829 
830 	if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_HASH)
831 	{
832 		SecPkgContext_AuthNtlmHash* AuthNtlmHash = (SecPkgContext_AuthNtlmHash*)pBuffer;
833 
834 		if (cbBuffer < sizeof(SecPkgContext_AuthNtlmHash))
835 			return SEC_E_INVALID_PARAMETER;
836 
837 		if (AuthNtlmHash->Version == 1)
838 			CopyMemory(context->NtlmHash, AuthNtlmHash->NtlmHash, 16);
839 		else if (AuthNtlmHash->Version == 2)
840 			CopyMemory(context->NtlmV2Hash, AuthNtlmHash->NtlmHash, 16);
841 
842 		return SEC_E_OK;
843 	}
844 	else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_SAM_FILE)
845 	{
846 		const char* filename = (char*)pBuffer;
847 		free(context->SamFile);
848 		context->SamFile = NULL;
849 
850 		if (filename)
851 		{
852 			context->SamFile = _strdup(filename);
853 
854 			if (!context->SamFile)
855 				return SEC_E_INSUFFICIENT_MEMORY;
856 		}
857 
858 		return SEC_E_OK;
859 	}
860 	else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_MESSAGE)
861 	{
862 		SecPkgContext_AuthNtlmMessage* AuthNtlmMessage = (SecPkgContext_AuthNtlmMessage*)pBuffer;
863 
864 		if (cbBuffer < sizeof(SecPkgContext_AuthNtlmMessage))
865 			return SEC_E_INVALID_PARAMETER;
866 
867 		if (AuthNtlmMessage->type == 1)
868 		{
869 			sspi_SecBufferFree(&context->NegotiateMessage);
870 
871 			if (!sspi_SecBufferAlloc(&context->NegotiateMessage, AuthNtlmMessage->length))
872 				return SEC_E_INSUFFICIENT_MEMORY;
873 
874 			CopyMemory(context->NegotiateMessage.pvBuffer, AuthNtlmMessage->buffer,
875 			           AuthNtlmMessage->length);
876 		}
877 		else if (AuthNtlmMessage->type == 2)
878 		{
879 			sspi_SecBufferFree(&context->ChallengeMessage);
880 
881 			if (!sspi_SecBufferAlloc(&context->ChallengeMessage, AuthNtlmMessage->length))
882 				return SEC_E_INSUFFICIENT_MEMORY;
883 
884 			CopyMemory(context->ChallengeMessage.pvBuffer, AuthNtlmMessage->buffer,
885 			           AuthNtlmMessage->length);
886 		}
887 		else if (AuthNtlmMessage->type == 3)
888 		{
889 			sspi_SecBufferFree(&context->AuthenticateMessage);
890 
891 			if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, AuthNtlmMessage->length))
892 				return SEC_E_INSUFFICIENT_MEMORY;
893 
894 			CopyMemory(context->AuthenticateMessage.pvBuffer, AuthNtlmMessage->buffer,
895 			           AuthNtlmMessage->length);
896 		}
897 
898 		return SEC_E_OK;
899 	}
900 	else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_TIMESTAMP)
901 	{
902 		SecPkgContext_AuthNtlmTimestamp* AuthNtlmTimestamp =
903 		    (SecPkgContext_AuthNtlmTimestamp*)pBuffer;
904 
905 		if (cbBuffer < sizeof(SecPkgContext_AuthNtlmTimestamp))
906 			return SEC_E_INVALID_PARAMETER;
907 
908 		if (AuthNtlmTimestamp->ChallengeOrResponse)
909 			CopyMemory(context->ChallengeTimestamp, AuthNtlmTimestamp->Timestamp, 8);
910 		else
911 			CopyMemory(context->Timestamp, AuthNtlmTimestamp->Timestamp, 8);
912 
913 		return SEC_E_OK;
914 	}
915 	else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE)
916 	{
917 		SecPkgContext_AuthNtlmClientChallenge* AuthNtlmClientChallenge =
918 		    (SecPkgContext_AuthNtlmClientChallenge*)pBuffer;
919 
920 		if (cbBuffer < sizeof(SecPkgContext_AuthNtlmClientChallenge))
921 			return SEC_E_INVALID_PARAMETER;
922 
923 		CopyMemory(context->ClientChallenge, AuthNtlmClientChallenge->ClientChallenge, 8);
924 		return SEC_E_OK;
925 	}
926 	else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE)
927 	{
928 		SecPkgContext_AuthNtlmServerChallenge* AuthNtlmServerChallenge =
929 		    (SecPkgContext_AuthNtlmServerChallenge*)pBuffer;
930 
931 		if (cbBuffer < sizeof(SecPkgContext_AuthNtlmServerChallenge))
932 			return SEC_E_INVALID_PARAMETER;
933 
934 		CopyMemory(context->ServerChallenge, AuthNtlmServerChallenge->ServerChallenge, 8);
935 		return SEC_E_OK;
936 	}
937 	else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_HASH_CB)
938 	{
939 		context->HashCallback = (psPeerComputeNtlmHash)pBuffer;
940 		return SEC_E_OK;
941 	}
942 	else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_HASH_CB_DATA)
943 	{
944 		context->HashCallbackArg = pBuffer;
945 		return SEC_E_OK;
946 	}
947 
948 	WLog_ERR(TAG, "[%s]: TODO: Implement ulAttribute=%08" PRIx32, __FUNCTION__, ulAttribute);
949 	return SEC_E_UNSUPPORTED_FUNCTION;
950 }
951 
ntlm_SetContextAttributesA(PCtxtHandle phContext,ULONG ulAttribute,void * pBuffer,ULONG cbBuffer)952 static SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesA(PCtxtHandle phContext,
953                                                             ULONG ulAttribute, void* pBuffer,
954                                                             ULONG cbBuffer)
955 {
956 	return ntlm_SetContextAttributesW(phContext, ulAttribute, pBuffer, cbBuffer);
957 }
958 
ntlm_RevertSecurityContext(PCtxtHandle phContext)959 static SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(PCtxtHandle phContext)
960 {
961 	return SEC_E_OK;
962 }
963 
ntlm_EncryptMessage(PCtxtHandle phContext,ULONG fQOP,PSecBufferDesc pMessage,ULONG MessageSeqNo)964 static SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP,
965                                                      PSecBufferDesc pMessage, ULONG MessageSeqNo)
966 {
967 	ULONG index;
968 	int length;
969 	void* data;
970 	UINT32 SeqNo;
971 	UINT32 value;
972 	BYTE digest[WINPR_MD5_DIGEST_LENGTH];
973 	BYTE checksum[8];
974 	BYTE* signature;
975 	ULONG version = 1;
976 	WINPR_HMAC_CTX* hmac;
977 	NTLM_CONTEXT* context;
978 	PSecBuffer data_buffer = NULL;
979 	PSecBuffer signature_buffer = NULL;
980 	SeqNo = MessageSeqNo;
981 	context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
982 
983 	for (index = 0; index < pMessage->cBuffers; index++)
984 	{
985 		SecBuffer* cur = &pMessage->pBuffers[index];
986 
987 		if (cur->BufferType & SECBUFFER_DATA)
988 			data_buffer = cur;
989 		else if (cur->BufferType & SECBUFFER_TOKEN)
990 			signature_buffer = cur;
991 	}
992 
993 	if (!data_buffer)
994 		return SEC_E_INVALID_TOKEN;
995 
996 	if (!signature_buffer)
997 		return SEC_E_INVALID_TOKEN;
998 
999 	/* Copy original data buffer */
1000 	length = data_buffer->cbBuffer;
1001 	data = malloc(length);
1002 
1003 	if (!data)
1004 		return SEC_E_INSUFFICIENT_MEMORY;
1005 
1006 	CopyMemory(data, data_buffer->pvBuffer, length);
1007 	/* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */
1008 	hmac = winpr_HMAC_New();
1009 
1010 	if (hmac &&
1011 	    winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->SendSigningKey, WINPR_MD5_DIGEST_LENGTH))
1012 	{
1013 		Data_Write_UINT32(&value, SeqNo);
1014 		winpr_HMAC_Update(hmac, (void*)&value, 4);
1015 		winpr_HMAC_Update(hmac, (void*)data, length);
1016 		winpr_HMAC_Final(hmac, digest, WINPR_MD5_DIGEST_LENGTH);
1017 		winpr_HMAC_Free(hmac);
1018 	}
1019 	else
1020 	{
1021 		winpr_HMAC_Free(hmac);
1022 		free(data);
1023 		return SEC_E_INSUFFICIENT_MEMORY;
1024 	}
1025 
1026 	/* Encrypt message using with RC4, result overwrites original buffer */
1027 	if ((data_buffer->BufferType & SECBUFFER_READONLY) == 0)
1028 	{
1029 		if (context->confidentiality)
1030 			winpr_RC4_Update(context->SendRc4Seal, length, (BYTE*)data,
1031 			                 (BYTE*)data_buffer->pvBuffer);
1032 		else
1033 			CopyMemory(data_buffer->pvBuffer, data, length);
1034 	}
1035 
1036 #ifdef WITH_DEBUG_NTLM
1037 	WLog_DBG(TAG, "Data Buffer (length = %d)", length);
1038 	winpr_HexDump(TAG, WLOG_DEBUG, data, length);
1039 	WLog_DBG(TAG, "Encrypted Data Buffer (length = %" PRIu32 ")", data_buffer->cbBuffer);
1040 	winpr_HexDump(TAG, WLOG_DEBUG, data_buffer->pvBuffer, data_buffer->cbBuffer);
1041 #endif
1042 	free(data);
1043 	/* RC4-encrypt first 8 bytes of digest */
1044 	winpr_RC4_Update(context->SendRc4Seal, 8, digest, checksum);
1045 	if ((signature_buffer->BufferType & SECBUFFER_READONLY) == 0)
1046 	{
1047 		signature = (BYTE*)signature_buffer->pvBuffer;
1048 		/* Concatenate version, ciphertext and sequence number to build signature */
1049 		Data_Write_UINT32(signature, version);
1050 		CopyMemory(&signature[4], (void*)checksum, 8);
1051 		Data_Write_UINT32(&signature[12], SeqNo);
1052 	}
1053 	context->SendSeqNum++;
1054 #ifdef WITH_DEBUG_NTLM
1055 	WLog_DBG(TAG, "Signature (length = %" PRIu32 ")", signature_buffer->cbBuffer);
1056 	winpr_HexDump(TAG, WLOG_DEBUG, signature_buffer->pvBuffer, signature_buffer->cbBuffer);
1057 #endif
1058 	return SEC_E_OK;
1059 }
1060 
ntlm_DecryptMessage(PCtxtHandle phContext,PSecBufferDesc pMessage,ULONG MessageSeqNo,PULONG pfQOP)1061 static SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferDesc pMessage,
1062                                                      ULONG MessageSeqNo, PULONG pfQOP)
1063 {
1064 	int index;
1065 	int length;
1066 	void* data;
1067 	UINT32 SeqNo;
1068 	UINT32 value;
1069 	BYTE digest[WINPR_MD5_DIGEST_LENGTH];
1070 	BYTE checksum[8];
1071 	UINT32 version = 1;
1072 	WINPR_HMAC_CTX* hmac;
1073 	NTLM_CONTEXT* context;
1074 	BYTE expected_signature[WINPR_MD5_DIGEST_LENGTH];
1075 	PSecBuffer data_buffer = NULL;
1076 	PSecBuffer signature_buffer = NULL;
1077 	SeqNo = (UINT32)MessageSeqNo;
1078 	context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
1079 
1080 	for (index = 0; index < (int)pMessage->cBuffers; index++)
1081 	{
1082 		if (pMessage->pBuffers[index].BufferType == SECBUFFER_DATA)
1083 			data_buffer = &pMessage->pBuffers[index];
1084 		else if (pMessage->pBuffers[index].BufferType == SECBUFFER_TOKEN)
1085 			signature_buffer = &pMessage->pBuffers[index];
1086 	}
1087 
1088 	if (!data_buffer)
1089 		return SEC_E_INVALID_TOKEN;
1090 
1091 	if (!signature_buffer)
1092 		return SEC_E_INVALID_TOKEN;
1093 
1094 	/* Copy original data buffer */
1095 	length = data_buffer->cbBuffer;
1096 	data = malloc(length);
1097 
1098 	if (!data)
1099 		return SEC_E_INSUFFICIENT_MEMORY;
1100 
1101 	CopyMemory(data, data_buffer->pvBuffer, length);
1102 
1103 	/* Decrypt message using with RC4, result overwrites original buffer */
1104 
1105 	if (context->confidentiality)
1106 		winpr_RC4_Update(context->RecvRc4Seal, length, (BYTE*)data, (BYTE*)data_buffer->pvBuffer);
1107 	else
1108 		CopyMemory(data_buffer->pvBuffer, data, length);
1109 
1110 	/* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */
1111 	hmac = winpr_HMAC_New();
1112 
1113 	if (hmac &&
1114 	    winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->RecvSigningKey, WINPR_MD5_DIGEST_LENGTH))
1115 	{
1116 		Data_Write_UINT32(&value, SeqNo);
1117 		winpr_HMAC_Update(hmac, (void*)&value, 4);
1118 		winpr_HMAC_Update(hmac, (void*)data_buffer->pvBuffer, data_buffer->cbBuffer);
1119 		winpr_HMAC_Final(hmac, digest, WINPR_MD5_DIGEST_LENGTH);
1120 		winpr_HMAC_Free(hmac);
1121 	}
1122 	else
1123 	{
1124 		winpr_HMAC_Free(hmac);
1125 		free(data);
1126 		return SEC_E_INSUFFICIENT_MEMORY;
1127 	}
1128 
1129 #ifdef WITH_DEBUG_NTLM
1130 	WLog_DBG(TAG, "Encrypted Data Buffer (length = %d)", length);
1131 	winpr_HexDump(TAG, WLOG_DEBUG, data, length);
1132 	WLog_DBG(TAG, "Data Buffer (length = %" PRIu32 ")", data_buffer->cbBuffer);
1133 	winpr_HexDump(TAG, WLOG_DEBUG, data_buffer->pvBuffer, data_buffer->cbBuffer);
1134 #endif
1135 	free(data);
1136 	/* RC4-encrypt first 8 bytes of digest */
1137 	winpr_RC4_Update(context->RecvRc4Seal, 8, digest, checksum);
1138 	/* Concatenate version, ciphertext and sequence number to build signature */
1139 	Data_Write_UINT32(expected_signature, version);
1140 	CopyMemory(&expected_signature[4], (void*)checksum, 8);
1141 	Data_Write_UINT32(&expected_signature[12], SeqNo);
1142 	context->RecvSeqNum++;
1143 
1144 	if (memcmp(signature_buffer->pvBuffer, expected_signature, 16) != 0)
1145 	{
1146 		/* signature verification failed! */
1147 		WLog_ERR(TAG, "signature verification failed, something nasty is going on!");
1148 #ifdef WITH_DEBUG_NTLM
1149 		WLog_ERR(TAG, "Expected Signature:");
1150 		winpr_HexDump(TAG, WLOG_ERROR, expected_signature, 16);
1151 		WLog_ERR(TAG, "Actual Signature:");
1152 		winpr_HexDump(TAG, WLOG_ERROR, (BYTE*)signature_buffer->pvBuffer, 16);
1153 #endif
1154 		return SEC_E_MESSAGE_ALTERED;
1155 	}
1156 
1157 	return SEC_E_OK;
1158 }
1159 
ntlm_MakeSignature(PCtxtHandle phContext,ULONG fQOP,PSecBufferDesc pMessage,ULONG MessageSeqNo)1160 static SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext, ULONG fQOP,
1161                                                     PSecBufferDesc pMessage, ULONG MessageSeqNo)
1162 {
1163 	WLog_ERR(TAG, "[%s]: TODO: Implement", __FUNCTION__);
1164 	return SEC_E_UNSUPPORTED_FUNCTION;
1165 }
1166 
ntlm_VerifySignature(PCtxtHandle phContext,PSecBufferDesc pMessage,ULONG MessageSeqNo,PULONG pfQOP)1167 static SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle phContext,
1168                                                       PSecBufferDesc pMessage, ULONG MessageSeqNo,
1169                                                       PULONG pfQOP)
1170 {
1171 	WLog_ERR(TAG, "[%s]: TODO: Implement", __FUNCTION__);
1172 	return SEC_E_UNSUPPORTED_FUNCTION;
1173 }
1174 
1175 const SecurityFunctionTableA NTLM_SecurityFunctionTableA = {
1176 	1,                                /* dwVersion */
1177 	NULL,                             /* EnumerateSecurityPackages */
1178 	ntlm_QueryCredentialsAttributesA, /* QueryCredentialsAttributes */
1179 	ntlm_AcquireCredentialsHandleA,   /* AcquireCredentialsHandle */
1180 	ntlm_FreeCredentialsHandle,       /* FreeCredentialsHandle */
1181 	NULL,                             /* Reserved2 */
1182 	ntlm_InitializeSecurityContextA,  /* InitializeSecurityContext */
1183 	ntlm_AcceptSecurityContext,       /* AcceptSecurityContext */
1184 	ntlm_CompleteAuthToken,           /* CompleteAuthToken */
1185 	ntlm_DeleteSecurityContext,       /* DeleteSecurityContext */
1186 	NULL,                             /* ApplyControlToken */
1187 	ntlm_QueryContextAttributesA,     /* QueryContextAttributes */
1188 	ntlm_ImpersonateSecurityContext,  /* ImpersonateSecurityContext */
1189 	ntlm_RevertSecurityContext,       /* RevertSecurityContext */
1190 	ntlm_MakeSignature,               /* MakeSignature */
1191 	ntlm_VerifySignature,             /* VerifySignature */
1192 	NULL,                             /* FreeContextBuffer */
1193 	NULL,                             /* QuerySecurityPackageInfo */
1194 	NULL,                             /* Reserved3 */
1195 	NULL,                             /* Reserved4 */
1196 	NULL,                             /* ExportSecurityContext */
1197 	NULL,                             /* ImportSecurityContext */
1198 	NULL,                             /* AddCredentials */
1199 	NULL,                             /* Reserved8 */
1200 	NULL,                             /* QuerySecurityContextToken */
1201 	ntlm_EncryptMessage,              /* EncryptMessage */
1202 	ntlm_DecryptMessage,              /* DecryptMessage */
1203 	ntlm_SetContextAttributesA,       /* SetContextAttributes */
1204 };
1205 
1206 const SecurityFunctionTableW NTLM_SecurityFunctionTableW = {
1207 	1,                                /* dwVersion */
1208 	NULL,                             /* EnumerateSecurityPackages */
1209 	ntlm_QueryCredentialsAttributesW, /* QueryCredentialsAttributes */
1210 	ntlm_AcquireCredentialsHandleW,   /* AcquireCredentialsHandle */
1211 	ntlm_FreeCredentialsHandle,       /* FreeCredentialsHandle */
1212 	NULL,                             /* Reserved2 */
1213 	ntlm_InitializeSecurityContextW,  /* InitializeSecurityContext */
1214 	ntlm_AcceptSecurityContext,       /* AcceptSecurityContext */
1215 	ntlm_CompleteAuthToken,           /* CompleteAuthToken */
1216 	ntlm_DeleteSecurityContext,       /* DeleteSecurityContext */
1217 	NULL,                             /* ApplyControlToken */
1218 	ntlm_QueryContextAttributesW,     /* QueryContextAttributes */
1219 	ntlm_ImpersonateSecurityContext,  /* ImpersonateSecurityContext */
1220 	ntlm_RevertSecurityContext,       /* RevertSecurityContext */
1221 	ntlm_MakeSignature,               /* MakeSignature */
1222 	ntlm_VerifySignature,             /* VerifySignature */
1223 	NULL,                             /* FreeContextBuffer */
1224 	NULL,                             /* QuerySecurityPackageInfo */
1225 	NULL,                             /* Reserved3 */
1226 	NULL,                             /* Reserved4 */
1227 	NULL,                             /* ExportSecurityContext */
1228 	NULL,                             /* ImportSecurityContext */
1229 	NULL,                             /* AddCredentials */
1230 	NULL,                             /* Reserved8 */
1231 	NULL,                             /* QuerySecurityContextToken */
1232 	ntlm_EncryptMessage,              /* EncryptMessage */
1233 	ntlm_DecryptMessage,              /* DecryptMessage */
1234 	ntlm_SetContextAttributesA,       /* SetContextAttributes */
1235 };
1236 
1237 const SecPkgInfoA NTLM_SecPkgInfoA = {
1238 	0x00082B37,             /* fCapabilities */
1239 	1,                      /* wVersion */
1240 	0x000A,                 /* wRPCID */
1241 	0x00000B48,             /* cbMaxToken */
1242 	"NTLM",                 /* Name */
1243 	"NTLM Security Package" /* Comment */
1244 };
1245 
1246 static WCHAR NTLM_SecPkgInfoW_Name[] = { 'N', 'T', 'L', 'M', '\0' };
1247 
1248 static WCHAR NTLM_SecPkgInfoW_Comment[] = {
1249 	'N', 'T', 'L', 'M', ' ', 'S', 'e', 'c', 'u', 'r', 'i',
1250 	't', 'y', ' ', 'P', 'a', 'c', 'k', 'a', 'g', 'e', '\0'
1251 };
1252 
1253 const SecPkgInfoW NTLM_SecPkgInfoW = {
1254 	0x00082B37,              /* fCapabilities */
1255 	1,                       /* wVersion */
1256 	0x000A,                  /* wRPCID */
1257 	0x00000B48,              /* cbMaxToken */
1258 	NTLM_SecPkgInfoW_Name,   /* Name */
1259 	NTLM_SecPkgInfoW_Comment /* Comment */
1260 };
1261