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