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  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  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  UINT16 AvId = 0;
113  if (!pAvPair || !pair)
114  return FALSE;
115 
116  if (size < sizeof(NTLM_AV_PAIR))
117  return FALSE;
118 
119  Data_Read_UINT16(&pAvPair->AvId, AvId);
120 
121  *pair = AvId;
122  return TRUE;
123 }
124 
125 ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
126 {
127  size_t cbAvPair = 0;
128  NTLM_AV_PAIR* pAvPair = NULL;
129 
130  pAvPair = ntlm_av_pair_get(pAvPairList, cbAvPairList, MsvAvEOL, &cbAvPair);
131  if (!pAvPair)
132  return 0;
133 
134  if (pAvPair < pAvPairList)
135  return 0;
136 
137  const size_t size = ((PBYTE)pAvPair - (PBYTE)pAvPairList) + 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  UINT16 AvLen = 0;
146  if (!pAvPair)
147  return FALSE;
148 
149  if (size < sizeof(NTLM_AV_PAIR))
150  return FALSE;
151 
152  Data_Read_UINT16(&pAvPair->AvLen, AvLen);
153 
154  *pAvLen = AvLen;
155  return TRUE;
156 }
157 
158 #ifdef WITH_DEBUG_NTLM
159 void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
160 {
161  UINT16 pair = 0;
162  size_t cbAvPair = cbAvPairList;
163  NTLM_AV_PAIR* pAvPair = pAvPairList;
164 
165  if (!ntlm_av_pair_check(pAvPair, cbAvPair))
166  return;
167 
168  WLog_VRB(TAG, "AV_PAIRs =");
169 
170  while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair) && (pair != MsvAvEOL))
171  {
172  size_t cbLen = 0;
173  ntlm_av_pair_get_len(pAvPair, cbAvPair, &cbLen);
174 
175  WLog_VRB(TAG, "\t%s AvId: %" PRIu16 " AvLen: %" PRIu16 "", get_av_pair_string(pair), pair);
176  winpr_HexDump(TAG, WLOG_TRACE, ntlm_av_pair_get_value_pointer(pAvPair), cbLen);
177 
178  pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
179  }
180 }
181 #endif
182 
183 static ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength)
184 {
185  /* size of headers + value lengths + terminating MsvAvEOL AV_PAIR */
186  return ((AvPairsCount + 1) * 4) + AvPairsValueLength;
187 }
188 
189 PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair)
190 {
191  WINPR_ASSERT(pAvPair);
192  return (PBYTE)pAvPair + sizeof(NTLM_AV_PAIR);
193 }
194 
195 static BOOL ntlm_av_pair_get_next_offset(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pOffset)
196 {
197  size_t avLen = 0;
198  if (!pOffset)
199  return FALSE;
200 
201  if (!ntlm_av_pair_get_len(pAvPair, size, &avLen))
202  return FALSE;
203  *pOffset = avLen + sizeof(NTLM_AV_PAIR);
204  return TRUE;
205 }
206 
207 static BOOL ntlm_av_pair_check(const NTLM_AV_PAIR* pAvPair, size_t cbAvPair)
208 {
209  return ntlm_av_pair_check_data(pAvPair, cbAvPair, 0);
210 }
211 
212 static NTLM_AV_PAIR* ntlm_av_pair_next(NTLM_AV_PAIR* pAvPair, size_t* pcbAvPair)
213 {
214  size_t offset = 0;
215 
216  if (!pcbAvPair)
217  return NULL;
218  if (!ntlm_av_pair_check(pAvPair, *pcbAvPair))
219  return NULL;
220 
221  if (!ntlm_av_pair_get_next_offset(pAvPair, *pcbAvPair, &offset))
222  return NULL;
223 
224  *pcbAvPair -= offset;
225  return (NTLM_AV_PAIR*)((PBYTE)pAvPair + offset);
226 }
227 
228 NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTLM_AV_ID AvId,
229  size_t* pcbAvPairListRemaining)
230 {
231  UINT16 id = 0;
232  size_t cbAvPair = cbAvPairList;
233  NTLM_AV_PAIR* pAvPair = pAvPairList;
234 
235  if (!ntlm_av_pair_check(pAvPair, cbAvPair))
236  pAvPair = NULL;
237 
238  while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &id))
239  {
240  if (id == AvId)
241  break;
242  if (id == MsvAvEOL)
243  {
244  pAvPair = NULL;
245  break;
246  }
247 
248  pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
249  }
250 
251  if (!pAvPair)
252  cbAvPair = 0;
253  if (pcbAvPairListRemaining)
254  *pcbAvPairListRemaining = cbAvPair;
255 
256  return pAvPair;
257 }
258 
259 static BOOL ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTLM_AV_ID AvId,
260  PBYTE Value, UINT16 AvLen)
261 {
262  size_t cbAvPair = 0;
263  NTLM_AV_PAIR* pAvPair = NULL;
264 
265  pAvPair = ntlm_av_pair_get(pAvPairList, cbAvPairList, MsvAvEOL, &cbAvPair);
266 
267  /* size of header + value length + terminating MsvAvEOL AV_PAIR */
268  if (!pAvPair || cbAvPair < 2 * sizeof(NTLM_AV_PAIR) + AvLen)
269  return FALSE;
270 
271  ntlm_av_pair_set_id(pAvPair, (UINT16)AvId);
272  ntlm_av_pair_set_len(pAvPair, AvLen);
273  if (AvLen)
274  {
275  WINPR_ASSERT(Value != NULL);
276  CopyMemory(ntlm_av_pair_get_value_pointer(pAvPair), Value, AvLen);
277  }
278 
279  pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
280  return ntlm_av_pair_list_init(pAvPair, cbAvPair);
281 }
282 
283 static BOOL ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList,
284  NTLM_AV_PAIR* pAvPair, size_t cbAvPair)
285 {
286  UINT16 pair = 0;
287  size_t avLen = 0;
288 
289  if (!ntlm_av_pair_check(pAvPair, cbAvPair))
290  return FALSE;
291 
292  if (!ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair))
293  return FALSE;
294 
295  if (!ntlm_av_pair_get_len(pAvPair, cbAvPair, &avLen))
296  return FALSE;
297 
298  WINPR_ASSERT(avLen <= UINT16_MAX);
299  return ntlm_av_pair_add(pAvPairList, cbAvPairList, pair,
300  ntlm_av_pair_get_value_pointer(pAvPair), (UINT16)avLen);
301 }
302 
303 static int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type)
304 {
305  char* name = NULL;
306  int status = -1;
307  DWORD nSize = 0;
308  CHAR* computerName = NULL;
309 
310  WINPR_ASSERT(pName);
311 
312  if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) || GetLastError() != ERROR_MORE_DATA)
313  return -1;
314 
315  computerName = calloc(nSize, sizeof(CHAR));
316 
317  if (!computerName)
318  return -1;
319 
320  if (!GetComputerNameExA(ComputerNameNetBIOS, computerName, &nSize))
321  {
322  free(computerName);
323  return -1;
324  }
325 
326  if (nSize > MAX_COMPUTERNAME_LENGTH)
327  computerName[MAX_COMPUTERNAME_LENGTH] = '\0';
328 
329  name = computerName;
330 
331  if (!name)
332  return -1;
333 
334  if (type == ComputerNameNetBIOS)
335  CharUpperA(name);
336 
337  size_t len = 0;
338  pName->Buffer = ConvertUtf8ToWCharAlloc(name, &len);
339 
340  if (!pName->Buffer || (len == 0) || (len > UINT16_MAX / sizeof(WCHAR)))
341  {
342  free(pName->Buffer);
343  pName->Buffer = NULL;
344  free(name);
345  return status;
346  }
347 
348  pName->Length = (USHORT)((len) * sizeof(WCHAR));
349  pName->MaximumLength = pName->Length;
350  free(name);
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  Data_Write_UINT32(&context->SingleHostData.Size, 48);
467  Data_Write_UINT32(&context->SingleHostData.Z4, 0);
468  Data_Write_UINT32(&context->SingleHostData.DataPresent, 1);
469  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  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 }