FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
ntlm_av_pairs.c
1
20#include <winpr/config.h>
21
22#include <winpr/assert.h>
23
24#include "ntlm.h"
25#include "../sspi.h"
26
27#include <winpr/crt.h>
28#include <winpr/print.h>
29#include <winpr/sysinfo.h>
30#include <winpr/tchar.h>
31#include <winpr/crypto.h>
32
33#include "ntlm_compute.h"
34
35#include "ntlm_av_pairs.h"
36
37#include "../../log.h"
38#define TAG WINPR_TAG("sspi.NTLM")
39
40static BOOL ntlm_av_pair_get_next_offset(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pOffset);
41
42static BOOL ntlm_av_pair_check_data(const NTLM_AV_PAIR* pAvPair, size_t cbAvPair, size_t size)
43{
44 size_t offset = 0;
45 if (!pAvPair || cbAvPair < sizeof(NTLM_AV_PAIR) + size)
46 return FALSE;
47 if (!ntlm_av_pair_get_next_offset(pAvPair, cbAvPair, &offset))
48 return FALSE;
49 return cbAvPair >= offset;
50}
51
52static const char* get_av_pair_string(UINT16 pair)
53{
54 switch (pair)
55 {
56 case MsvAvEOL:
57 return "MsvAvEOL";
58 case MsvAvNbComputerName:
59 return "MsvAvNbComputerName";
60 case MsvAvNbDomainName:
61 return "MsvAvNbDomainName";
62 case MsvAvDnsComputerName:
63 return "MsvAvDnsComputerName";
64 case MsvAvDnsDomainName:
65 return "MsvAvDnsDomainName";
66 case MsvAvDnsTreeName:
67 return "MsvAvDnsTreeName";
68 case MsvAvFlags:
69 return "MsvAvFlags";
70 case MsvAvTimestamp:
71 return "MsvAvTimestamp";
72 case MsvAvSingleHost:
73 return "MsvAvSingleHost";
74 case MsvAvTargetName:
75 return "MsvAvTargetName";
76 case MsvAvChannelBindings:
77 return "MsvAvChannelBindings";
78 default:
79 return "UNKNOWN";
80 }
81}
82
83static BOOL ntlm_av_pair_check(const NTLM_AV_PAIR* pAvPair, size_t cbAvPair);
84static NTLM_AV_PAIR* ntlm_av_pair_next(NTLM_AV_PAIR* pAvPairList, size_t* pcbAvPairList);
85
86static INLINE void ntlm_av_pair_set_id(NTLM_AV_PAIR* pAvPair, UINT16 id)
87{
88 WINPR_ASSERT(pAvPair);
89 winpr_Data_Write_UINT16(&pAvPair->AvId, id);
90}
91
92static INLINE void ntlm_av_pair_set_len(NTLM_AV_PAIR* pAvPair, UINT16 len)
93{
94 WINPR_ASSERT(pAvPair);
95 winpr_Data_Write_UINT16(&pAvPair->AvLen, len);
96}
97
98static BOOL ntlm_av_pair_list_init(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
99{
100 NTLM_AV_PAIR* pAvPair = pAvPairList;
101
102 if (!pAvPair || (cbAvPairList < sizeof(NTLM_AV_PAIR)))
103 return FALSE;
104
105 ntlm_av_pair_set_id(pAvPair, MsvAvEOL);
106 ntlm_av_pair_set_len(pAvPair, 0);
107 return TRUE;
108}
109
110static INLINE BOOL ntlm_av_pair_get_id(const NTLM_AV_PAIR* pAvPair, size_t size, UINT16* pair)
111{
112 if (!pAvPair || !pair)
113 return FALSE;
114
115 if (size < sizeof(NTLM_AV_PAIR))
116 return FALSE;
117
118 const UINT16 AvId = winpr_Data_Get_UINT16(&pAvPair->AvId);
119
120 *pair = AvId;
121 return TRUE;
122}
123
124ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
125{
126 size_t cbAvPair = 0;
127 NTLM_AV_PAIR* pAvPair = NULL;
128
129 pAvPair = ntlm_av_pair_get(pAvPairList, cbAvPairList, MsvAvEOL, &cbAvPair);
130 if (!pAvPair)
131 return 0;
132
133 if (pAvPair < pAvPairList)
134 return 0;
135
136 const size_t size = WINPR_ASSERTING_INT_CAST(size_t, ((PBYTE)pAvPair - (PBYTE)pAvPairList)) +
137 sizeof(NTLM_AV_PAIR);
138 WINPR_ASSERT(size <= UINT32_MAX);
139 WINPR_ASSERT(size >= 0);
140 return (ULONG)size;
141}
142
143static INLINE BOOL ntlm_av_pair_get_len(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pAvLen)
144{
145 if (!pAvPair)
146 return FALSE;
147
148 if (size < sizeof(NTLM_AV_PAIR))
149 return FALSE;
150
151 const UINT16 AvLen = winpr_Data_Get_UINT16(&pAvPair->AvLen);
152
153 *pAvLen = AvLen;
154 return TRUE;
155}
156
157#ifdef WITH_DEBUG_NTLM
158void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
159{
160 UINT16 pair = 0;
161 size_t cbAvPair = cbAvPairList;
162 NTLM_AV_PAIR* pAvPair = pAvPairList;
163
164 if (!ntlm_av_pair_check(pAvPair, cbAvPair))
165 return;
166
167 WLog_VRB(TAG, "AV_PAIRs =");
168
169 while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair) && (pair != MsvAvEOL))
170 {
171 size_t cbLen = 0;
172 ntlm_av_pair_get_len(pAvPair, cbAvPair, &cbLen);
173
174 WLog_VRB(TAG, "\t%s AvId: %" PRIu16 " AvLen: %" PRIu16 "", get_av_pair_string(pair), pair);
175 winpr_HexDump(TAG, WLOG_TRACE, ntlm_av_pair_get_value_pointer(pAvPair), cbLen);
176
177 pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
178 }
179}
180#endif
181
182static ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength)
183{
184 /* size of headers + value lengths + terminating MsvAvEOL AV_PAIR */
185 return ((AvPairsCount + 1) * 4) + AvPairsValueLength;
186}
187
188PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair)
189{
190 WINPR_ASSERT(pAvPair);
191 return (PBYTE)pAvPair + sizeof(NTLM_AV_PAIR);
192}
193
194static BOOL ntlm_av_pair_get_next_offset(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pOffset)
195{
196 size_t avLen = 0;
197 if (!pOffset)
198 return FALSE;
199
200 if (!ntlm_av_pair_get_len(pAvPair, size, &avLen))
201 return FALSE;
202 *pOffset = avLen + sizeof(NTLM_AV_PAIR);
203 return TRUE;
204}
205
206static BOOL ntlm_av_pair_check(const NTLM_AV_PAIR* pAvPair, size_t cbAvPair)
207{
208 return ntlm_av_pair_check_data(pAvPair, cbAvPair, 0);
209}
210
211static NTLM_AV_PAIR* ntlm_av_pair_next(NTLM_AV_PAIR* pAvPair, size_t* pcbAvPair)
212{
213 size_t offset = 0;
214
215 if (!pcbAvPair)
216 return NULL;
217 if (!ntlm_av_pair_check(pAvPair, *pcbAvPair))
218 return NULL;
219
220 if (!ntlm_av_pair_get_next_offset(pAvPair, *pcbAvPair, &offset))
221 return NULL;
222
223 *pcbAvPair -= offset;
224 return (NTLM_AV_PAIR*)((PBYTE)pAvPair + offset);
225}
226
227NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTLM_AV_ID AvId,
228 size_t* pcbAvPairListRemaining)
229{
230 UINT16 id = 0;
231 size_t cbAvPair = cbAvPairList;
232 NTLM_AV_PAIR* pAvPair = pAvPairList;
233
234 if (!ntlm_av_pair_check(pAvPair, cbAvPair))
235 pAvPair = NULL;
236
237 while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &id))
238 {
239 if (id == AvId)
240 break;
241 if (id == MsvAvEOL)
242 {
243 pAvPair = NULL;
244 break;
245 }
246
247 pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
248 }
249
250 if (!pAvPair)
251 cbAvPair = 0;
252 if (pcbAvPairListRemaining)
253 *pcbAvPairListRemaining = cbAvPair;
254
255 return pAvPair;
256}
257
258static BOOL ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTLM_AV_ID AvId,
259 PBYTE Value, UINT16 AvLen)
260{
261 size_t cbAvPair = 0;
262 NTLM_AV_PAIR* pAvPair = NULL;
263
264 pAvPair = ntlm_av_pair_get(pAvPairList, cbAvPairList, MsvAvEOL, &cbAvPair);
265
266 /* size of header + value length + terminating MsvAvEOL AV_PAIR */
267 if (!pAvPair || cbAvPair < 2 * sizeof(NTLM_AV_PAIR) + AvLen)
268 return FALSE;
269
270 ntlm_av_pair_set_id(pAvPair, (UINT16)AvId);
271 ntlm_av_pair_set_len(pAvPair, AvLen);
272 if (AvLen)
273 {
274 WINPR_ASSERT(Value != NULL);
275 CopyMemory(ntlm_av_pair_get_value_pointer(pAvPair), Value, AvLen);
276 }
277
278 pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
279 return ntlm_av_pair_list_init(pAvPair, cbAvPair);
280}
281
282static BOOL ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList,
283 NTLM_AV_PAIR* pAvPair, size_t cbAvPair)
284{
285 UINT16 pair = 0;
286 size_t avLen = 0;
287
288 if (!ntlm_av_pair_check(pAvPair, cbAvPair))
289 return FALSE;
290
291 if (!ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair))
292 return FALSE;
293
294 if (!ntlm_av_pair_get_len(pAvPair, cbAvPair, &avLen))
295 return FALSE;
296
297 WINPR_ASSERT(avLen <= UINT16_MAX);
298 return ntlm_av_pair_add(pAvPairList, cbAvPairList, pair,
299 ntlm_av_pair_get_value_pointer(pAvPair), (UINT16)avLen);
300}
301
302static char* get_name(COMPUTER_NAME_FORMAT type)
303{
304 DWORD nSize = 0;
305
306 if (GetComputerNameExA(type, NULL, &nSize))
307 return NULL;
308
309 if (GetLastError() != ERROR_MORE_DATA)
310 return NULL;
311
312 char* computerName = calloc(1, nSize);
313
314 if (!computerName)
315 return NULL;
316
317 if (!GetComputerNameExA(type, computerName, &nSize))
318 {
319 free(computerName);
320 return NULL;
321 }
322
323 return computerName;
324}
325
326static int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type)
327{
328 int status = -1;
329
330 WINPR_ASSERT(pName);
331
332 char* name = get_name(ComputerNameNetBIOS);
333 if (!name)
334 return -1;
335
336 CharUpperA(name);
337
338 size_t len = 0;
339 pName->Buffer = ConvertUtf8ToWCharAlloc(name, &len);
340 free(name);
341
342 if (!pName->Buffer || (len == 0) || (len > UINT16_MAX / sizeof(WCHAR)))
343 {
344 free(pName->Buffer);
345 pName->Buffer = NULL;
346 return status;
347 }
348
349 pName->Length = (USHORT)((len) * sizeof(WCHAR));
350 pName->MaximumLength = pName->Length;
351 return 1;
352}
353
354static void ntlm_free_unicode_string(PUNICODE_STRING string)
355{
356 if (string)
357 {
358 if (string->Length > 0)
359 {
360 free(string->Buffer);
361 string->Buffer = NULL;
362 string->Length = 0;
363 string->MaximumLength = 0;
364 }
365 }
366}
367
386/*
387typedef struct gss_channel_bindings_struct {
388 OM_uint32 initiator_addrtype;
389 gss_buffer_desc initiator_address;
390 OM_uint32 acceptor_addrtype;
391 gss_buffer_desc acceptor_address;
392 gss_buffer_desc application_data;
393} *gss_channel_bindings_t;
394 */
395
396static BOOL ntlm_md5_update_uint32_be(WINPR_DIGEST_CTX* md5, UINT32 num)
397{
398 BYTE be32[4];
399 be32[0] = (num >> 0) & 0xFF;
400 be32[1] = (num >> 8) & 0xFF;
401 be32[2] = (num >> 16) & 0xFF;
402 be32[3] = (num >> 24) & 0xFF;
403 return winpr_Digest_Update(md5, be32, 4);
404}
405
406static void ntlm_compute_channel_bindings(NTLM_CONTEXT* context)
407{
408 WINPR_DIGEST_CTX* md5 = NULL;
409 BYTE* ChannelBindingToken = NULL;
410 UINT32 ChannelBindingTokenLength = 0;
411 SEC_CHANNEL_BINDINGS* ChannelBindings = NULL;
412
413 WINPR_ASSERT(context);
414
415 ZeroMemory(context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH);
416 ChannelBindings = context->Bindings.Bindings;
417
418 if (!ChannelBindings)
419 return;
420
421 if (!(md5 = winpr_Digest_New()))
422 return;
423
424 if (!winpr_Digest_Init(md5, WINPR_MD_MD5))
425 goto out;
426
427 ChannelBindingTokenLength = context->Bindings.BindingsLength - sizeof(SEC_CHANNEL_BINDINGS);
428 ChannelBindingToken = &((BYTE*)ChannelBindings)[ChannelBindings->dwApplicationDataOffset];
429
430 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->dwInitiatorAddrType))
431 goto out;
432
433 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbInitiatorLength))
434 goto out;
435
436 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->dwAcceptorAddrType))
437 goto out;
438
439 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbAcceptorLength))
440 goto out;
441
442 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbApplicationDataLength))
443 goto out;
444
445 if (!winpr_Digest_Update(md5, (void*)ChannelBindingToken, ChannelBindingTokenLength))
446 goto out;
447
448 if (!winpr_Digest_Final(md5, context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH))
449 goto out;
450
451out:
452 winpr_Digest_Free(md5);
453}
454
455static void ntlm_compute_single_host_data(NTLM_CONTEXT* context)
456{
457 WINPR_ASSERT(context);
466 winpr_Data_Write_UINT32(&context->SingleHostData.Size, 48);
467 winpr_Data_Write_UINT32(&context->SingleHostData.Z4, 0);
468 winpr_Data_Write_UINT32(&context->SingleHostData.DataPresent, 1);
469 winpr_Data_Write_UINT32(&context->SingleHostData.CustomData, SECURITY_MANDATORY_MEDIUM_RID);
470 FillMemory(context->SingleHostData.MachineID, 32, 0xAA);
471}
472
473BOOL ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
474{
475 BOOL rc = FALSE;
476 ULONG length = 0;
477 ULONG AvPairsCount = 0;
478 ULONG AvPairsLength = 0;
479 NTLM_AV_PAIR* pAvPairList = NULL;
480 size_t cbAvPairList = 0;
481 UNICODE_STRING NbDomainName = { 0 };
482 UNICODE_STRING NbComputerName = { 0 };
483 UNICODE_STRING DnsDomainName = { 0 };
484 UNICODE_STRING DnsComputerName = { 0 };
485
486 WINPR_ASSERT(context);
487
488 if (ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS) < 0)
489 goto fail;
490
491 NbComputerName.Buffer = NULL;
492
493 if (ntlm_get_target_computer_name(&NbComputerName, ComputerNameNetBIOS) < 0)
494 goto fail;
495
496 DnsDomainName.Buffer = NULL;
497
498 if (ntlm_get_target_computer_name(&DnsDomainName, ComputerNameDnsDomain) < 0)
499 goto fail;
500
501 DnsComputerName.Buffer = NULL;
502
503 if (ntlm_get_target_computer_name(&DnsComputerName, ComputerNameDnsHostname) < 0)
504 goto fail;
505
506 AvPairsCount = 5;
507 AvPairsLength = NbDomainName.Length + NbComputerName.Length + DnsDomainName.Length +
508 DnsComputerName.Length + 8;
509 length = ntlm_av_pair_list_size(AvPairsCount, AvPairsLength);
510
511 if (!sspi_SecBufferAlloc(&context->ChallengeTargetInfo, length))
512 goto fail;
513
514 pAvPairList = (NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer;
515 cbAvPairList = context->ChallengeTargetInfo.cbBuffer;
516
517 if (!ntlm_av_pair_list_init(pAvPairList, cbAvPairList))
518 goto fail;
519
520 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvNbDomainName, (PBYTE)NbDomainName.Buffer,
521 NbDomainName.Length))
522 goto fail;
523
524 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvNbComputerName,
525 (PBYTE)NbComputerName.Buffer, NbComputerName.Length))
526 goto fail;
527
528 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvDnsDomainName,
529 (PBYTE)DnsDomainName.Buffer, DnsDomainName.Length))
530 goto fail;
531
532 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvDnsComputerName,
533 (PBYTE)DnsComputerName.Buffer, DnsComputerName.Length))
534 goto fail;
535
536 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvTimestamp, context->Timestamp,
537 sizeof(context->Timestamp)))
538 goto fail;
539
540 rc = TRUE;
541fail:
542 ntlm_free_unicode_string(&NbDomainName);
543 ntlm_free_unicode_string(&NbComputerName);
544 ntlm_free_unicode_string(&DnsDomainName);
545 ntlm_free_unicode_string(&DnsComputerName);
546 return rc;
547}
548
549BOOL ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
550{
551 ULONG size = 0;
552 ULONG AvPairsCount = 0;
553 ULONG AvPairsValueLength = 0;
554 NTLM_AV_PAIR* AvTimestamp = NULL;
555 NTLM_AV_PAIR* AvNbDomainName = NULL;
556 NTLM_AV_PAIR* AvNbComputerName = NULL;
557 NTLM_AV_PAIR* AvDnsDomainName = NULL;
558 NTLM_AV_PAIR* AvDnsComputerName = NULL;
559 NTLM_AV_PAIR* AvDnsTreeName = NULL;
560 NTLM_AV_PAIR* ChallengeTargetInfo = NULL;
561 NTLM_AV_PAIR* AuthenticateTargetInfo = NULL;
562 size_t cbAvTimestamp = 0;
563 size_t cbAvNbDomainName = 0;
564 size_t cbAvNbComputerName = 0;
565 size_t cbAvDnsDomainName = 0;
566 size_t cbAvDnsComputerName = 0;
567 size_t cbAvDnsTreeName = 0;
568 size_t cbChallengeTargetInfo = 0;
569 size_t cbAuthenticateTargetInfo = 0;
570
571 WINPR_ASSERT(context);
572
573 AvPairsCount = 1;
574 AvPairsValueLength = 0;
575 ChallengeTargetInfo = (NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer;
576 cbChallengeTargetInfo = context->ChallengeTargetInfo.cbBuffer;
577 AvNbDomainName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvNbDomainName,
578 &cbAvNbDomainName);
579 AvNbComputerName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
580 MsvAvNbComputerName, &cbAvNbComputerName);
581 AvDnsDomainName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
582 MsvAvDnsDomainName, &cbAvDnsDomainName);
583 AvDnsComputerName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
584 MsvAvDnsComputerName, &cbAvDnsComputerName);
585 AvDnsTreeName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvDnsTreeName,
586 &cbAvDnsTreeName);
587 AvTimestamp = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvTimestamp,
588 &cbAvTimestamp);
589
590 if (AvNbDomainName)
591 {
592 size_t avLen = 0;
593 if (!ntlm_av_pair_get_len(AvNbDomainName, cbAvNbDomainName, &avLen))
594 goto fail;
595 AvPairsCount++; /* MsvAvNbDomainName */
596 AvPairsValueLength += avLen;
597 }
598
599 if (AvNbComputerName)
600 {
601 size_t avLen = 0;
602 if (!ntlm_av_pair_get_len(AvNbComputerName, cbAvNbComputerName, &avLen))
603 goto fail;
604 AvPairsCount++; /* MsvAvNbComputerName */
605 AvPairsValueLength += avLen;
606 }
607
608 if (AvDnsDomainName)
609 {
610 size_t avLen = 0;
611 if (!ntlm_av_pair_get_len(AvDnsDomainName, cbAvDnsDomainName, &avLen))
612 goto fail;
613 AvPairsCount++; /* MsvAvDnsDomainName */
614 AvPairsValueLength += avLen;
615 }
616
617 if (AvDnsComputerName)
618 {
619 size_t avLen = 0;
620 if (!ntlm_av_pair_get_len(AvDnsComputerName, cbAvDnsComputerName, &avLen))
621 goto fail;
622 AvPairsCount++; /* MsvAvDnsComputerName */
623 AvPairsValueLength += avLen;
624 }
625
626 if (AvDnsTreeName)
627 {
628 size_t avLen = 0;
629 if (!ntlm_av_pair_get_len(AvDnsTreeName, cbAvDnsTreeName, &avLen))
630 goto fail;
631 AvPairsCount++; /* MsvAvDnsTreeName */
632 AvPairsValueLength += avLen;
633 }
634
635 AvPairsCount++; /* MsvAvTimestamp */
636 AvPairsValueLength += 8;
637
638 if (context->UseMIC)
639 {
640 AvPairsCount++; /* MsvAvFlags */
641 AvPairsValueLength += 4;
642 }
643
644 if (context->SendSingleHostData)
645 {
646 AvPairsCount++; /* MsvAvSingleHost */
647 ntlm_compute_single_host_data(context);
648 AvPairsValueLength += context->SingleHostData.Size;
649 }
650
656 if (!context->SuppressExtendedProtection)
657 {
662 AvPairsCount++; /* MsvAvChannelBindings */
663 AvPairsValueLength += 16;
664 ntlm_compute_channel_bindings(context);
665
666 if (context->ServicePrincipalName.Length > 0)
667 {
668 AvPairsCount++; /* MsvAvTargetName */
669 AvPairsValueLength += context->ServicePrincipalName.Length;
670 }
671 }
672
673 size = ntlm_av_pair_list_size(AvPairsCount, AvPairsValueLength);
674
675 if (context->NTLMv2)
676 size += 8; /* unknown 8-byte padding */
677
678 if (!sspi_SecBufferAlloc(&context->AuthenticateTargetInfo, size))
679 goto fail;
680
681 AuthenticateTargetInfo = (NTLM_AV_PAIR*)context->AuthenticateTargetInfo.pvBuffer;
682 cbAuthenticateTargetInfo = context->AuthenticateTargetInfo.cbBuffer;
683
684 if (!ntlm_av_pair_list_init(AuthenticateTargetInfo, cbAuthenticateTargetInfo))
685 goto fail;
686
687 if (AvNbDomainName)
688 {
689 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvNbDomainName,
690 cbAvNbDomainName))
691 goto fail;
692 }
693
694 if (AvNbComputerName)
695 {
696 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
697 AvNbComputerName, cbAvNbComputerName))
698 goto fail;
699 }
700
701 if (AvDnsDomainName)
702 {
703 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
704 AvDnsDomainName, cbAvDnsDomainName))
705 goto fail;
706 }
707
708 if (AvDnsComputerName)
709 {
710 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
711 AvDnsComputerName, cbAvDnsComputerName))
712 goto fail;
713 }
714
715 if (AvDnsTreeName)
716 {
717 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvDnsTreeName,
718 cbAvDnsTreeName))
719 goto fail;
720 }
721
722 if (AvTimestamp)
723 {
724 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvTimestamp,
725 cbAvTimestamp))
726 goto fail;
727 }
728
729 if (context->UseMIC)
730 {
731 UINT32 flags = 0;
732 winpr_Data_Write_UINT32(&flags, MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK);
733
734 if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvFlags,
735 (PBYTE)&flags, 4))
736 goto fail;
737 }
738
739 if (context->SendSingleHostData)
740 {
741 WINPR_ASSERT(context->SingleHostData.Size <= UINT16_MAX);
742 if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvSingleHost,
743 (PBYTE)&context->SingleHostData,
744 (UINT16)context->SingleHostData.Size))
745 goto fail;
746 }
747
748 if (!context->SuppressExtendedProtection)
749 {
750 if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
751 MsvAvChannelBindings, context->ChannelBindingsHash, 16))
752 goto fail;
753
754 if (context->ServicePrincipalName.Length > 0)
755 {
756 if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvTargetName,
757 (PBYTE)context->ServicePrincipalName.Buffer,
758 context->ServicePrincipalName.Length))
759 goto fail;
760 }
761 }
762
763 if (context->NTLMv2)
764 {
765 NTLM_AV_PAIR* AvEOL = NULL;
766 AvEOL = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvEOL, NULL);
767
768 if (!AvEOL)
769 goto fail;
770
771 ZeroMemory(AvEOL, sizeof(NTLM_AV_PAIR));
772 }
773
774 return TRUE;
775fail:
776 sspi_SecBufferFree(&context->AuthenticateTargetInfo);
777 return FALSE;
778}