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