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