FreeRDP
TestNTLM.c
1 
2 #include <winpr/crt.h>
3 #include <winpr/assert.h>
4 #include <winpr/sspi.h>
5 #include <winpr/print.h>
6 #include <winpr/wlog.h>
7 
8 struct test_input_t
9 {
10  const char* user;
11  const char* domain;
12  const char* pwd;
13  const BYTE* ntlm;
14  const BYTE* ntlmv2;
15  BOOL dynamic;
16  BOOL expected;
17 };
18 
19 typedef struct
20 {
21  CtxtHandle context;
22  ULONG cbMaxToken;
23  ULONG fContextReq;
24  ULONG pfContextAttr;
25  TimeStamp expiration;
26  PSecBuffer pBuffer;
27  SecBuffer inputBuffer[2];
28  SecBuffer outputBuffer[2];
29  BOOL haveContext;
30  BOOL haveInputBuffer;
31  BOOL UseNtlmV2Hash;
32  LPTSTR ServicePrincipalName;
33  SecBufferDesc inputBufferDesc;
34  SecBufferDesc outputBufferDesc;
35  CredHandle credentials;
36  BOOL confidentiality;
37  SecPkgInfo* pPackageInfo;
38  SecurityFunctionTable* table;
39  SEC_WINNT_AUTH_IDENTITY identity;
40 } TEST_NTLM_SERVER;
41 
42 static BYTE TEST_NTLM_TIMESTAMP[8] = { 0x33, 0x57, 0xbd, 0xb1, 0x07, 0x8b, 0xcf, 0x01 };
43 
44 static BYTE TEST_NTLM_CLIENT_CHALLENGE[8] = { 0x20, 0xc0, 0x2b, 0x3d, 0xc0, 0x61, 0xa7, 0x73 };
45 
46 static BYTE TEST_NTLM_SERVER_CHALLENGE[8] = { 0xa4, 0xf1, 0xba, 0xa6, 0x7c, 0xdc, 0x1a, 0x12 };
47 
48 static BYTE TEST_NTLM_NEGOTIATE[] =
49  "\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2"
50  "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
51  "\x06\x03\x80\x25\x00\x00\x00\x0f";
52 
53 static BYTE TEST_NTLM_CHALLENGE[] =
54  "\x4e\x54\x4c\x4d\x53\x53\x50\x00\x02\x00\x00\x00\x00\x00\x00\x00"
55  "\x38\x00\x00\x00\x07\x82\x88\xa2\xa4\xf1\xba\xa6\x7c\xdc\x1a\x12"
56  "\x00\x00\x00\x00\x00\x00\x00\x00\x66\x00\x66\x00\x38\x00\x00\x00"
57  "\x06\x03\x80\x25\x00\x00\x00\x0f\x02\x00\x0e\x00\x4e\x00\x45\x00"
58  "\x57\x00\x59\x00\x45\x00\x41\x00\x52\x00\x01\x00\x0e\x00\x4e\x00"
59  "\x45\x00\x57\x00\x59\x00\x45\x00\x41\x00\x52\x00\x04\x00\x1c\x00"
60  "\x6c\x00\x61\x00\x62\x00\x2e\x00\x77\x00\x61\x00\x79\x00\x6b\x00"
61  "\x2e\x00\x6c\x00\x6f\x00\x63\x00\x61\x00\x6c\x00\x03\x00\x0e\x00"
62  "\x6e\x00\x65\x00\x77\x00\x79\x00\x65\x00\x61\x00\x72\x00\x07\x00"
63  "\x08\x00\x33\x57\xbd\xb1\x07\x8b\xcf\x01\x00\x00\x00\x00";
64 
65 static BYTE TEST_NTLM_AUTHENTICATE[] =
66  "\x4e\x54\x4c\x4d\x53\x53\x50\x00\x03\x00\x00\x00\x18\x00\x18\x00"
67  "\x82\x00\x00\x00\x08\x01\x08\x01\x9a\x00\x00\x00\x0c\x00\x0c\x00"
68  "\x58\x00\x00\x00\x10\x00\x10\x00\x64\x00\x00\x00\x0e\x00\x0e\x00"
69  "\x74\x00\x00\x00\x00\x00\x00\x00\xa2\x01\x00\x00\x05\x82\x88\xa2"
70  "\x06\x03\x80\x25\x00\x00\x00\x0f\x12\xe5\x5a\xf5\x80\xee\x3f\x29"
71  "\xe1\xde\x90\x4d\x73\x77\x06\x25\x44\x00\x6f\x00\x6d\x00\x61\x00"
72  "\x69\x00\x6e\x00\x55\x00\x73\x00\x65\x00\x72\x00\x6e\x00\x61\x00"
73  "\x6d\x00\x65\x00\x4e\x00\x45\x00\x57\x00\x59\x00\x45\x00\x41\x00"
74  "\x52\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
75  "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x62\x14\x68\xc8\x98\x12"
76  "\xe7\x39\xd8\x76\x1b\xe9\xf7\x54\xb5\xe3\x01\x01\x00\x00\x00\x00"
77  "\x00\x00\x33\x57\xbd\xb1\x07\x8b\xcf\x01\x20\xc0\x2b\x3d\xc0\x61"
78  "\xa7\x73\x00\x00\x00\x00\x02\x00\x0e\x00\x4e\x00\x45\x00\x57\x00"
79  "\x59\x00\x45\x00\x41\x00\x52\x00\x01\x00\x0e\x00\x4e\x00\x45\x00"
80  "\x57\x00\x59\x00\x45\x00\x41\x00\x52\x00\x04\x00\x1c\x00\x6c\x00"
81  "\x61\x00\x62\x00\x2e\x00\x77\x00\x61\x00\x79\x00\x6b\x00\x2e\x00"
82  "\x6c\x00\x6f\x00\x63\x00\x61\x00\x6c\x00\x03\x00\x0e\x00\x6e\x00"
83  "\x65\x00\x77\x00\x79\x00\x65\x00\x61\x00\x72\x00\x07\x00\x08\x00"
84  "\x33\x57\xbd\xb1\x07\x8b\xcf\x01\x06\x00\x04\x00\x02\x00\x00\x00"
85  "\x08\x00\x30\x00\x30\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"
86  "\x00\x20\x00\x00\x1e\x10\xf5\x2c\x54\x2f\x2e\x77\x1c\x13\xbf\xc3"
87  "\x3f\xe1\x7b\x28\x7e\x0b\x93\x5a\x39\xd2\xce\x12\xd7\xbd\x8c\x4e"
88  "\x2b\xb5\x0b\xf5\x0a\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00"
89  "\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x1a\x00\x48\x00\x54\x00"
90  "\x54\x00\x50\x00\x2f\x00\x72\x00\x77\x00\x2e\x00\x6c\x00\x6f\x00"
91  "\x63\x00\x61\x00\x6c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
92  "\x00\x00";
93 
94 #define TEST_SSPI_INTERFACE SSPI_INTERFACE_WINPR
95 
96 static const char* TEST_NTLM_USER = "Username";
97 static const char* TEST_NTLM_DOMAIN = "Domain";
98 static const char* TEST_NTLM_PASSWORD = "P4ss123!";
99 
100 // static const char* TEST_NTLM_HASH_STRING = "d5922a65c4d5c082ca444af1be0001db";
101 
102 static const BYTE TEST_NTLM_HASH[16] = { 0xd5, 0x92, 0x2a, 0x65, 0xc4, 0xd5, 0xc0, 0x82,
103  0xca, 0x44, 0x4a, 0xf1, 0xbe, 0x00, 0x01, 0xdb };
104 
105 // static const char* TEST_NTLM_HASH_V2_STRING = "4c7f706f7dde05a9d1a0f4e7ffe3bfb8";
106 
107 static const BYTE TEST_NTLM_V2_HASH[16] = { 0x4c, 0x7f, 0x70, 0x6f, 0x7d, 0xde, 0x05, 0xa9,
108  0xd1, 0xa0, 0xf4, 0xe7, 0xff, 0xe3, 0xbf, 0xb8 };
109 
110 static const BYTE TEST_EMPTY_PWD_NTLM_HASH[] = { 0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31,
111  0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0 };
112 
113 static const BYTE TEST_EMPTY_PWD_NTLM_V2_HASH[] = {
114  0x0b, 0xce, 0x54, 0x87, 0x4e, 0x94, 0x20, 0x9e, 0x34, 0x48, 0x97, 0xc1, 0x60, 0x03, 0x6e, 0x3b
115 };
116 
117 #define NTLM_PACKAGE_NAME NTLM_SSP_NAME
118 
119 typedef struct
120 {
121  CtxtHandle context;
122  ULONG cbMaxToken;
123  ULONG fContextReq;
124  ULONG pfContextAttr;
125  TimeStamp expiration;
126  PSecBuffer pBuffer;
127  SecBuffer inputBuffer[2];
128  SecBuffer outputBuffer[2];
129  BOOL haveContext;
130  BOOL haveInputBuffer;
131  LPTSTR ServicePrincipalName;
132  SecBufferDesc inputBufferDesc;
133  SecBufferDesc outputBufferDesc;
134  CredHandle credentials;
135  BOOL confidentiality;
136  SecPkgInfo* pPackageInfo;
137  SecurityFunctionTable* table;
138  SEC_WINNT_AUTH_IDENTITY identity;
139 } TEST_NTLM_CLIENT;
140 
141 static int test_ntlm_client_init(TEST_NTLM_CLIENT* ntlm, const char* user, const char* domain,
142  const char* password)
143 {
144  SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
145 
146  WINPR_ASSERT(ntlm);
147 
148  SecInvalidateHandle(&(ntlm->context));
149  ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
150  if (!ntlm->table)
151  return -1;
152  const int rc = sspi_SetAuthIdentity(&(ntlm->identity), user, domain, password);
153  if (rc < 0)
154  return rc;
155 
156  status = ntlm->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &ntlm->pPackageInfo);
157 
158  if (status != SEC_E_OK)
159  {
160  (void)fprintf(stderr, "QuerySecurityPackageInfo status: %s (0x%08" PRIX32 ")\n",
161  GetSecurityStatusString(status), status);
162  return -1;
163  }
164 
165  ntlm->cbMaxToken = ntlm->pPackageInfo->cbMaxToken;
166  status = ntlm->table->AcquireCredentialsHandle(NULL, NTLM_PACKAGE_NAME, SECPKG_CRED_OUTBOUND,
167  NULL, &ntlm->identity, NULL, NULL,
168  &ntlm->credentials, &ntlm->expiration);
169 
170  if (status != SEC_E_OK)
171  {
172  (void)fprintf(stderr, "AcquireCredentialsHandle status: %s (0x%08" PRIX32 ")\n",
173  GetSecurityStatusString(status), status);
174  return -1;
175  }
176 
177  ntlm->haveContext = FALSE;
178  ntlm->haveInputBuffer = FALSE;
179  ZeroMemory(&ntlm->inputBuffer, sizeof(SecBuffer));
180  ZeroMemory(&ntlm->outputBuffer, sizeof(SecBuffer));
181  ntlm->fContextReq = 0;
182 #if 0
183  /* HTTP authentication flags */
184  ntlm->fContextReq |= ISC_REQ_CONFIDENTIALITY;
185 #endif
186  /* NLA authentication flags */
187  ntlm->fContextReq |= ISC_REQ_MUTUAL_AUTH;
188  ntlm->fContextReq |= ISC_REQ_CONFIDENTIALITY;
189  ntlm->fContextReq |= ISC_REQ_USE_SESSION_KEY;
190  return 1;
191 }
192 
193 static void test_ntlm_client_uninit(TEST_NTLM_CLIENT* ntlm)
194 {
195  if (!ntlm)
196  return;
197 
198  if (ntlm->outputBuffer[0].pvBuffer)
199  {
200  free(ntlm->outputBuffer[0].pvBuffer);
201  ntlm->outputBuffer[0].pvBuffer = NULL;
202  }
203 
204  free(ntlm->identity.User);
205  free(ntlm->identity.Domain);
206  free(ntlm->identity.Password);
207  free(ntlm->ServicePrincipalName);
208 
209  if (ntlm->table)
210  {
211  SECURITY_STATUS status = ntlm->table->FreeCredentialsHandle(&ntlm->credentials);
212  WINPR_ASSERT((status == SEC_E_OK) || (status == SEC_E_SECPKG_NOT_FOUND) ||
213  (status == SEC_E_UNSUPPORTED_FUNCTION));
214 
215  status = ntlm->table->FreeContextBuffer(ntlm->pPackageInfo);
216  WINPR_ASSERT((status == SEC_E_OK) || (status = SEC_E_INVALID_HANDLE));
217 
218  status = ntlm->table->DeleteSecurityContext(&ntlm->context);
219  WINPR_ASSERT((status == SEC_E_OK) || (status == SEC_E_SECPKG_NOT_FOUND) ||
220  (status == SEC_E_UNSUPPORTED_FUNCTION));
221  }
222 }
223 
261 static BOOL IsSecurityStatusError(SECURITY_STATUS status)
262 {
263  BOOL error = TRUE;
264 
265  switch (status)
266  {
267  case SEC_E_OK:
268  case SEC_I_CONTINUE_NEEDED:
269  case SEC_I_COMPLETE_NEEDED:
270  case SEC_I_COMPLETE_AND_CONTINUE:
271  case SEC_I_LOCAL_LOGON:
272  case SEC_I_CONTEXT_EXPIRED:
273  case SEC_I_INCOMPLETE_CREDENTIALS:
274  case SEC_I_RENEGOTIATE:
275  case SEC_I_NO_LSA_CONTEXT:
276  case SEC_I_SIGNATURE_NEEDED:
277  case SEC_I_NO_RENEGOTIATION:
278  error = FALSE;
279  break;
280  default:
281  break;
282  }
283 
284  return error;
285 }
286 
287 static int test_ntlm_client_authenticate(TEST_NTLM_CLIENT* ntlm)
288 {
289  SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
290 
291  WINPR_ASSERT(ntlm);
292  if (ntlm->outputBuffer[0].pvBuffer)
293  {
294  free(ntlm->outputBuffer[0].pvBuffer);
295  ntlm->outputBuffer[0].pvBuffer = NULL;
296  }
297 
298  ntlm->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
299  ntlm->outputBufferDesc.cBuffers = 1;
300  ntlm->outputBufferDesc.pBuffers = ntlm->outputBuffer;
301  ntlm->outputBuffer[0].BufferType = SECBUFFER_TOKEN;
302  ntlm->outputBuffer[0].cbBuffer = ntlm->cbMaxToken;
303  ntlm->outputBuffer[0].pvBuffer = malloc(ntlm->outputBuffer[0].cbBuffer);
304 
305  if (!ntlm->outputBuffer[0].pvBuffer)
306  return -1;
307 
308  if (ntlm->haveInputBuffer)
309  {
310  ntlm->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
311  ntlm->inputBufferDesc.cBuffers = 1;
312  ntlm->inputBufferDesc.pBuffers = ntlm->inputBuffer;
313  ntlm->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
314  }
315 
316  if ((!ntlm) || (!ntlm->table))
317  {
318  (void)fprintf(stderr, "ntlm_authenticate: invalid ntlm context\n");
319  return -1;
320  }
321 
322  status = ntlm->table->InitializeSecurityContext(
323  &ntlm->credentials, (ntlm->haveContext) ? &ntlm->context : NULL,
324  (ntlm->ServicePrincipalName) ? ntlm->ServicePrincipalName : NULL, ntlm->fContextReq, 0,
325  SECURITY_NATIVE_DREP, (ntlm->haveInputBuffer) ? &ntlm->inputBufferDesc : NULL, 0,
326  &ntlm->context, &ntlm->outputBufferDesc, &ntlm->pfContextAttr, &ntlm->expiration);
327 
328  if (IsSecurityStatusError(status))
329  return -1;
330 
331  if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
332  {
333  if (ntlm->table->CompleteAuthToken)
334  {
335  SECURITY_STATUS rc =
336  ntlm->table->CompleteAuthToken(&ntlm->context, &ntlm->outputBufferDesc);
337  if (rc != SEC_E_OK)
338  return -1;
339  }
340 
341  if (status == SEC_I_COMPLETE_NEEDED)
342  status = SEC_E_OK;
343  else if (status == SEC_I_COMPLETE_AND_CONTINUE)
344  status = SEC_I_CONTINUE_NEEDED;
345  }
346 
347  if (ntlm->haveInputBuffer)
348  {
349  free(ntlm->inputBuffer[0].pvBuffer);
350  }
351 
352  ntlm->haveInputBuffer = TRUE;
353  ntlm->haveContext = TRUE;
354  return (status == SEC_I_CONTINUE_NEEDED) ? 1 : 0;
355 }
356 
357 static TEST_NTLM_CLIENT* test_ntlm_client_new(void)
358 {
359  TEST_NTLM_CLIENT* ntlm = (TEST_NTLM_CLIENT*)calloc(1, sizeof(TEST_NTLM_CLIENT));
360 
361  if (!ntlm)
362  return NULL;
363 
364  return ntlm;
365 }
366 
367 static void test_ntlm_client_free(TEST_NTLM_CLIENT* ntlm)
368 {
369  if (!ntlm)
370  return;
371 
372  test_ntlm_client_uninit(ntlm);
373  free(ntlm);
374 }
375 
376 static int test_ntlm_server_init(TEST_NTLM_SERVER* ntlm)
377 {
378  SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
379 
380  WINPR_ASSERT(ntlm);
381 
382  ntlm->UseNtlmV2Hash = TRUE;
383  SecInvalidateHandle(&(ntlm->context));
384  ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
385  if (!ntlm->table)
386  return SEC_E_INTERNAL_ERROR;
387 
388  status = ntlm->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &ntlm->pPackageInfo);
389 
390  if (status != SEC_E_OK)
391  {
392  (void)fprintf(stderr, "QuerySecurityPackageInfo status: %s (0x%08" PRIX32 ")\n",
393  GetSecurityStatusString(status), status);
394  return -1;
395  }
396 
397  ntlm->cbMaxToken = ntlm->pPackageInfo->cbMaxToken;
398  status = ntlm->table->AcquireCredentialsHandle(NULL, NTLM_PACKAGE_NAME, SECPKG_CRED_INBOUND,
399  NULL, NULL, NULL, NULL, &ntlm->credentials,
400  &ntlm->expiration);
401 
402  if (status != SEC_E_OK)
403  {
404  (void)fprintf(stderr, "AcquireCredentialsHandle status: %s (0x%08" PRIX32 ")\n",
405  GetSecurityStatusString(status), status);
406  return -1;
407  }
408 
409  ntlm->haveContext = FALSE;
410  ntlm->haveInputBuffer = FALSE;
411  ZeroMemory(&ntlm->inputBuffer, sizeof(SecBuffer));
412  ZeroMemory(&ntlm->outputBuffer, sizeof(SecBuffer));
413  ntlm->fContextReq = 0;
414  /* NLA authentication flags */
415  ntlm->fContextReq |= ASC_REQ_MUTUAL_AUTH;
416  ntlm->fContextReq |= ASC_REQ_CONFIDENTIALITY;
417  ntlm->fContextReq |= ASC_REQ_CONNECTION;
418  ntlm->fContextReq |= ASC_REQ_USE_SESSION_KEY;
419  ntlm->fContextReq |= ASC_REQ_REPLAY_DETECT;
420  ntlm->fContextReq |= ASC_REQ_SEQUENCE_DETECT;
421  ntlm->fContextReq |= ASC_REQ_EXTENDED_ERROR;
422  return 1;
423 }
424 
425 static void test_ntlm_server_uninit(TEST_NTLM_SERVER* ntlm)
426 {
427  if (!ntlm)
428  return;
429 
430  if (ntlm->outputBuffer[0].pvBuffer)
431  {
432  free(ntlm->outputBuffer[0].pvBuffer);
433  ntlm->outputBuffer[0].pvBuffer = NULL;
434  }
435 
436  free(ntlm->identity.User);
437  free(ntlm->identity.Domain);
438  free(ntlm->identity.Password);
439  free(ntlm->ServicePrincipalName);
440 
441  if (ntlm->table)
442  {
443  SECURITY_STATUS status = ntlm->table->FreeCredentialsHandle(&ntlm->credentials);
444  WINPR_ASSERT(status == SEC_E_OK);
445  status = ntlm->table->FreeContextBuffer(ntlm->pPackageInfo);
446  WINPR_ASSERT(status == SEC_E_OK);
447  status = ntlm->table->DeleteSecurityContext(&ntlm->context);
448  WINPR_ASSERT(status == SEC_E_OK);
449  }
450 }
451 
452 static int test_ntlm_server_authenticate(const struct test_input_t* targ, TEST_NTLM_SERVER* ntlm)
453 {
454  SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
455 
456  WINPR_ASSERT(ntlm);
457  WINPR_ASSERT(targ);
458 
459  ntlm->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
460  ntlm->inputBufferDesc.cBuffers = 1;
461  ntlm->inputBufferDesc.pBuffers = ntlm->inputBuffer;
462  ntlm->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
463  ntlm->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
464  ntlm->outputBufferDesc.cBuffers = 1;
465  ntlm->outputBufferDesc.pBuffers = &ntlm->outputBuffer[0];
466  ntlm->outputBuffer[0].BufferType = SECBUFFER_TOKEN;
467  ntlm->outputBuffer[0].cbBuffer = ntlm->cbMaxToken;
468  ntlm->outputBuffer[0].pvBuffer = malloc(ntlm->outputBuffer[0].cbBuffer);
469 
470  if (!ntlm->outputBuffer[0].pvBuffer)
471  return -1;
472 
473  status = ntlm->table->AcceptSecurityContext(
474  &ntlm->credentials, ntlm->haveContext ? &ntlm->context : NULL, &ntlm->inputBufferDesc,
475  ntlm->fContextReq, SECURITY_NATIVE_DREP, &ntlm->context, &ntlm->outputBufferDesc,
476  &ntlm->pfContextAttr, &ntlm->expiration);
477 
478  if (status == SEC_I_CONTINUE_NEEDED)
479  {
480  SecPkgContext_AuthNtlmHash AuthNtlmHash = { 0 };
481 
482  if (ntlm->UseNtlmV2Hash)
483  {
484  AuthNtlmHash.Version = 2;
485  CopyMemory(AuthNtlmHash.NtlmHash, targ->ntlmv2, 16);
486  }
487  else
488  {
489  AuthNtlmHash.Version = 1;
490  CopyMemory(AuthNtlmHash.NtlmHash, targ->ntlm, 16);
491  }
492 
493  status =
494  ntlm->table->SetContextAttributes(&ntlm->context, SECPKG_ATTR_AUTH_NTLM_HASH,
495  &AuthNtlmHash, sizeof(SecPkgContext_AuthNtlmHash));
496  }
497 
498  if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED))
499  {
500  (void)fprintf(stderr, "AcceptSecurityContext status: %s (0x%08" PRIX32 ")\n",
501  GetSecurityStatusString(status), status);
502  return -1; /* Access Denied */
503  }
504 
505  ntlm->haveContext = TRUE;
506  return (status == SEC_I_CONTINUE_NEEDED) ? 1 : 0;
507 }
508 
509 static TEST_NTLM_SERVER* test_ntlm_server_new(void)
510 {
511  TEST_NTLM_SERVER* ntlm = (TEST_NTLM_SERVER*)calloc(1, sizeof(TEST_NTLM_SERVER));
512 
513  if (!ntlm)
514  return NULL;
515 
516  return ntlm;
517 }
518 
519 static void test_ntlm_server_free(TEST_NTLM_SERVER* ntlm)
520 {
521  if (!ntlm)
522  return;
523 
524  test_ntlm_server_uninit(ntlm);
525  free(ntlm);
526 }
527 
528 static BOOL test_default(const struct test_input_t* arg)
529 {
530  BOOL rc = FALSE;
531  PSecBuffer pSecBuffer = NULL;
532 
533  WINPR_ASSERT(arg);
534 
535  printf("testcase {user=%s, domain=%s, password=%s, dynamic=%s}\n", arg->user, arg->domain,
536  arg->pwd, arg->dynamic ? "TRUE" : "FALSE");
537 
541  TEST_NTLM_CLIENT* client = test_ntlm_client_new();
542  TEST_NTLM_SERVER* server = test_ntlm_server_new();
543 
544  if (!client || !server)
545  {
546  printf("Memory allocation failed\n");
547  goto fail;
548  }
549 
550  int status = test_ntlm_client_init(client, arg->user, arg->domain, arg->pwd);
551 
552  if (status < 0)
553  {
554  printf("test_ntlm_client_init failure\n");
555  goto fail;
556  }
557 
562  status = test_ntlm_server_init(server);
563 
564  if (status < 0)
565  {
566  printf("test_ntlm_server_init failure\n");
567  goto fail;
568  }
569 
573  status = test_ntlm_client_authenticate(client);
574 
575  if (status < 0)
576  {
577  printf("test_ntlm_client_authenticate failure\n");
578  goto fail;
579  }
580 
581  if (!arg->dynamic)
582  {
583  SecPkgContext_AuthNtlmTimestamp AuthNtlmTimestamp = { 0 };
584  SecPkgContext_AuthNtlmClientChallenge AuthNtlmClientChallenge = { 0 };
585  SecPkgContext_AuthNtlmServerChallenge AuthNtlmServerChallenge = { 0 };
586  CopyMemory(AuthNtlmTimestamp.Timestamp, TEST_NTLM_TIMESTAMP, 8);
587  AuthNtlmTimestamp.ChallengeOrResponse = TRUE;
588  SECURITY_STATUS rc = client->table->SetContextAttributes(
589  &client->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP, &AuthNtlmTimestamp,
591  WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
592 
593  AuthNtlmTimestamp.ChallengeOrResponse = FALSE;
594  rc = client->table->SetContextAttributes(&client->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP,
595  &AuthNtlmTimestamp,
597  WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
598 
599  CopyMemory(AuthNtlmClientChallenge.ClientChallenge, TEST_NTLM_CLIENT_CHALLENGE, 8);
600  CopyMemory(AuthNtlmServerChallenge.ServerChallenge, TEST_NTLM_SERVER_CHALLENGE, 8);
601  rc = client->table->SetContextAttributes(
602  &client->context, SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE, &AuthNtlmClientChallenge,
604  WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
605 
606  rc = client->table->SetContextAttributes(
607  &client->context, SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE, &AuthNtlmServerChallenge,
609  WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
610  }
611 
612  pSecBuffer = &(client->outputBuffer[0]);
613 
614  if (!arg->dynamic)
615  {
616  pSecBuffer->cbBuffer = sizeof(TEST_NTLM_NEGOTIATE) - 1;
617  free(pSecBuffer->pvBuffer);
618  pSecBuffer->pvBuffer = malloc(pSecBuffer->cbBuffer);
619 
620  if (!pSecBuffer->pvBuffer)
621  {
622  printf("Memory allocation failed\n");
623  goto fail;
624  }
625 
626  CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_NEGOTIATE, pSecBuffer->cbBuffer);
627  }
628 
629  (void)fprintf(stderr, "NTLM_NEGOTIATE (length = %" PRIu32 "):\n", pSecBuffer->cbBuffer);
630  winpr_HexDump("sspi.test", WLOG_DEBUG, (BYTE*)pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
635  server->haveInputBuffer = TRUE;
636  server->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
637  server->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
638  server->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
639  status = test_ntlm_server_authenticate(arg, server);
640 
641  if (status < 0)
642  {
643  printf("test_ntlm_server_authenticate failure\n");
644  goto fail;
645  }
646 
647  if (!arg->dynamic)
648  {
649  SecPkgContext_AuthNtlmTimestamp AuthNtlmTimestamp = { 0 };
650  SecPkgContext_AuthNtlmClientChallenge AuthNtlmClientChallenge = { 0 };
651  SecPkgContext_AuthNtlmServerChallenge AuthNtlmServerChallenge = { 0 };
652  CopyMemory(AuthNtlmTimestamp.Timestamp, TEST_NTLM_TIMESTAMP, 8);
653  AuthNtlmTimestamp.ChallengeOrResponse = TRUE;
654  SECURITY_STATUS rc = client->table->SetContextAttributes(
655  &server->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP, &AuthNtlmTimestamp,
657  WINPR_ASSERT(rc == SEC_E_OK);
658 
659  AuthNtlmTimestamp.ChallengeOrResponse = FALSE;
660  rc = client->table->SetContextAttributes(&server->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP,
661  &AuthNtlmTimestamp,
663  WINPR_ASSERT(rc == SEC_E_OK);
664 
665  CopyMemory(AuthNtlmClientChallenge.ClientChallenge, TEST_NTLM_CLIENT_CHALLENGE, 8);
666  CopyMemory(AuthNtlmServerChallenge.ServerChallenge, TEST_NTLM_SERVER_CHALLENGE, 8);
667  rc = server->table->SetContextAttributes(
668  &server->context, SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE, &AuthNtlmClientChallenge,
670  WINPR_ASSERT(rc == SEC_E_OK);
671 
672  rc = server->table->SetContextAttributes(
673  &server->context, SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE, &AuthNtlmServerChallenge,
675  WINPR_ASSERT(rc == SEC_E_OK);
676  }
677 
678  pSecBuffer = &(server->outputBuffer[0]);
679 
680  if (!arg->dynamic)
681  {
682  SecPkgContext_AuthNtlmMessage AuthNtlmMessage = { 0 };
683  pSecBuffer->cbBuffer = sizeof(TEST_NTLM_CHALLENGE) - 1;
684  free(pSecBuffer->pvBuffer);
685  pSecBuffer->pvBuffer = malloc(pSecBuffer->cbBuffer);
686 
687  if (!pSecBuffer->pvBuffer)
688  {
689  printf("Memory allocation failed\n");
690  goto fail;
691  }
692 
693  CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_CHALLENGE, pSecBuffer->cbBuffer);
694  AuthNtlmMessage.type = 2;
695  AuthNtlmMessage.length = pSecBuffer->cbBuffer;
696  AuthNtlmMessage.buffer = (BYTE*)pSecBuffer->pvBuffer;
697  SECURITY_STATUS rc = server->table->SetContextAttributes(
698  &server->context, SECPKG_ATTR_AUTH_NTLM_MESSAGE, &AuthNtlmMessage,
700  if (rc != SEC_E_OK)
701  goto fail;
702  }
703 
704  (void)fprintf(stderr, "NTLM_CHALLENGE (length = %" PRIu32 "):\n", pSecBuffer->cbBuffer);
705  winpr_HexDump("sspi.test", WLOG_DEBUG, (BYTE*)pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
710  client->haveInputBuffer = TRUE;
711  client->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
712  client->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
713  client->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
714  status = test_ntlm_client_authenticate(client);
715 
716  if (status < 0)
717  {
718  printf("test_ntlm_client_authenticate failure\n");
719  goto fail;
720  }
721 
722  pSecBuffer = &(client->outputBuffer[0]);
723 
724  if (!arg->dynamic)
725  {
726  pSecBuffer->cbBuffer = sizeof(TEST_NTLM_AUTHENTICATE) - 1;
727  free(pSecBuffer->pvBuffer);
728  pSecBuffer->pvBuffer = malloc(pSecBuffer->cbBuffer);
729 
730  if (!pSecBuffer->pvBuffer)
731  {
732  printf("Memory allocation failed\n");
733  goto fail;
734  }
735 
736  CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_AUTHENTICATE, pSecBuffer->cbBuffer);
737  }
738 
739  (void)fprintf(stderr, "NTLM_AUTHENTICATE (length = %" PRIu32 "):\n", pSecBuffer->cbBuffer);
740  winpr_HexDump("sspi.test", WLOG_DEBUG, (BYTE*)pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
744  server->haveInputBuffer = TRUE;
745  server->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
746  server->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
747  server->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
748  status = test_ntlm_server_authenticate(arg, server);
749 
750  if (status < 0)
751  {
752  printf("test_ntlm_server_authenticate failure\n");
753  goto fail;
754  }
755 
756  rc = TRUE;
757 
758 fail:
762  test_ntlm_client_free(client);
763  test_ntlm_server_free(server);
764 
765  printf("testcase {user=%s, domain=%s, password=%s, dynamic=%s} returns %d\n", arg->user,
766  arg->domain, arg->pwd, arg->dynamic ? "TRUE" : "FALSE", rc);
767  return rc;
768 }
769 
770 int TestNTLM(int argc, char* argv[])
771 {
772  WINPR_UNUSED(argc);
773  WINPR_UNUSED(argv);
774 
775  const struct test_input_t inputs[] = {
776  { TEST_NTLM_USER, TEST_NTLM_DOMAIN, TEST_NTLM_PASSWORD, TEST_NTLM_HASH, TEST_NTLM_V2_HASH,
777  TRUE, TRUE },
778  { TEST_NTLM_USER, TEST_NTLM_DOMAIN, TEST_NTLM_PASSWORD, TEST_NTLM_HASH, TEST_NTLM_V2_HASH,
779  FALSE, TRUE },
780  { TEST_NTLM_USER, TEST_NTLM_DOMAIN, "", TEST_EMPTY_PWD_NTLM_HASH,
781  TEST_EMPTY_PWD_NTLM_V2_HASH, TRUE, TRUE },
782  { TEST_NTLM_USER, TEST_NTLM_DOMAIN, NULL, TEST_EMPTY_PWD_NTLM_HASH,
783  TEST_EMPTY_PWD_NTLM_V2_HASH, TRUE, FALSE }
784  };
785 
786  int rc = 0;
787  for (size_t x = 0; x < ARRAYSIZE(inputs); x++)
788  {
789  const struct test_input_t* cur = &inputs[x];
790  const BOOL res = test_default(cur);
791  if (res != cur->expected)
792  rc = -1;
793  }
794  return rc;
795 }