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