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, cbAvPair), 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, size_t cbAvPair)
196{
197 WINPR_ASSERT(pAvPair);
198 if (cbAvPair < sizeof(NTLM_AV_PAIR))
199 return nullptr;
200 return (PBYTE)pAvPair + sizeof(NTLM_AV_PAIR);
201}
202
203static BOOL ntlm_av_pair_get_next_offset(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pOffset)
204{
205 size_t avLen = 0;
206 if (!pOffset)
207 return FALSE;
208
209 if (!ntlm_av_pair_get_len(pAvPair, size, &avLen))
210 return FALSE;
211 *pOffset = avLen + sizeof(NTLM_AV_PAIR);
212 return TRUE;
213}
214
215static BOOL ntlm_av_pair_check(const NTLM_AV_PAIR* pAvPair, size_t cbAvPair)
216{
217 return ntlm_av_pair_check_data(pAvPair, cbAvPair, 0);
218}
219
220static NTLM_AV_PAIR* ntlm_av_pair_next(NTLM_AV_PAIR* pAvPair, size_t* pcbAvPair)
221{
222 size_t offset = 0;
223
224 if (!pcbAvPair)
225 return nullptr;
226 if (!ntlm_av_pair_check(pAvPair, *pcbAvPair))
227 return nullptr;
228
229 if (!ntlm_av_pair_get_next_offset(pAvPair, *pcbAvPair, &offset))
230 return nullptr;
231
232 *pcbAvPair -= offset;
233 NTLM_AV_PAIR* next = (NTLM_AV_PAIR*)((PBYTE)pAvPair + offset);
234 if (!ntlm_av_pair_check(next, *pcbAvPair))
235 return nullptr;
236 return next;
237}
238
239NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTLM_AV_ID AvId,
240 size_t* pcbAvPairListRemaining)
241{
242 UINT16 id = 0;
243 size_t cbAvPair = cbAvPairList;
244 NTLM_AV_PAIR* pAvPair = pAvPairList;
245
246 if (!ntlm_av_pair_check(pAvPair, cbAvPair))
247 pAvPair = nullptr;
248
249 while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &id))
250 {
251 if (id == AvId)
252 break;
253 if (id == MsvAvEOL)
254 {
255 pAvPair = nullptr;
256 break;
257 }
258
259 pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
260 }
261
262 if (!pAvPair)
263 cbAvPair = 0;
264 if (pcbAvPairListRemaining)
265 *pcbAvPairListRemaining = cbAvPair;
266
267 return pAvPair;
268}
269
270static BOOL ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTLM_AV_ID AvId,
271 PBYTE Value, UINT16 AvLen)
272{
273 size_t cbAvPair = 0;
274 NTLM_AV_PAIR* pAvPair = nullptr;
275
276 pAvPair = ntlm_av_pair_get(pAvPairList, cbAvPairList, MsvAvEOL, &cbAvPair);
277
278 /* size of header + value length + terminating MsvAvEOL AV_PAIR */
279 if (!pAvPair || cbAvPair < 2 * sizeof(NTLM_AV_PAIR) + AvLen)
280 return FALSE;
281
282 ntlm_av_pair_set_id(pAvPair, (UINT16)AvId);
283 ntlm_av_pair_set_len(pAvPair, AvLen);
284 if (AvLen)
285 {
286 WINPR_ASSERT(Value != nullptr);
287 CopyMemory(ntlm_av_pair_get_value_pointer(pAvPair, cbAvPair), Value, AvLen);
288 }
289
290 pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
291 return ntlm_av_pair_list_init(pAvPair, cbAvPair);
292}
293
294static BOOL ntlm_av_pair_valid(UINT16 pair)
295{
296 switch (pair)
297 {
298 case MsvAvEOL:
299 case MsvAvNbComputerName:
300 case MsvAvNbDomainName:
301 case MsvAvDnsComputerName:
302 case MsvAvDnsDomainName:
303 case MsvAvDnsTreeName:
304 case MsvAvFlags:
305 case MsvAvTimestamp:
306 case MsvAvSingleHost:
307 case MsvAvTargetName:
308 case MsvAvChannelBindings:
309 return TRUE;
310 default:
311 return FALSE;
312 }
313}
314
315static BOOL ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList,
316 NTLM_AV_PAIR* pAvPair, size_t cbAvPair)
317{
318 UINT16 pair = 0;
319 size_t avLen = 0;
320
321 if (!ntlm_av_pair_check(pAvPair, cbAvPair))
322 return FALSE;
323
324 if (!ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair))
325 return FALSE;
326
327 if (!ntlm_av_pair_get_len(pAvPair, cbAvPair, &avLen))
328 return FALSE;
329
330 if (!ntlm_av_pair_valid(pair))
331 return FALSE;
332
333 WINPR_ASSERT(avLen <= UINT16_MAX);
334 return ntlm_av_pair_add(pAvPairList, cbAvPairList, WINPR_ASSERTING_INT_CAST(NTLM_AV_ID, pair),
335 ntlm_av_pair_get_value_pointer(pAvPair, cbAvPair), (UINT16)avLen);
336}
337
338static int ntlm_get_target_computer_name(PUNICODE_STRING pName,
339 WINPR_ATTR_UNUSED COMPUTER_NAME_FORMAT type)
340{
341 int status = -1;
342
343 WINPR_ASSERT(pName);
344
345 char* name = get_computer_name(ComputerNameNetBIOS, nullptr);
346 if (!name)
347 return -1;
348
349 CharUpperA(name);
350
351 size_t len = 0;
352 pName->Buffer = ConvertUtf8ToWCharAlloc(name, &len);
353 free(name);
354
355 if (!pName->Buffer || (len == 0) || (len > UINT16_MAX / sizeof(WCHAR)))
356 {
357 free(pName->Buffer);
358 pName->Buffer = nullptr;
359 return status;
360 }
361
362 pName->Length = (USHORT)((len) * sizeof(WCHAR));
363 pName->MaximumLength = pName->Length;
364 return 1;
365}
366
367static void ntlm_free_unicode_string(PUNICODE_STRING string)
368{
369 if (string)
370 {
371 if (string->Length > 0)
372 {
373 free(string->Buffer);
374 string->Buffer = nullptr;
375 string->Length = 0;
376 string->MaximumLength = 0;
377 }
378 }
379}
380
399/*
400typedef struct gss_channel_bindings_struct {
401 OM_uint32 initiator_addrtype;
402 gss_buffer_desc initiator_address;
403 OM_uint32 acceptor_addrtype;
404 gss_buffer_desc acceptor_address;
405 gss_buffer_desc application_data;
406} *gss_channel_bindings_t;
407 */
408
409static BOOL ntlm_md5_update_uint32_be(WINPR_DIGEST_CTX* md5, UINT32 num)
410{
411 BYTE be32[4];
412 be32[0] = (num >> 0) & 0xFF;
413 be32[1] = (num >> 8) & 0xFF;
414 be32[2] = (num >> 16) & 0xFF;
415 be32[3] = (num >> 24) & 0xFF;
416 return winpr_Digest_Update(md5, be32, 4);
417}
418
419static void ntlm_compute_channel_bindings(NTLM_CONTEXT* context)
420{
421 WINPR_DIGEST_CTX* md5 = nullptr;
422 BYTE* ChannelBindingToken = nullptr;
423 UINT32 ChannelBindingTokenLength = 0;
424 SEC_CHANNEL_BINDINGS* ChannelBindings = nullptr;
425
426 WINPR_ASSERT(context);
427
428 ZeroMemory(context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH);
429 ChannelBindings = context->Bindings.Bindings;
430
431 if (!ChannelBindings)
432 return;
433
434 if (!(md5 = winpr_Digest_New()))
435 return;
436
437 if (!winpr_Digest_Init(md5, WINPR_MD_MD5))
438 goto out;
439
440 ChannelBindingTokenLength = context->Bindings.BindingsLength - sizeof(SEC_CHANNEL_BINDINGS);
441 ChannelBindingToken = &((BYTE*)ChannelBindings)[ChannelBindings->dwApplicationDataOffset];
442
443 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->dwInitiatorAddrType))
444 goto out;
445
446 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbInitiatorLength))
447 goto out;
448
449 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->dwAcceptorAddrType))
450 goto out;
451
452 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbAcceptorLength))
453 goto out;
454
455 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbApplicationDataLength))
456 goto out;
457
458 if (!winpr_Digest_Update(md5, (void*)ChannelBindingToken, ChannelBindingTokenLength))
459 goto out;
460
461 if (!winpr_Digest_Final(md5, context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH))
462 goto out;
463
464out:
465 winpr_Digest_Free(md5);
466}
467
468static void ntlm_compute_single_host_data(NTLM_CONTEXT* context)
469{
470 WINPR_ASSERT(context);
479 winpr_Data_Write_UINT32(&context->SingleHostData.Size, 48);
480 winpr_Data_Write_UINT32(&context->SingleHostData.Z4, 0);
481 winpr_Data_Write_UINT32(&context->SingleHostData.DataPresent, 1);
482 winpr_Data_Write_UINT32(&context->SingleHostData.CustomData, SECURITY_MANDATORY_MEDIUM_RID);
483 FillMemory(context->SingleHostData.MachineID, 32, 0xAA);
484}
485
486BOOL ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
487{
488 BOOL rc = FALSE;
489 ULONG AvPairsCount = 0;
490 ULONG AvPairsLength = 0;
491 NTLM_AV_PAIR* pAvPairList = nullptr;
492 size_t cbAvPairList = 0;
493 UNICODE_STRING NbDomainName = WINPR_C_ARRAY_INIT;
494 UNICODE_STRING NbComputerName = WINPR_C_ARRAY_INIT;
495 UNICODE_STRING DnsDomainName = WINPR_C_ARRAY_INIT;
496 UNICODE_STRING DnsComputerName = WINPR_C_ARRAY_INIT;
497
498 WINPR_ASSERT(context);
499
500 if (ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS) < 0)
501 goto fail;
502
503 NbComputerName.Buffer = nullptr;
504
505 if (ntlm_get_target_computer_name(&NbComputerName, ComputerNameNetBIOS) < 0)
506 goto fail;
507
508 DnsDomainName.Buffer = nullptr;
509
510 if (ntlm_get_target_computer_name(&DnsDomainName, ComputerNameDnsDomain) < 0)
511 goto fail;
512
513 DnsComputerName.Buffer = nullptr;
514
515 if (ntlm_get_target_computer_name(&DnsComputerName, ComputerNameDnsHostname) < 0)
516 goto fail;
517
518 AvPairsCount = 5;
519 AvPairsLength = NbDomainName.Length + NbComputerName.Length + DnsDomainName.Length +
520 DnsComputerName.Length + 8;
521 {
522 const size_t length = ntlm_av_pair_list_size(AvPairsCount, AvPairsLength);
523 if (!sspi_SecBufferAlloc(&context->ChallengeTargetInfo,
524 WINPR_ASSERTING_INT_CAST(uint32_t, length)))
525 goto fail;
526 }
527
528 pAvPairList = (NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer;
529 cbAvPairList = context->ChallengeTargetInfo.cbBuffer;
530
531 if (!ntlm_av_pair_list_init(pAvPairList, cbAvPairList))
532 goto fail;
533
534 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvNbDomainName, (PBYTE)NbDomainName.Buffer,
535 NbDomainName.Length))
536 goto fail;
537
538 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvNbComputerName,
539 (PBYTE)NbComputerName.Buffer, NbComputerName.Length))
540 goto fail;
541
542 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvDnsDomainName,
543 (PBYTE)DnsDomainName.Buffer, DnsDomainName.Length))
544 goto fail;
545
546 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvDnsComputerName,
547 (PBYTE)DnsComputerName.Buffer, DnsComputerName.Length))
548 goto fail;
549
550 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvTimestamp, context->Timestamp,
551 sizeof(context->Timestamp)))
552 goto fail;
553
554 rc = TRUE;
555fail:
556 ntlm_free_unicode_string(&NbDomainName);
557 ntlm_free_unicode_string(&NbComputerName);
558 ntlm_free_unicode_string(&DnsDomainName);
559 ntlm_free_unicode_string(&DnsComputerName);
560 return rc;
561}
562
563BOOL ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
564{
565 ULONG AvPairsCount = 0;
566 size_t AvPairsValueLength = 0;
567 NTLM_AV_PAIR* AvTimestamp = nullptr;
568 NTLM_AV_PAIR* AvNbDomainName = nullptr;
569 NTLM_AV_PAIR* AvNbComputerName = nullptr;
570 NTLM_AV_PAIR* AvDnsDomainName = nullptr;
571 NTLM_AV_PAIR* AvDnsComputerName = nullptr;
572 NTLM_AV_PAIR* AvDnsTreeName = nullptr;
573 NTLM_AV_PAIR* ChallengeTargetInfo = nullptr;
574 NTLM_AV_PAIR* AuthenticateTargetInfo = nullptr;
575 size_t cbAvTimestamp = 0;
576 size_t cbAvNbDomainName = 0;
577 size_t cbAvNbComputerName = 0;
578 size_t cbAvDnsDomainName = 0;
579 size_t cbAvDnsComputerName = 0;
580 size_t cbAvDnsTreeName = 0;
581 size_t cbChallengeTargetInfo = 0;
582 size_t cbAuthenticateTargetInfo = 0;
583
584 WINPR_ASSERT(context);
585
586 AvPairsCount = 1;
587 ChallengeTargetInfo = (NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer;
588 cbChallengeTargetInfo = context->ChallengeTargetInfo.cbBuffer;
589 AvNbDomainName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvNbDomainName,
590 &cbAvNbDomainName);
591 AvNbComputerName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
592 MsvAvNbComputerName, &cbAvNbComputerName);
593 AvDnsDomainName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
594 MsvAvDnsDomainName, &cbAvDnsDomainName);
595 AvDnsComputerName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
596 MsvAvDnsComputerName, &cbAvDnsComputerName);
597 AvDnsTreeName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvDnsTreeName,
598 &cbAvDnsTreeName);
599 AvTimestamp = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvTimestamp,
600 &cbAvTimestamp);
601
602 if (AvNbDomainName)
603 {
604 size_t avLen = 0;
605 if (!ntlm_av_pair_get_len(AvNbDomainName, cbAvNbDomainName, &avLen))
606 goto fail;
607 AvPairsCount++; /* MsvAvNbDomainName */
608 AvPairsValueLength += avLen;
609 }
610
611 if (AvNbComputerName)
612 {
613 size_t avLen = 0;
614 if (!ntlm_av_pair_get_len(AvNbComputerName, cbAvNbComputerName, &avLen))
615 goto fail;
616 AvPairsCount++; /* MsvAvNbComputerName */
617 AvPairsValueLength += avLen;
618 }
619
620 if (AvDnsDomainName)
621 {
622 size_t avLen = 0;
623 if (!ntlm_av_pair_get_len(AvDnsDomainName, cbAvDnsDomainName, &avLen))
624 goto fail;
625 AvPairsCount++; /* MsvAvDnsDomainName */
626 AvPairsValueLength += avLen;
627 }
628
629 if (AvDnsComputerName)
630 {
631 size_t avLen = 0;
632 if (!ntlm_av_pair_get_len(AvDnsComputerName, cbAvDnsComputerName, &avLen))
633 goto fail;
634 AvPairsCount++; /* MsvAvDnsComputerName */
635 AvPairsValueLength += avLen;
636 }
637
638 if (AvDnsTreeName)
639 {
640 size_t avLen = 0;
641 if (!ntlm_av_pair_get_len(AvDnsTreeName, cbAvDnsTreeName, &avLen))
642 goto fail;
643 AvPairsCount++; /* MsvAvDnsTreeName */
644 AvPairsValueLength += avLen;
645 }
646
647 AvPairsCount++; /* MsvAvTimestamp */
648 AvPairsValueLength += 8;
649
650 if (context->UseMIC)
651 {
652 AvPairsCount++; /* MsvAvFlags */
653 AvPairsValueLength += 4;
654 }
655
656 if (context->SendSingleHostData)
657 {
658 AvPairsCount++; /* MsvAvSingleHost */
659 ntlm_compute_single_host_data(context);
660 AvPairsValueLength += context->SingleHostData.Size;
661 }
662
668 if (!context->SuppressExtendedProtection)
669 {
674 AvPairsCount++; /* MsvAvChannelBindings */
675 AvPairsValueLength += 16;
676 ntlm_compute_channel_bindings(context);
677
678 if (context->ServicePrincipalName.Length > 0)
679 {
680 AvPairsCount++; /* MsvAvTargetName */
681 AvPairsValueLength += context->ServicePrincipalName.Length;
682 }
683 }
684
685 {
686 size_t size = ntlm_av_pair_list_size(AvPairsCount, AvPairsValueLength);
687 if (context->NTLMv2)
688 size += 8; /* unknown 8-byte padding */
689
690 if (!sspi_SecBufferAlloc(&context->AuthenticateTargetInfo,
691 WINPR_ASSERTING_INT_CAST(uint32_t, size)))
692 goto fail;
693 }
694
695 AuthenticateTargetInfo = (NTLM_AV_PAIR*)context->AuthenticateTargetInfo.pvBuffer;
696 cbAuthenticateTargetInfo = context->AuthenticateTargetInfo.cbBuffer;
697
698 if (!ntlm_av_pair_list_init(AuthenticateTargetInfo, cbAuthenticateTargetInfo))
699 goto fail;
700
701 if (AvNbDomainName)
702 {
703 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvNbDomainName,
704 cbAvNbDomainName))
705 goto fail;
706 }
707
708 if (AvNbComputerName)
709 {
710 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
711 AvNbComputerName, cbAvNbComputerName))
712 goto fail;
713 }
714
715 if (AvDnsDomainName)
716 {
717 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
718 AvDnsDomainName, cbAvDnsDomainName))
719 goto fail;
720 }
721
722 if (AvDnsComputerName)
723 {
724 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
725 AvDnsComputerName, cbAvDnsComputerName))
726 goto fail;
727 }
728
729 if (AvDnsTreeName)
730 {
731 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvDnsTreeName,
732 cbAvDnsTreeName))
733 goto fail;
734 }
735
736 if (AvTimestamp)
737 {
738 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvTimestamp,
739 cbAvTimestamp))
740 goto fail;
741 }
742
743 if (context->UseMIC)
744 {
745 UINT32 flags = 0;
746 winpr_Data_Write_UINT32(&flags, MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK);
747
748 if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvFlags,
749 (PBYTE)&flags, 4))
750 goto fail;
751 }
752
753 if (context->SendSingleHostData)
754 {
755 WINPR_ASSERT(context->SingleHostData.Size <= UINT16_MAX);
756 if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvSingleHost,
757 (PBYTE)&context->SingleHostData,
758 (UINT16)context->SingleHostData.Size))
759 goto fail;
760 }
761
762 if (!context->SuppressExtendedProtection)
763 {
764 if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
765 MsvAvChannelBindings, context->ChannelBindingsHash, 16))
766 goto fail;
767
768 if (context->ServicePrincipalName.Length > 0)
769 {
770 if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvTargetName,
771 (PBYTE)context->ServicePrincipalName.Buffer,
772 context->ServicePrincipalName.Length))
773 goto fail;
774 }
775 }
776
777 if (context->NTLMv2)
778 {
779 size_t cbAvEOL = 0;
780 NTLM_AV_PAIR* AvEOL =
781 ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvEOL, &cbAvEOL);
782
783 size_t cbAvEntryLen = 0;
784 if (!ntlm_av_pair_get_len(AvEOL, cbAvEOL, &cbAvEntryLen))
785 goto fail;
786
787 ZeroMemory(AvEOL, sizeof(NTLM_AV_PAIR));
788 }
789
790 return TRUE;
791fail:
792 sspi_SecBufferFree(&context->AuthenticateTargetInfo);
793 return FALSE;
794}