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