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