FreeRDP
Loading...
Searching...
No Matches
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
8struct 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
19typedef 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
42static BYTE TEST_NTLM_TIMESTAMP[8] = { 0x33, 0x57, 0xbd, 0xb1, 0x07, 0x8b, 0xcf, 0x01 };
43
44static BYTE TEST_NTLM_CLIENT_CHALLENGE[8] = { 0x20, 0xc0, 0x2b, 0x3d, 0xc0, 0x61, 0xa7, 0x73 };
45
46static BYTE TEST_NTLM_SERVER_CHALLENGE[8] = { 0xa4, 0xf1, 0xba, 0xa6, 0x7c, 0xdc, 0x1a, 0x12 };
47
48static 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
53static 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
65static 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
96static const char* TEST_NTLM_USER = "Username";
97static const char* TEST_NTLM_DOMAIN = "Domain";
98static const char* TEST_NTLM_PASSWORD = "P4ss123!";
99
100// static const char* TEST_NTLM_HASH_STRING = "d5922a65c4d5c082ca444af1be0001db";
101
102static 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
107static 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
110static 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
113static 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
119typedef 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
141static 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
193static 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
261static 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
287static 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
357static 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
367static 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
376static 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
425static 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
452static 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
509static 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
519static 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
528static 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
758fail:
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
770int 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}