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