FreeRDP
Loading...
Searching...
No Matches
sspi_winpr.c
1
21#include <winpr/config.h>
22#include <winpr/assert.h>
23#include <winpr/windows.h>
24
25#include <winpr/crt.h>
26#include <winpr/sspi.h>
27#include <winpr/ssl.h>
28#include <winpr/print.h>
29
30#include "sspi.h"
31
32#include "sspi_winpr.h"
33
34#include "../utils.h"
35#include "../log.h"
36#define TAG WINPR_TAG("sspi")
37
38/* Authentication Functions: http://msdn.microsoft.com/en-us/library/windows/desktop/aa374731/ */
39
40#include "NTLM/ntlm.h"
41#include "NTLM/ntlm_export.h"
42#include "CredSSP/credssp.h"
43#include "Kerberos/kerberos.h"
44#include "Negotiate/negotiate.h"
45#include "Schannel/schannel.h"
46
47static const SecPkgInfoA* SecPkgInfoA_LIST[] = { &NTLM_SecPkgInfoA, &KERBEROS_SecPkgInfoA,
48 &NEGOTIATE_SecPkgInfoA, &CREDSSP_SecPkgInfoA,
49 &SCHANNEL_SecPkgInfoA };
50
51static const SecPkgInfoW* SecPkgInfoW_LIST[] = { &NTLM_SecPkgInfoW, &KERBEROS_SecPkgInfoW,
52 &NEGOTIATE_SecPkgInfoW, &CREDSSP_SecPkgInfoW,
53 &SCHANNEL_SecPkgInfoW };
54
55typedef struct
56{
57 const SEC_CHAR* Name;
58 const SecurityFunctionTableA* SecurityFunctionTable;
59} SecurityFunctionTableA_NAME;
60
61typedef struct
62{
63 const SEC_WCHAR* Name;
64 const SecurityFunctionTableW* SecurityFunctionTable;
65} SecurityFunctionTableW_NAME;
66
67static const SecurityFunctionTableA_NAME SecurityFunctionTableA_NAME_LIST[] = {
68 { "NTLM", &NTLM_SecurityFunctionTableA },
69 { "Kerberos", &KERBEROS_SecurityFunctionTableA },
70 { "Negotiate", &NEGOTIATE_SecurityFunctionTableA },
71 { "CREDSSP", &CREDSSP_SecurityFunctionTableA },
72 { "Schannel", &SCHANNEL_SecurityFunctionTableA }
73};
74
75static WCHAR BUFFER_NAME_LIST_W[5][32] = WINPR_C_ARRAY_INIT;
76
77static const SecurityFunctionTableW_NAME SecurityFunctionTableW_NAME_LIST[] = {
78 { BUFFER_NAME_LIST_W[0], &NTLM_SecurityFunctionTableW },
79 { BUFFER_NAME_LIST_W[1], &KERBEROS_SecurityFunctionTableW },
80 { BUFFER_NAME_LIST_W[2], &NEGOTIATE_SecurityFunctionTableW },
81 { BUFFER_NAME_LIST_W[3], &CREDSSP_SecurityFunctionTableW },
82 { BUFFER_NAME_LIST_W[4], &SCHANNEL_SecurityFunctionTableW }
83};
84
85typedef struct
86{
87 void* contextBuffer;
88 UINT32 allocatorIndex;
89} CONTEXT_BUFFER_ALLOC_ENTRY;
90
91typedef struct
92{
93 UINT32 cEntries;
94 UINT32 cMaxEntries;
95 CONTEXT_BUFFER_ALLOC_ENTRY* entries;
96} CONTEXT_BUFFER_ALLOC_TABLE;
97
98static CONTEXT_BUFFER_ALLOC_TABLE ContextBufferAllocTable = WINPR_C_ARRAY_INIT;
99
100static int sspi_ContextBufferAllocTableNew(void)
101{
102 size_t size = 0;
103 ContextBufferAllocTable.entries = nullptr;
104 ContextBufferAllocTable.cEntries = 0;
105 ContextBufferAllocTable.cMaxEntries = 4;
106 size = sizeof(CONTEXT_BUFFER_ALLOC_ENTRY) * ContextBufferAllocTable.cMaxEntries;
107 ContextBufferAllocTable.entries = (CONTEXT_BUFFER_ALLOC_ENTRY*)calloc(1, size);
108
109 if (!ContextBufferAllocTable.entries)
110 return -1;
111
112 return 1;
113}
114
115static int sspi_ContextBufferAllocTableGrow(void)
116{
117 size_t size = 0;
118 CONTEXT_BUFFER_ALLOC_ENTRY* entries = nullptr;
119 ContextBufferAllocTable.cEntries = 0;
120 ContextBufferAllocTable.cMaxEntries *= 2;
121 size = sizeof(CONTEXT_BUFFER_ALLOC_ENTRY) * ContextBufferAllocTable.cMaxEntries;
122
123 if (!size)
124 return -1;
125
126 entries = (CONTEXT_BUFFER_ALLOC_ENTRY*)realloc(ContextBufferAllocTable.entries, size);
127
128 if (!entries)
129 {
130 free(ContextBufferAllocTable.entries);
131 return -1;
132 }
133
134 ContextBufferAllocTable.entries = entries;
135 ZeroMemory((void*)&ContextBufferAllocTable.entries[ContextBufferAllocTable.cMaxEntries / 2],
136 size / 2);
137 return 1;
138}
139
140static void sspi_ContextBufferAllocTableFree(void)
141{
142 if (ContextBufferAllocTable.cEntries != 0)
143 WLog_ERR(TAG, "ContextBufferAllocTable.entries == %" PRIu32,
144 ContextBufferAllocTable.cEntries);
145
146 ContextBufferAllocTable.cEntries = ContextBufferAllocTable.cMaxEntries = 0;
147 free(ContextBufferAllocTable.entries);
148 ContextBufferAllocTable.entries = nullptr;
149}
150
151void* sspi_ContextBufferAlloc(UINT32 allocatorIndex, size_t size)
152{
153 void* contextBuffer = nullptr;
154
155 for (UINT32 index = 0; index < ContextBufferAllocTable.cMaxEntries; index++)
156 {
157 if (!ContextBufferAllocTable.entries[index].contextBuffer)
158 {
159 contextBuffer = calloc(1, size);
160
161 if (!contextBuffer)
162 return nullptr;
163
164 ContextBufferAllocTable.cEntries++;
165 ContextBufferAllocTable.entries[index].contextBuffer = contextBuffer;
166 ContextBufferAllocTable.entries[index].allocatorIndex = allocatorIndex;
167 return ContextBufferAllocTable.entries[index].contextBuffer;
168 }
169 }
170
171 /* no available entry was found, the table needs to be grown */
172
173 if (sspi_ContextBufferAllocTableGrow() < 0)
174 return nullptr;
175
176 /* the next call to sspi_ContextBufferAlloc() should now succeed */
177 return sspi_ContextBufferAlloc(allocatorIndex, size);
178}
179
180SSPI_CREDENTIALS* sspi_CredentialsNew(void)
181{
182 SSPI_CREDENTIALS* credentials = (SSPI_CREDENTIALS*)calloc(1, sizeof(SSPI_CREDENTIALS));
183 if (!credentials)
184 return nullptr;
185
186 credentials->ntlmSettingsV2 = sspi_AllocSecNtlmSettings();
187 if (!credentials->ntlmSettingsV2)
188 {
189 sspi_CredentialsFree(credentials);
190 return nullptr;
191 }
192
193 return credentials;
194}
195
196void sspi_CredentialsFree(SSPI_CREDENTIALS* credentials)
197{
198 if (!credentials)
199 return;
200
201 size_t userLength = credentials->identity.UserLength;
202 size_t domainLength = credentials->identity.DomainLength;
203 size_t passwordLength = credentials->identity.PasswordLength;
204
205 if (credentials->identity.Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
206 {
207 userLength *= 2;
208 domainLength *= 2;
209 passwordLength *= 2;
210 }
211
212 if (credentials->identity.User)
213 memset(credentials->identity.User, 0, userLength);
214 if (credentials->identity.Domain)
215 memset(credentials->identity.Domain, 0, domainLength);
216 if (credentials->identity.Password)
217 memset(credentials->identity.Password, 0, passwordLength);
218 free(credentials->identity.User);
219 free(credentials->identity.Domain);
220 free(credentials->identity.Password);
221 sspi_FreeSecNtlmSettings(credentials->ntlmSettingsV2);
222
223 free(credentials);
224}
225
226void* sspi_SecBufferAlloc(PSecBuffer SecBuffer, ULONG size)
227{
228 if (!SecBuffer)
229 return nullptr;
230
231 SecBuffer->pvBuffer = calloc(1, size);
232
233 if (!SecBuffer->pvBuffer)
234 return nullptr;
235
236 SecBuffer->cbBuffer = size;
237 return SecBuffer->pvBuffer;
238}
239
240void sspi_SecBufferFree(PSecBuffer SecBuffer)
241{
242 if (!SecBuffer)
243 return;
244
245 if (SecBuffer->pvBuffer)
246 memset(SecBuffer->pvBuffer, 0, SecBuffer->cbBuffer);
247
248 free(SecBuffer->pvBuffer);
249 SecBuffer->pvBuffer = nullptr;
250 SecBuffer->cbBuffer = 0;
251}
252
253SecHandle* sspi_SecureHandleAlloc(void)
254{
255 SecHandle* handle = (SecHandle*)calloc(1, sizeof(SecHandle));
256
257 if (!handle)
258 return nullptr;
259
260 SecInvalidateHandle(handle);
261 return handle;
262}
263
264void* sspi_SecureHandleGetLowerPointer(SecHandle* handle)
265{
266 void* pointer = nullptr;
267
268 if (!handle || !SecIsValidHandle(handle) || !handle->dwLower)
269 return nullptr;
270
271 pointer = (void*)~((size_t)handle->dwLower);
272 return pointer;
273}
274
275void sspi_SecureHandleInvalidate(SecHandle* handle)
276{
277 if (!handle)
278 return;
279
280 handle->dwLower = 0;
281 handle->dwUpper = 0;
282}
283
284void sspi_SecureHandleSetLowerPointer(SecHandle* handle, void* pointer)
285{
286 if (!handle)
287 return;
288
289 handle->dwLower = (ULONG_PTR)(~((size_t)pointer));
290}
291
292void* sspi_SecureHandleGetUpperPointer(SecHandle* handle)
293{
294 void* pointer = nullptr;
295
296 if (!handle || !SecIsValidHandle(handle) || !handle->dwUpper)
297 return nullptr;
298
299 pointer = (void*)~((size_t)handle->dwUpper);
300 return pointer;
301}
302
303void sspi_SecureHandleSetUpperPointer(SecHandle* handle, void* pointer)
304{
305 if (!handle)
306 return;
307
308 handle->dwUpper = (ULONG_PTR)(~((size_t)pointer));
309}
310
311SSPI_PACKAGE_ID sspi_SecureHandleGetPackageId(SecHandle* handle)
312{
313 if (!handle || !SecIsValidHandle(handle) || !handle->dwUpper)
314 return SSPI_PACKAGE_NONE;
315
316 return (SSPI_PACKAGE_ID)(~((size_t)handle->dwUpper));
317}
318
319void sspi_SecureHandleSetPackageId(SecHandle* handle, SSPI_PACKAGE_ID id)
320{
321 if (!handle)
322 return;
323
324 handle->dwUpper = (ULONG_PTR)(~((size_t)id));
325}
326
327void sspi_SecureHandleFree(SecHandle* handle)
328{
329 free(handle);
330}
331
332int sspi_SetAuthIdentityW(SEC_WINNT_AUTH_IDENTITY* identity, const WCHAR* user, const WCHAR* domain,
333 const WCHAR* password)
334{
335 return sspi_SetAuthIdentityWithLengthW(identity, user, user ? _wcslen(user) : 0, domain,
336 domain ? _wcslen(domain) : 0, password,
337 password ? _wcslen(password) : 0);
338}
339
340static BOOL copy(WCHAR** dst, ULONG* dstLen, const WCHAR* what, size_t len)
341{
342 WINPR_ASSERT(dst);
343 WINPR_ASSERT(dstLen);
344
345 *dst = nullptr;
346 *dstLen = 0;
347
348 if (len > UINT32_MAX)
349 return FALSE;
350
351 /* Case what="" and len=0 should allocate an empty string */
352 if (!what && (len != 0))
353 return FALSE;
354 if (!what && (len == 0))
355 return TRUE;
356
357 *dst = calloc(sizeof(WCHAR), len + 1);
358 if (!*dst)
359 return FALSE;
360
361 memcpy(*dst, what, len * sizeof(WCHAR));
362 *dstLen = WINPR_ASSERTING_INT_CAST(UINT32, len);
363 return TRUE;
364}
365
366int sspi_SetAuthIdentityWithLengthW(SEC_WINNT_AUTH_IDENTITY* identity, const WCHAR* user,
367 size_t userLen, const WCHAR* domain, size_t domainLen,
368 const WCHAR* password, size_t passwordLen)
369{
370 WINPR_ASSERT(identity);
371 sspi_FreeAuthIdentity(identity);
372 identity->Flags &= (uint32_t)~SEC_WINNT_AUTH_IDENTITY_ANSI;
373 identity->Flags |= SEC_WINNT_AUTH_IDENTITY_UNICODE;
374
375 if (!copy(&identity->User, &identity->UserLength, user, userLen))
376 return -1;
377
378 if (!copy(&identity->Domain, &identity->DomainLength, domain, domainLen))
379 return -1;
380
381 if (!copy(&identity->Password, &identity->PasswordLength, password, passwordLen))
382 return -1;
383
384 return 1;
385}
386
387int sspi_SetAuthIdentityA(SEC_WINNT_AUTH_IDENTITY* identity, const char* user, const char* domain,
388 const char* password)
389{
390 int rc = 0;
391 size_t unicodeUserLenW = 0;
392 size_t unicodeDomainLenW = 0;
393 size_t unicodePasswordLenW = 0;
394 LPWSTR unicodeUser = nullptr;
395 LPWSTR unicodeDomain = nullptr;
396 LPWSTR unicodePassword = nullptr;
397
398 if (user)
399 unicodeUser = ConvertUtf8ToWCharAlloc(user, &unicodeUserLenW);
400
401 if (domain)
402 unicodeDomain = ConvertUtf8ToWCharAlloc(domain, &unicodeDomainLenW);
403
404 if (password)
405 unicodePassword = ConvertUtf8ToWCharAlloc(password, &unicodePasswordLenW);
406
407 rc = sspi_SetAuthIdentityWithLengthW(identity, unicodeUser, unicodeUserLenW, unicodeDomain,
408 unicodeDomainLenW, unicodePassword, unicodePasswordLenW);
409
410 winpr_znfree(unicodeUser, unicodeUserLenW * sizeof(WCHAR));
411 winpr_znfree(unicodeDomain, unicodeDomainLenW * sizeof(WCHAR));
412 winpr_znfree(unicodePassword, unicodePasswordLenW * sizeof(WCHAR));
413 return rc;
414}
415
416UINT32 sspi_GetAuthIdentityVersion(const void* identity)
417{
418 UINT32 version = 0;
419
420 if (!identity)
421 return 0;
422
423 version = *((const UINT32*)identity);
424
425 if ((version == SEC_WINNT_AUTH_IDENTITY_VERSION) ||
426 (version == SEC_WINNT_AUTH_IDENTITY_VERSION_2))
427 {
428 return version;
429 }
430
431 return 0; // SEC_WINNT_AUTH_IDENTITY (no version)
432}
433
434UINT32 sspi_GetAuthIdentityFlags(const void* identity)
435{
436 UINT32 version = 0;
437 UINT32 flags = 0;
438
439 if (!identity)
440 return 0;
441
442 version = sspi_GetAuthIdentityVersion(identity);
443
444 if (version == SEC_WINNT_AUTH_IDENTITY_VERSION)
445 {
446 flags = ((const SEC_WINNT_AUTH_IDENTITY_EX*)identity)->Flags;
447 }
448 else if (version == SEC_WINNT_AUTH_IDENTITY_VERSION_2)
449 {
450 flags = ((const SEC_WINNT_AUTH_IDENTITY_EX2*)identity)->Flags;
451 }
452 else // SEC_WINNT_AUTH_IDENTITY
453 {
454 flags = ((const SEC_WINNT_AUTH_IDENTITY*)identity)->Flags;
455 }
456
457 return flags;
458}
459
460BOOL sspi_GetAuthIdentityUserDomainW(const void* identity, const WCHAR** pUser, UINT32* pUserLength,
461 const WCHAR** pDomain, UINT32* pDomainLength)
462{
463 UINT32 version = 0;
464
465 if (!identity)
466 return FALSE;
467
468 version = sspi_GetAuthIdentityVersion(identity);
469
470 if (version == SEC_WINNT_AUTH_IDENTITY_VERSION)
471 {
472 const SEC_WINNT_AUTH_IDENTITY_EXW* id = (const SEC_WINNT_AUTH_IDENTITY_EXW*)identity;
473 *pUser = (const WCHAR*)id->User;
474 *pUserLength = id->UserLength;
475 *pDomain = (const WCHAR*)id->Domain;
476 *pDomainLength = id->DomainLength;
477 }
478 else if (version == SEC_WINNT_AUTH_IDENTITY_VERSION_2)
479 {
480 const SEC_WINNT_AUTH_IDENTITY_EX2* id = (const SEC_WINNT_AUTH_IDENTITY_EX2*)identity;
481 UINT32 UserOffset = id->UserOffset;
482 UINT32 DomainOffset = id->DomainOffset;
483 *pUser = WINPR_PACKED_ALIGN_CAST(const WCHAR*, &((const uint8_t*)identity)[UserOffset]);
484 *pUserLength = id->UserLength / 2;
485 *pDomain = WINPR_PACKED_ALIGN_CAST(const WCHAR*, &((const uint8_t*)identity)[DomainOffset]);
486 *pDomainLength = id->DomainLength / 2;
487 }
488 else // SEC_WINNT_AUTH_IDENTITY
489 {
490 const SEC_WINNT_AUTH_IDENTITY_W* id = (const SEC_WINNT_AUTH_IDENTITY_W*)identity;
491 *pUser = (const WCHAR*)id->User;
492 *pUserLength = id->UserLength;
493 *pDomain = (const WCHAR*)id->Domain;
494 *pDomainLength = id->DomainLength;
495 }
496
497 return TRUE;
498}
499
500BOOL sspi_GetAuthIdentityUserDomainA(const void* identity, const char** pUser, UINT32* pUserLength,
501 const char** pDomain, UINT32* pDomainLength)
502{
503 UINT32 version = 0;
504
505 if (!identity)
506 return FALSE;
507
508 version = sspi_GetAuthIdentityVersion(identity);
509
510 if (version == SEC_WINNT_AUTH_IDENTITY_VERSION)
511 {
512 const SEC_WINNT_AUTH_IDENTITY_EXA* id = (const SEC_WINNT_AUTH_IDENTITY_EXA*)identity;
513 *pUser = (const char*)id->User;
514 *pUserLength = id->UserLength;
515 *pDomain = (const char*)id->Domain;
516 *pDomainLength = id->DomainLength;
517 }
518 else if (version == SEC_WINNT_AUTH_IDENTITY_VERSION_2)
519 {
520 const SEC_WINNT_AUTH_IDENTITY_EX2* id = (const SEC_WINNT_AUTH_IDENTITY_EX2*)identity;
521 UINT32 UserOffset = id->UserOffset;
522 UINT32 DomainOffset = id->DomainOffset;
523 *pUser = (const char*)&((const uint8_t*)identity)[UserOffset];
524 *pUserLength = id->UserLength;
525 *pDomain = (const char*)&((const uint8_t*)identity)[DomainOffset];
526 *pDomainLength = id->DomainLength;
527 }
528 else // SEC_WINNT_AUTH_IDENTITY
529 {
530 const SEC_WINNT_AUTH_IDENTITY_A* id = (const SEC_WINNT_AUTH_IDENTITY_A*)identity;
531 *pUser = (const char*)id->User;
532 *pUserLength = id->UserLength;
533 *pDomain = (const char*)id->Domain;
534 *pDomainLength = id->DomainLength;
535 }
536
537 return TRUE;
538}
539
540BOOL sspi_GetAuthIdentityPasswordW(const void* identity, const WCHAR** pPassword,
541 UINT32* pPasswordLength)
542{
543 UINT32 version = 0;
544
545 if (!identity)
546 return FALSE;
547
548 version = sspi_GetAuthIdentityVersion(identity);
549
550 if (version == SEC_WINNT_AUTH_IDENTITY_VERSION)
551 {
552 const SEC_WINNT_AUTH_IDENTITY_EXW* id = (const SEC_WINNT_AUTH_IDENTITY_EXW*)identity;
553 *pPassword = (const WCHAR*)id->Password;
554 *pPasswordLength = id->PasswordLength;
555 }
556 else if (version == SEC_WINNT_AUTH_IDENTITY_VERSION_2)
557 {
558 return FALSE; // TODO: packed credentials
559 }
560 else // SEC_WINNT_AUTH_IDENTITY
561 {
562 const SEC_WINNT_AUTH_IDENTITY_W* id = (const SEC_WINNT_AUTH_IDENTITY_W*)identity;
563 *pPassword = (const WCHAR*)id->Password;
564 *pPasswordLength = id->PasswordLength;
565 }
566
567 return TRUE;
568}
569
570BOOL sspi_GetAuthIdentityPasswordA(const void* identity, const char** pPassword,
571 UINT32* pPasswordLength)
572{
573 UINT32 version = 0;
574
575 if (!identity)
576 return FALSE;
577
578 version = sspi_GetAuthIdentityVersion(identity);
579
580 if (version == SEC_WINNT_AUTH_IDENTITY_VERSION)
581 {
582 const SEC_WINNT_AUTH_IDENTITY_EXA* id = (const SEC_WINNT_AUTH_IDENTITY_EXA*)identity;
583 *pPassword = (const char*)id->Password;
584 *pPasswordLength = id->PasswordLength;
585 }
586 else if (version == SEC_WINNT_AUTH_IDENTITY_VERSION_2)
587 {
588 return FALSE; // TODO: packed credentials
589 }
590 else // SEC_WINNT_AUTH_IDENTITY
591 {
592 const SEC_WINNT_AUTH_IDENTITY_A* id = (const SEC_WINNT_AUTH_IDENTITY_A*)identity;
593 *pPassword = (const char*)id->Password;
594 *pPasswordLength = id->PasswordLength;
595 }
596
597 return TRUE;
598}
599
600BOOL sspi_CopyAuthIdentityFieldsA(const SEC_WINNT_AUTH_IDENTITY_INFO* identity, char** pUser,
601 char** pDomain, char** pPassword)
602{
603 BOOL success = FALSE;
604 const char* UserA = nullptr;
605 const char* DomainA = nullptr;
606 const char* PasswordA = nullptr;
607 const WCHAR* UserW = nullptr;
608 const WCHAR* DomainW = nullptr;
609 const WCHAR* PasswordW = nullptr;
610 UINT32 UserLength = 0;
611 UINT32 DomainLength = 0;
612 UINT32 PasswordLength = 0;
613
614 if (!identity || !pUser || !pDomain || !pPassword)
615 return FALSE;
616
617 *pUser = *pDomain = *pPassword = nullptr;
618
619 UINT32 identityFlags = sspi_GetAuthIdentityFlags(identity);
620
621 if ((identityFlags & SEC_WINNT_AUTH_IDENTITY_ANSI) != 0)
622 {
623 if (!sspi_GetAuthIdentityUserDomainA(identity, &UserA, &UserLength, &DomainA,
624 &DomainLength))
625 goto cleanup;
626
627 if (!sspi_GetAuthIdentityPasswordA(identity, &PasswordA, &PasswordLength))
628 goto cleanup;
629
630 if (UserA && UserLength)
631 {
632 *pUser = _strdup(UserA);
633
634 if (!(*pUser))
635 goto cleanup;
636 }
637
638 if (DomainA && DomainLength)
639 {
640 *pDomain = _strdup(DomainA);
641
642 if (!(*pDomain))
643 goto cleanup;
644 }
645
646 if (PasswordA && PasswordLength)
647 {
648 *pPassword = _strdup(PasswordA);
649
650 if (!(*pPassword))
651 goto cleanup;
652 }
653
654 success = TRUE;
655 }
656 else if ((identityFlags & SEC_WINNT_AUTH_IDENTITY_UNICODE) != 0)
657 {
658 if (!sspi_GetAuthIdentityUserDomainW(identity, &UserW, &UserLength, &DomainW,
659 &DomainLength))
660 goto cleanup;
661
662 if (!sspi_GetAuthIdentityPasswordW(identity, &PasswordW, &PasswordLength))
663 goto cleanup;
664
665 if (UserW && (UserLength > 0))
666 {
667 *pUser = ConvertWCharNToUtf8Alloc(UserW, UserLength, nullptr);
668 if (!(*pUser))
669 goto cleanup;
670 }
671
672 if (DomainW && (DomainLength > 0))
673 {
674 *pDomain = ConvertWCharNToUtf8Alloc(DomainW, DomainLength, nullptr);
675 if (!(*pDomain))
676 goto cleanup;
677 }
678
679 if (PasswordW && (PasswordLength > 0))
680 {
681 *pPassword = ConvertWCharNToUtf8Alloc(PasswordW, PasswordLength, nullptr);
682 if (!(*pPassword))
683 goto cleanup;
684 }
685
686 success = TRUE;
687 }
688
689cleanup:
690 return success;
691}
692
693BOOL sspi_CopyAuthIdentityFieldsW(const SEC_WINNT_AUTH_IDENTITY_INFO* identity, WCHAR** pUser,
694 WCHAR** pDomain, WCHAR** pPassword)
695{
696 BOOL success = FALSE;
697 const char* UserA = nullptr;
698 const char* DomainA = nullptr;
699 const char* PasswordA = nullptr;
700 const WCHAR* UserW = nullptr;
701 const WCHAR* DomainW = nullptr;
702 const WCHAR* PasswordW = nullptr;
703 UINT32 UserLength = 0;
704 UINT32 DomainLength = 0;
705 UINT32 PasswordLength = 0;
706
707 if (!identity || !pUser || !pDomain || !pPassword)
708 return FALSE;
709
710 *pUser = *pDomain = *pPassword = nullptr;
711
712 UINT32 identityFlags = sspi_GetAuthIdentityFlags(identity);
713
714 if ((identityFlags & SEC_WINNT_AUTH_IDENTITY_ANSI) != 0)
715 {
716 if (!sspi_GetAuthIdentityUserDomainA(identity, &UserA, &UserLength, &DomainA,
717 &DomainLength))
718 goto cleanup;
719
720 if (!sspi_GetAuthIdentityPasswordA(identity, &PasswordA, &PasswordLength))
721 goto cleanup;
722
723 if (UserA && (UserLength > 0))
724 {
725 WCHAR* ptr = ConvertUtf8NToWCharAlloc(UserA, UserLength, nullptr);
726 *pUser = ptr;
727
728 if (!ptr)
729 goto cleanup;
730 }
731
732 if (DomainA && (DomainLength > 0))
733 {
734 WCHAR* ptr = ConvertUtf8NToWCharAlloc(DomainA, DomainLength, nullptr);
735 *pDomain = ptr;
736 if (!ptr)
737 goto cleanup;
738 }
739
740 if (PasswordA && (PasswordLength > 0))
741 {
742 WCHAR* ptr = ConvertUtf8NToWCharAlloc(PasswordA, PasswordLength, nullptr);
743
744 *pPassword = ptr;
745 if (!ptr)
746 goto cleanup;
747 }
748
749 success = TRUE;
750 }
751 else if ((identityFlags & SEC_WINNT_AUTH_IDENTITY_UNICODE) != 0)
752 {
753 if (!sspi_GetAuthIdentityUserDomainW(identity, &UserW, &UserLength, &DomainW,
754 &DomainLength))
755 goto cleanup;
756
757 if (!sspi_GetAuthIdentityPasswordW(identity, &PasswordW, &PasswordLength))
758 goto cleanup;
759
760 if (UserW && UserLength)
761 {
762 *pUser = winpr_wcsndup(UserW, UserLength / sizeof(WCHAR));
763
764 if (!(*pUser))
765 goto cleanup;
766 }
767
768 if (DomainW && DomainLength)
769 {
770 *pDomain = winpr_wcsndup(DomainW, DomainLength / sizeof(WCHAR));
771
772 if (!(*pDomain))
773 goto cleanup;
774 }
775
776 if (PasswordW && PasswordLength)
777 {
778 *pPassword = winpr_wcsndup(PasswordW, PasswordLength / sizeof(WCHAR));
779
780 if (!(*pPassword))
781 goto cleanup;
782 }
783
784 success = TRUE;
785 }
786
787cleanup:
788 return success;
789}
790
791BOOL sspi_CopyAuthPackageListA(const SEC_WINNT_AUTH_IDENTITY_INFO* identity, char** pPackageList)
792{
793 UINT32 version = 0;
794 UINT32 identityFlags = 0;
795 char* PackageList = nullptr;
796 const char* PackageListA = nullptr;
797 const WCHAR* PackageListW = nullptr;
798 UINT32 PackageListLength = 0;
799 UINT32 PackageListOffset = 0;
800 const void* pAuthData = (const void*)identity;
801
802 if (!pAuthData)
803 return FALSE;
804
805 version = sspi_GetAuthIdentityVersion(pAuthData);
806 identityFlags = sspi_GetAuthIdentityFlags(pAuthData);
807
808 if ((identityFlags & SEC_WINNT_AUTH_IDENTITY_ANSI) != 0)
809 {
810 if (version == SEC_WINNT_AUTH_IDENTITY_VERSION)
811 {
812 const SEC_WINNT_AUTH_IDENTITY_EXA* ad = (const SEC_WINNT_AUTH_IDENTITY_EXA*)pAuthData;
813 PackageListA = (const char*)ad->PackageList;
814 PackageListLength = ad->PackageListLength;
815 }
816
817 if (PackageListA && PackageListLength)
818 {
819 PackageList = _strdup(PackageListA);
820 }
821 }
822 else if ((identityFlags & SEC_WINNT_AUTH_IDENTITY_UNICODE) != 0)
823 {
824 if (version == SEC_WINNT_AUTH_IDENTITY_VERSION)
825 {
826 const SEC_WINNT_AUTH_IDENTITY_EXW* ad = (const SEC_WINNT_AUTH_IDENTITY_EXW*)pAuthData;
827 PackageListW = (const WCHAR*)ad->PackageList;
828 PackageListLength = ad->PackageListLength;
829 }
830 else if (version == SEC_WINNT_AUTH_IDENTITY_VERSION_2)
831 {
832 const SEC_WINNT_AUTH_IDENTITY_EX2* ad = (const SEC_WINNT_AUTH_IDENTITY_EX2*)pAuthData;
833 PackageListOffset = ad->PackageListOffset;
834 PackageListW = WINPR_PACKED_ALIGN_CAST(const WCHAR*,
835 &((const uint8_t*)pAuthData)[PackageListOffset]);
836 PackageListLength = ad->PackageListLength / 2;
837 }
838
839 if (PackageListW && (PackageListLength > 0))
840 PackageList = ConvertWCharNToUtf8Alloc(PackageListW, PackageListLength, nullptr);
841 }
842
843 if (PackageList)
844 {
845 *pPackageList = PackageList;
846 return TRUE;
847 }
848
849 return FALSE;
850}
851
852int sspi_CopyAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity,
853 const SEC_WINNT_AUTH_IDENTITY_INFO* srcIdentity)
854{
855 int status = 0;
856 UINT32 identityFlags = 0;
857 const char* UserA = nullptr;
858 const char* DomainA = nullptr;
859 const char* PasswordA = nullptr;
860 const WCHAR* UserW = nullptr;
861 const WCHAR* DomainW = nullptr;
862 const WCHAR* PasswordW = nullptr;
863 UINT32 UserLength = 0;
864 UINT32 DomainLength = 0;
865 UINT32 PasswordLength = 0;
866
867 sspi_FreeAuthIdentity(identity);
868
869 identityFlags = sspi_GetAuthIdentityFlags(srcIdentity);
870
871 identity->Flags = identityFlags;
872
873 if ((identityFlags & SEC_WINNT_AUTH_IDENTITY_ANSI) != 0)
874 {
875 if (!sspi_GetAuthIdentityUserDomainA(srcIdentity, &UserA, &UserLength, &DomainA,
876 &DomainLength))
877 {
878 return -1;
879 }
880
881 if (!sspi_GetAuthIdentityPasswordA(srcIdentity, &PasswordA, &PasswordLength))
882 {
883 return -1;
884 }
885
886 status = sspi_SetAuthIdentity(identity, UserA, DomainA, PasswordA);
887
888 if (status <= 0)
889 return -1;
890
891 identity->Flags &= (uint32_t)~SEC_WINNT_AUTH_IDENTITY_ANSI;
892 identity->Flags |= SEC_WINNT_AUTH_IDENTITY_UNICODE;
893 return 1;
894 }
895
896 identity->Flags |= SEC_WINNT_AUTH_IDENTITY_UNICODE;
897
898 if (!sspi_GetAuthIdentityUserDomainW(srcIdentity, &UserW, &UserLength, &DomainW, &DomainLength))
899 {
900 return -1;
901 }
902
903 if (!sspi_GetAuthIdentityPasswordW(srcIdentity, &PasswordW, &PasswordLength))
904 {
905 return -1;
906 }
907
908 /* login/password authentication */
909 identity->UserLength = UserLength;
910
911 if (identity->UserLength > 0)
912 {
913 identity->User = (UINT16*)calloc((identity->UserLength + 1), sizeof(WCHAR));
914
915 if (!identity->User)
916 return -1;
917
918 CopyMemory(identity->User, UserW, identity->UserLength * sizeof(WCHAR));
919 identity->User[identity->UserLength] = 0;
920 }
921
922 identity->DomainLength = DomainLength;
923
924 if (identity->DomainLength > 0)
925 {
926 identity->Domain = (UINT16*)calloc((identity->DomainLength + 1), sizeof(WCHAR));
927
928 if (!identity->Domain)
929 return -1;
930
931 CopyMemory(identity->Domain, DomainW, identity->DomainLength * sizeof(WCHAR));
932 identity->Domain[identity->DomainLength] = 0;
933 }
934
935 identity->PasswordLength = PasswordLength;
936
937 if (PasswordW)
938 {
939 identity->Password = (UINT16*)calloc((identity->PasswordLength + 1), sizeof(WCHAR));
940
941 if (!identity->Password)
942 return -1;
943
944 CopyMemory(identity->Password, PasswordW, identity->PasswordLength * sizeof(WCHAR));
945 identity->Password[identity->PasswordLength] = 0;
946 }
947
948 /* End of login/password authentication */
949 return 1;
950}
951
952PSecBuffer sspi_FindSecBuffer(PSecBufferDesc pMessage, ULONG BufferType)
953{
954 PSecBuffer pSecBuffer = nullptr;
955
956 for (UINT32 index = 0; index < pMessage->cBuffers; index++)
957 {
958 if (pMessage->pBuffers[index].BufferType == BufferType)
959 {
960 pSecBuffer = &pMessage->pBuffers[index];
961 break;
962 }
963 }
964
965 return pSecBuffer;
966}
967
968static BOOL WINPR_init(void)
969{
970
971 for (size_t x = 0; x < ARRAYSIZE(SecurityFunctionTableA_NAME_LIST); x++)
972 {
973 const SecurityFunctionTableA_NAME* cur = &SecurityFunctionTableA_NAME_LIST[x];
974 InitializeConstWCharFromUtf8(cur->Name, BUFFER_NAME_LIST_W[x],
975 ARRAYSIZE(BUFFER_NAME_LIST_W[x]));
976 }
977 return TRUE;
978}
979
980static BOOL CALLBACK sspi_init(WINPR_ATTR_UNUSED PINIT_ONCE InitOnce,
981 WINPR_ATTR_UNUSED PVOID Parameter, WINPR_ATTR_UNUSED PVOID* Context)
982{
983 if (!winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT))
984 return FALSE;
985 sspi_ContextBufferAllocTableNew();
986 if (!SCHANNEL_init())
987 return FALSE;
988 if (!KERBEROS_init())
989 return FALSE;
990 if (!NTLM_init())
991 return FALSE;
992 if (!CREDSSP_init())
993 return FALSE;
994 if (!NEGOTIATE_init())
995 return FALSE;
996 return WINPR_init();
997}
998
999void sspi_GlobalInit(void)
1000{
1001 static INIT_ONCE once = INIT_ONCE_STATIC_INIT;
1002 DWORD flags = 0;
1003
1004 /* Dispatch indexes these lists with SSPI_PACKAGE_ID - 1, so every one of them must have
1005 * exactly one entry per package, in the order the enum declares. Adding a package to the
1006 * enum without extending all four lists (and the W name buffers) would otherwise read past
1007 * the end or dispatch to the wrong package, silently. */
1008 WINPR_STATIC_ASSERT(ARRAYSIZE(SecPkgInfoA_LIST) == SSPI_PACKAGE_COUNT - 1);
1009 WINPR_STATIC_ASSERT(ARRAYSIZE(SecPkgInfoW_LIST) == SSPI_PACKAGE_COUNT - 1);
1010 WINPR_STATIC_ASSERT(ARRAYSIZE(SecurityFunctionTableA_NAME_LIST) == SSPI_PACKAGE_COUNT - 1);
1011 WINPR_STATIC_ASSERT(ARRAYSIZE(SecurityFunctionTableW_NAME_LIST) == SSPI_PACKAGE_COUNT - 1);
1012 WINPR_STATIC_ASSERT(ARRAYSIZE(BUFFER_NAME_LIST_W) == SSPI_PACKAGE_COUNT - 1);
1013
1014 if (!InitOnceExecuteOnce(&once, sspi_init, &flags, nullptr))
1015 WLog_ERR(TAG, "InitOnceExecuteOnce failed");
1016}
1017
1018void sspi_GlobalFinish(void)
1019{
1020 sspi_ContextBufferAllocTableFree();
1021}
1022
1023static const SecurityFunctionTableA* sspi_GetSecurityFunctionTableAByNameA(const SEC_CHAR* Name)
1024{
1025 size_t cPackages = ARRAYSIZE(SecPkgInfoA_LIST);
1026
1027 for (size_t index = 0; index < cPackages; index++)
1028 {
1029 if (strcmp(Name, SecurityFunctionTableA_NAME_LIST[index].Name) == 0)
1030 {
1031 return SecurityFunctionTableA_NAME_LIST[index].SecurityFunctionTable;
1032 }
1033 }
1034
1035 return nullptr;
1036}
1037
1038static const SecurityFunctionTableW* sspi_GetSecurityFunctionTableWByNameW(const SEC_WCHAR* Name)
1039{
1040 size_t cPackages = ARRAYSIZE(SecPkgInfoW_LIST);
1041
1042 for (size_t index = 0; index < cPackages; index++)
1043 {
1044 if (_wcscmp(Name, SecurityFunctionTableW_NAME_LIST[index].Name) == 0)
1045 {
1046 return SecurityFunctionTableW_NAME_LIST[index].SecurityFunctionTable;
1047 }
1048 }
1049
1050 return nullptr;
1051}
1052
1053/* Table lookup for the context/credential dispatch wrappers, which identify their package
1054 * by the handle itself. Takes the handle rather than an index so the identifier is read in
1055 * one place instead of at every call site. */
1056WINPR_ATTR_NODISCARD static const SecurityFunctionTableA*
1057sspi_GetSecurityFunctionTableAByHandle(SecHandle* handle)
1058{
1059 const SSPI_PACKAGE_ID id = sspi_SecureHandleGetPackageId(handle);
1060
1061 if ((id < SSPI_PACKAGE_NTLM) || (id > ARRAYSIZE(SecurityFunctionTableA_NAME_LIST)))
1062 return nullptr;
1063
1064 return SecurityFunctionTableA_NAME_LIST[id - 1].SecurityFunctionTable;
1065}
1066
1067WINPR_ATTR_NODISCARD static const SecurityFunctionTableW*
1068sspi_GetSecurityFunctionTableWByHandle(SecHandle* handle)
1069{
1070 const SSPI_PACKAGE_ID id = sspi_SecureHandleGetPackageId(handle);
1071
1072 if ((id < SSPI_PACKAGE_NTLM) || (id > ARRAYSIZE(SecurityFunctionTableW_NAME_LIST)))
1073 return nullptr;
1074
1075 return SecurityFunctionTableW_NAME_LIST[id - 1].SecurityFunctionTable;
1076}
1077
1078static void FreeContextBuffer_EnumerateSecurityPackages(void* contextBuffer);
1079static void FreeContextBuffer_QuerySecurityPackageInfo(void* contextBuffer);
1080
1081void sspi_ContextBufferFree(void* contextBuffer)
1082{
1083 UINT32 allocatorIndex = 0;
1084
1085 for (size_t index = 0; index < ContextBufferAllocTable.cMaxEntries; index++)
1086 {
1087 if (contextBuffer == ContextBufferAllocTable.entries[index].contextBuffer)
1088 {
1089 contextBuffer = ContextBufferAllocTable.entries[index].contextBuffer;
1090 allocatorIndex = ContextBufferAllocTable.entries[index].allocatorIndex;
1091 ContextBufferAllocTable.cEntries--;
1092 ContextBufferAllocTable.entries[index].allocatorIndex = 0;
1093 ContextBufferAllocTable.entries[index].contextBuffer = nullptr;
1094
1095 switch (allocatorIndex)
1096 {
1097 case EnumerateSecurityPackagesIndex:
1098 FreeContextBuffer_EnumerateSecurityPackages(contextBuffer);
1099 break;
1100
1101 case QuerySecurityPackageInfoIndex:
1102 FreeContextBuffer_QuerySecurityPackageInfo(contextBuffer);
1103 break;
1104 default:
1105 break;
1106 }
1107 }
1108 }
1109}
1110
1115/* Package Management */
1116
1117static SECURITY_STATUS SEC_ENTRY winpr_EnumerateSecurityPackagesW(ULONG* pcPackages,
1118 PSecPkgInfoW* ppPackageInfo)
1119{
1120 const size_t cPackages = ARRAYSIZE(SecPkgInfoW_LIST);
1121 const size_t size = sizeof(SecPkgInfoW) * cPackages;
1122 SecPkgInfoW* pPackageInfo =
1123 (SecPkgInfoW*)sspi_ContextBufferAlloc(EnumerateSecurityPackagesIndex, size);
1124
1125 WINPR_ASSERT(cPackages <= UINT32_MAX);
1126
1127 if (!pPackageInfo)
1128 return SEC_E_INSUFFICIENT_MEMORY;
1129
1130 for (size_t index = 0; index < cPackages; index++)
1131 {
1132 pPackageInfo[index].fCapabilities = SecPkgInfoW_LIST[index]->fCapabilities;
1133 pPackageInfo[index].wVersion = SecPkgInfoW_LIST[index]->wVersion;
1134 pPackageInfo[index].wRPCID = SecPkgInfoW_LIST[index]->wRPCID;
1135 pPackageInfo[index].cbMaxToken = SecPkgInfoW_LIST[index]->cbMaxToken;
1136 pPackageInfo[index].Name = _wcsdup(SecPkgInfoW_LIST[index]->Name);
1137 pPackageInfo[index].Comment = _wcsdup(SecPkgInfoW_LIST[index]->Comment);
1138 }
1139
1140 *(pcPackages) = (UINT32)cPackages;
1141 *(ppPackageInfo) = pPackageInfo;
1142 return SEC_E_OK;
1143}
1144
1145static SECURITY_STATUS SEC_ENTRY winpr_EnumerateSecurityPackagesA(ULONG* pcPackages,
1146 PSecPkgInfoA* ppPackageInfo)
1147{
1148 const size_t cPackages = ARRAYSIZE(SecPkgInfoA_LIST);
1149 const size_t size = sizeof(SecPkgInfoA) * cPackages;
1150 SecPkgInfoA* pPackageInfo =
1151 (SecPkgInfoA*)sspi_ContextBufferAlloc(EnumerateSecurityPackagesIndex, size);
1152
1153 WINPR_ASSERT(cPackages <= UINT32_MAX);
1154
1155 if (!pPackageInfo)
1156 return SEC_E_INSUFFICIENT_MEMORY;
1157
1158 for (size_t index = 0; index < cPackages; index++)
1159 {
1160 pPackageInfo[index].fCapabilities = SecPkgInfoA_LIST[index]->fCapabilities;
1161 pPackageInfo[index].wVersion = SecPkgInfoA_LIST[index]->wVersion;
1162 pPackageInfo[index].wRPCID = SecPkgInfoA_LIST[index]->wRPCID;
1163 pPackageInfo[index].cbMaxToken = SecPkgInfoA_LIST[index]->cbMaxToken;
1164 pPackageInfo[index].Name = _strdup(SecPkgInfoA_LIST[index]->Name);
1165 pPackageInfo[index].Comment = _strdup(SecPkgInfoA_LIST[index]->Comment);
1166
1167 if (!pPackageInfo[index].Name || !pPackageInfo[index].Comment)
1168 {
1169 sspi_ContextBufferFree(pPackageInfo);
1170 return SEC_E_INSUFFICIENT_MEMORY;
1171 }
1172 }
1173
1174 *(pcPackages) = (UINT32)cPackages;
1175 *(ppPackageInfo) = pPackageInfo;
1176 return SEC_E_OK;
1177}
1178
1179static void FreeContextBuffer_EnumerateSecurityPackages(void* contextBuffer)
1180{
1181 SecPkgInfoA* pPackageInfo = (SecPkgInfoA*)contextBuffer;
1182 size_t cPackages = ARRAYSIZE(SecPkgInfoA_LIST);
1183
1184 if (!pPackageInfo)
1185 return;
1186
1187 for (size_t index = 0; index < cPackages; index++)
1188 {
1189 free(pPackageInfo[index].Name);
1190 free(pPackageInfo[index].Comment);
1191 }
1192
1193 free(pPackageInfo);
1194}
1195
1196static SECURITY_STATUS SEC_ENTRY winpr_QuerySecurityPackageInfoW(SEC_WCHAR* pszPackageName,
1197 PSecPkgInfoW* ppPackageInfo)
1198{
1199 size_t cPackages = ARRAYSIZE(SecPkgInfoW_LIST);
1200
1201 for (size_t index = 0; index < cPackages; index++)
1202 {
1203 if (_wcscmp(pszPackageName, SecPkgInfoW_LIST[index]->Name) == 0)
1204 {
1205 size_t size = sizeof(SecPkgInfoW);
1206 SecPkgInfoW* pPackageInfo =
1207 (SecPkgInfoW*)sspi_ContextBufferAlloc(QuerySecurityPackageInfoIndex, size);
1208
1209 if (!pPackageInfo)
1210 return SEC_E_INSUFFICIENT_MEMORY;
1211
1212 pPackageInfo->fCapabilities = SecPkgInfoW_LIST[index]->fCapabilities;
1213 pPackageInfo->wVersion = SecPkgInfoW_LIST[index]->wVersion;
1214 pPackageInfo->wRPCID = SecPkgInfoW_LIST[index]->wRPCID;
1215 pPackageInfo->cbMaxToken = SecPkgInfoW_LIST[index]->cbMaxToken;
1216 pPackageInfo->Name = _wcsdup(SecPkgInfoW_LIST[index]->Name);
1217 pPackageInfo->Comment = _wcsdup(SecPkgInfoW_LIST[index]->Comment);
1218 *(ppPackageInfo) = pPackageInfo;
1219 return SEC_E_OK;
1220 }
1221 }
1222
1223 *(ppPackageInfo) = nullptr;
1224 return SEC_E_SECPKG_NOT_FOUND;
1225}
1226
1227static SECURITY_STATUS SEC_ENTRY winpr_QuerySecurityPackageInfoA(SEC_CHAR* pszPackageName,
1228 PSecPkgInfoA* ppPackageInfo)
1229{
1230 size_t cPackages = ARRAYSIZE(SecPkgInfoA_LIST);
1231
1232 for (size_t index = 0; index < cPackages; index++)
1233 {
1234 if (strcmp(pszPackageName, SecPkgInfoA_LIST[index]->Name) == 0)
1235 {
1236 size_t size = sizeof(SecPkgInfoA);
1237 SecPkgInfoA* pPackageInfo =
1238 (SecPkgInfoA*)sspi_ContextBufferAlloc(QuerySecurityPackageInfoIndex, size);
1239
1240 if (!pPackageInfo)
1241 return SEC_E_INSUFFICIENT_MEMORY;
1242
1243 pPackageInfo->fCapabilities = SecPkgInfoA_LIST[index]->fCapabilities;
1244 pPackageInfo->wVersion = SecPkgInfoA_LIST[index]->wVersion;
1245 pPackageInfo->wRPCID = SecPkgInfoA_LIST[index]->wRPCID;
1246 pPackageInfo->cbMaxToken = SecPkgInfoA_LIST[index]->cbMaxToken;
1247 pPackageInfo->Name = _strdup(SecPkgInfoA_LIST[index]->Name);
1248 pPackageInfo->Comment = _strdup(SecPkgInfoA_LIST[index]->Comment);
1249
1250 if (!pPackageInfo->Name || !pPackageInfo->Comment)
1251 {
1252 sspi_ContextBufferFree(pPackageInfo);
1253 return SEC_E_INSUFFICIENT_MEMORY;
1254 }
1255
1256 *(ppPackageInfo) = pPackageInfo;
1257 return SEC_E_OK;
1258 }
1259 }
1260
1261 *(ppPackageInfo) = nullptr;
1262 return SEC_E_SECPKG_NOT_FOUND;
1263}
1264
1265void FreeContextBuffer_QuerySecurityPackageInfo(void* contextBuffer)
1266{
1267 SecPkgInfo* pPackageInfo = (SecPkgInfo*)contextBuffer;
1268
1269 if (!pPackageInfo)
1270 return;
1271
1272 free(pPackageInfo->Name);
1273 free(pPackageInfo->Comment);
1274 free(pPackageInfo);
1275}
1276
1277#define log_status(what, status) log_status_((what), (status), __FILE__, __func__, __LINE__)
1278static SECURITY_STATUS log_status_(const char* what, SECURITY_STATUS status, const char* file,
1279 const char* fkt, size_t line)
1280{
1281 if (IsSecurityStatusError(status))
1282 {
1283 const DWORD level = WLOG_WARN;
1284 static wLog* log = nullptr;
1285 if (!log)
1286 log = WLog_Get(TAG);
1287
1288 if (WLog_IsLevelActive(log, level))
1289 {
1290 WLog_PrintTextMessage(log, level, line, file, fkt, "%s status %s [0x%08" PRIx32 "]",
1291 what, GetSecurityStatusString(status),
1292 WINPR_CXX_COMPAT_CAST(uint32_t, status));
1293 }
1294 }
1295 return status;
1296}
1297
1298/* Credential Management */
1299
1300static SECURITY_STATUS SEC_ENTRY winpr_AcquireCredentialsHandleW(
1301 SEC_WCHAR* pszPrincipal, SEC_WCHAR* pszPackage, ULONG fCredentialUse, void* pvLogonID,
1302 void* pAuthData, SEC_GET_KEY_FN pGetKeyFn, void* pvGetKeyArgument, PCredHandle phCredential,
1303 PTimeStamp ptsExpiry)
1304{
1305 const SecurityFunctionTableW* table = sspi_GetSecurityFunctionTableWByNameW(pszPackage);
1306
1307 if (!table)
1308 return SEC_E_SECPKG_NOT_FOUND;
1309
1310 if (!table->AcquireCredentialsHandleW)
1311 {
1312 WLog_WARN(TAG, "Security module does not provide an implementation");
1313 return SEC_E_UNSUPPORTED_FUNCTION;
1314 }
1315
1316 SECURITY_STATUS status = table->AcquireCredentialsHandleW(
1317 pszPrincipal, pszPackage, fCredentialUse, pvLogonID, pAuthData, pGetKeyFn, pvGetKeyArgument,
1318 phCredential, ptsExpiry);
1319 return log_status("AcquireCredentialsHandleW", status);
1320}
1321
1322static SECURITY_STATUS SEC_ENTRY winpr_AcquireCredentialsHandleA(
1323 SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage, ULONG fCredentialUse, void* pvLogonID,
1324 void* pAuthData, SEC_GET_KEY_FN pGetKeyFn, void* pvGetKeyArgument, PCredHandle phCredential,
1325 PTimeStamp ptsExpiry)
1326{
1327 const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByNameA(pszPackage);
1328
1329 if (!table)
1330 return SEC_E_SECPKG_NOT_FOUND;
1331
1332 if (!table->AcquireCredentialsHandleA)
1333 {
1334 WLog_WARN(TAG, "Security module does not provide an implementation");
1335 return SEC_E_UNSUPPORTED_FUNCTION;
1336 }
1337
1338 SECURITY_STATUS status = table->AcquireCredentialsHandleA(
1339 pszPrincipal, pszPackage, fCredentialUse, pvLogonID, pAuthData, pGetKeyFn, pvGetKeyArgument,
1340 phCredential, ptsExpiry);
1341 return log_status("AcquireCredentialsHandleA", status);
1342}
1343
1344static SECURITY_STATUS SEC_ENTRY winpr_ExportSecurityContext(PCtxtHandle phContext, ULONG fFlags,
1345 PSecBuffer pPackedContext,
1346 HANDLE* pToken)
1347{
1348 const SecurityFunctionTableW* table = sspi_GetSecurityFunctionTableWByHandle(phContext);
1349
1350 if (!table)
1351 return SEC_E_SECPKG_NOT_FOUND;
1352
1353 if (!table->ExportSecurityContext)
1354 {
1355 WLog_WARN(TAG, "Security module does not provide an implementation");
1356 return SEC_E_UNSUPPORTED_FUNCTION;
1357 }
1358
1359 SECURITY_STATUS status =
1360 table->ExportSecurityContext(phContext, fFlags, pPackedContext, pToken);
1361 return log_status("ExportSecurityContext", status);
1362}
1363
1364static SECURITY_STATUS SEC_ENTRY winpr_FreeCredentialsHandle(PCredHandle phCredential)
1365{
1366 const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByHandle(phCredential);
1367
1368 if (!table)
1369 return SEC_E_SECPKG_NOT_FOUND;
1370
1371 if (!table->FreeCredentialsHandle)
1372 {
1373 WLog_WARN(TAG, "Security module does not provide an implementation");
1374 return SEC_E_UNSUPPORTED_FUNCTION;
1375 }
1376
1377 SECURITY_STATUS status = table->FreeCredentialsHandle(phCredential);
1378 return log_status("FreeCredentialsHandle", status);
1379}
1380
1381static SECURITY_STATUS SEC_ENTRY winpr_ImportSecurityContextW(SEC_WCHAR* pszPackage,
1382 PSecBuffer pPackedContext,
1383 HANDLE pToken, PCtxtHandle phContext)
1384{
1385 const SecurityFunctionTableW* table = sspi_GetSecurityFunctionTableWByHandle(phContext);
1386
1387 if (!table)
1388 return SEC_E_SECPKG_NOT_FOUND;
1389
1390 if (!table->ImportSecurityContextW)
1391 {
1392 WLog_WARN(TAG, "Security module does not provide an implementation");
1393 return SEC_E_UNSUPPORTED_FUNCTION;
1394 }
1395
1396 SECURITY_STATUS status =
1397 table->ImportSecurityContextW(pszPackage, pPackedContext, pToken, phContext);
1398 return log_status("ImportSecurityContextW", status);
1399}
1400
1401static SECURITY_STATUS SEC_ENTRY winpr_ImportSecurityContextA(SEC_CHAR* pszPackage,
1402 PSecBuffer pPackedContext,
1403 HANDLE pToken, PCtxtHandle phContext)
1404{
1405 const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByHandle(phContext);
1406
1407 if (!table)
1408 return SEC_E_SECPKG_NOT_FOUND;
1409
1410 if (!table->ImportSecurityContextA)
1411 {
1412 WLog_WARN(TAG, "Security module does not provide an implementation");
1413 return SEC_E_UNSUPPORTED_FUNCTION;
1414 }
1415
1416 SECURITY_STATUS status =
1417 table->ImportSecurityContextA(pszPackage, pPackedContext, pToken, phContext);
1418 return log_status("ImportSecurityContextA", status);
1419}
1420
1421static SECURITY_STATUS SEC_ENTRY winpr_QueryCredentialsAttributesW(PCredHandle phCredential,
1422 ULONG ulAttribute, void* pBuffer)
1423{
1424 const SecurityFunctionTableW* table = sspi_GetSecurityFunctionTableWByHandle(phCredential);
1425
1426 if (!table)
1427 return SEC_E_SECPKG_NOT_FOUND;
1428
1429 if (!table->QueryCredentialsAttributesW)
1430 {
1431 WLog_WARN(TAG, "Security module does not provide an implementation");
1432 return SEC_E_UNSUPPORTED_FUNCTION;
1433 }
1434
1435 SECURITY_STATUS status = table->QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
1436 return log_status("QueryCredentialsAttributesW", status);
1437}
1438
1439static SECURITY_STATUS SEC_ENTRY winpr_QueryCredentialsAttributesA(PCredHandle phCredential,
1440 ULONG ulAttribute, void* pBuffer)
1441{
1442 const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByHandle(phCredential);
1443
1444 if (!table)
1445 return SEC_E_SECPKG_NOT_FOUND;
1446
1447 if (!table->QueryCredentialsAttributesA)
1448 {
1449 WLog_WARN(TAG, "Security module does not provide an implementation");
1450 return SEC_E_UNSUPPORTED_FUNCTION;
1451 }
1452
1453 SECURITY_STATUS status = table->QueryCredentialsAttributesA(phCredential, ulAttribute, pBuffer);
1454 return log_status("QueryCredentialsAttributesA", status);
1455}
1456
1457static SECURITY_STATUS SEC_ENTRY winpr_SetCredentialsAttributesW(PCredHandle phCredential,
1458 ULONG ulAttribute, void* pBuffer,
1459 ULONG cbBuffer)
1460{
1461 const SecurityFunctionTableW* table = sspi_GetSecurityFunctionTableWByHandle(phCredential);
1462
1463 if (!table)
1464 return SEC_E_SECPKG_NOT_FOUND;
1465
1466 if (!table->SetCredentialsAttributesW)
1467 {
1468 WLog_WARN(TAG, "Security module does not provide an implementation");
1469 return SEC_E_UNSUPPORTED_FUNCTION;
1470 }
1471
1472 SECURITY_STATUS status =
1473 table->SetCredentialsAttributesW(phCredential, ulAttribute, pBuffer, cbBuffer);
1474 return log_status("SetCredentialsAttributesW", status);
1475}
1476
1477static SECURITY_STATUS SEC_ENTRY winpr_SetCredentialsAttributesA(PCredHandle phCredential,
1478 ULONG ulAttribute, void* pBuffer,
1479 ULONG cbBuffer)
1480{
1481 const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByHandle(phCredential);
1482
1483 if (!table)
1484 return SEC_E_SECPKG_NOT_FOUND;
1485
1486 if (!table->SetCredentialsAttributesA)
1487 {
1488 WLog_WARN(TAG, "Security module does not provide an implementation");
1489 return SEC_E_UNSUPPORTED_FUNCTION;
1490 }
1491
1492 SECURITY_STATUS status =
1493 table->SetCredentialsAttributesA(phCredential, ulAttribute, pBuffer, cbBuffer);
1494 return log_status("SetCredentialsAttributesA", status);
1495}
1496
1497/* Context Management */
1498
1499static SECURITY_STATUS SEC_ENTRY
1500winpr_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput,
1501 ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext,
1502 PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsTimeStamp)
1503{
1504 const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByHandle(phCredential);
1505
1506 if (!table)
1507 return SEC_E_SECPKG_NOT_FOUND;
1508
1509 if (!table->AcceptSecurityContext)
1510 {
1511 WLog_WARN(TAG, "Security module does not provide an implementation");
1512 return SEC_E_UNSUPPORTED_FUNCTION;
1513 }
1514
1515 SECURITY_STATUS status =
1516 table->AcceptSecurityContext(phCredential, phContext, pInput, fContextReq, TargetDataRep,
1517 phNewContext, pOutput, pfContextAttr, ptsTimeStamp);
1518 return log_status("AcceptSecurityContext", status);
1519}
1520
1521static SECURITY_STATUS SEC_ENTRY winpr_ApplyControlToken(PCtxtHandle phContext,
1522 PSecBufferDesc pInput)
1523{
1524 const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByHandle(phContext);
1525
1526 if (!table)
1527 return SEC_E_SECPKG_NOT_FOUND;
1528
1529 if (!table->ApplyControlToken)
1530 {
1531 WLog_WARN(TAG, "Security module does not provide an implementation");
1532 return SEC_E_UNSUPPORTED_FUNCTION;
1533 }
1534
1535 SECURITY_STATUS status = table->ApplyControlToken(phContext, pInput);
1536 return log_status("ApplyControlToken", status);
1537}
1538
1539static SECURITY_STATUS SEC_ENTRY winpr_CompleteAuthToken(PCtxtHandle phContext,
1540 PSecBufferDesc pToken)
1541{
1542 const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByHandle(phContext);
1543
1544 if (!table)
1545 return SEC_E_SECPKG_NOT_FOUND;
1546
1547 if (!table->CompleteAuthToken)
1548 {
1549 WLog_WARN(TAG, "Security module does not provide an implementation");
1550 return SEC_E_UNSUPPORTED_FUNCTION;
1551 }
1552
1553 SECURITY_STATUS status = table->CompleteAuthToken(phContext, pToken);
1554 return log_status("CompleteAuthToken", status);
1555}
1556
1557static SECURITY_STATUS SEC_ENTRY winpr_DeleteSecurityContext(PCtxtHandle phContext)
1558{
1559 const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByHandle(phContext);
1560
1561 if (!table)
1562 return SEC_E_SECPKG_NOT_FOUND;
1563
1564 if (!table->DeleteSecurityContext)
1565 {
1566 WLog_WARN(TAG, "Security module does not provide an implementation");
1567 return SEC_E_UNSUPPORTED_FUNCTION;
1568 }
1569
1570 const SECURITY_STATUS status = table->DeleteSecurityContext(phContext);
1571 return log_status("DeleteSecurityContext", status);
1572}
1573
1574static SECURITY_STATUS SEC_ENTRY winpr_FreeContextBuffer(void* pvContextBuffer)
1575{
1576 if (!pvContextBuffer)
1577 return SEC_E_INVALID_HANDLE;
1578
1579 sspi_ContextBufferFree(pvContextBuffer);
1580 return SEC_E_OK;
1581}
1582
1583static SECURITY_STATUS SEC_ENTRY winpr_ImpersonateSecurityContext(PCtxtHandle phContext)
1584{
1585 const SecurityFunctionTableW* table = sspi_GetSecurityFunctionTableWByHandle(phContext);
1586
1587 if (!table)
1588 return SEC_E_SECPKG_NOT_FOUND;
1589
1590 if (!table->ImpersonateSecurityContext)
1591 {
1592 WLog_WARN(TAG, "Security module does not provide an implementation");
1593 return SEC_E_UNSUPPORTED_FUNCTION;
1594 }
1595
1596 SECURITY_STATUS status = table->ImpersonateSecurityContext(phContext);
1597 return log_status("ImpersonateSecurityContext", status);
1598}
1599
1600static SECURITY_STATUS SEC_ENTRY winpr_InitializeSecurityContextW(
1601 PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR* pszTargetName, ULONG fContextReq,
1602 ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2,
1603 PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
1604{
1605 const SecurityFunctionTableW* table = sspi_GetSecurityFunctionTableWByHandle(phCredential);
1606
1607 if (!table)
1608 return SEC_E_SECPKG_NOT_FOUND;
1609
1610 if (!table->InitializeSecurityContextW)
1611 {
1612 WLog_WARN(TAG, "Security module does not provide an implementation");
1613 return SEC_E_UNSUPPORTED_FUNCTION;
1614 }
1615
1616 const SECURITY_STATUS status = table->InitializeSecurityContextW(
1617 phCredential, phContext, pszTargetName, fContextReq, Reserved1, TargetDataRep, pInput,
1618 Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
1619 return log_status("InitializeSecurityContextW", status);
1620}
1621
1622static SECURITY_STATUS SEC_ENTRY winpr_InitializeSecurityContextA(
1623 PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR* pszTargetName, ULONG fContextReq,
1624 ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2,
1625 PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
1626{
1627 const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByHandle(phCredential);
1628
1629 if (!table)
1630 return SEC_E_SECPKG_NOT_FOUND;
1631
1632 if (!table->InitializeSecurityContextA)
1633 {
1634 WLog_WARN(TAG, "Security module does not provide an implementation");
1635 return SEC_E_UNSUPPORTED_FUNCTION;
1636 }
1637
1638 SECURITY_STATUS status = table->InitializeSecurityContextA(
1639 phCredential, phContext, pszTargetName, fContextReq, Reserved1, TargetDataRep, pInput,
1640 Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
1641
1642 return log_status("InitializeSecurityContextA", status);
1643}
1644
1645static SECURITY_STATUS SEC_ENTRY winpr_QueryContextAttributesW(PCtxtHandle phContext,
1646 ULONG ulAttribute, void* pBuffer)
1647{
1648 const SecurityFunctionTableW* table = sspi_GetSecurityFunctionTableWByHandle(phContext);
1649
1650 if (!table)
1651 return SEC_E_SECPKG_NOT_FOUND;
1652
1653 if (!table->QueryContextAttributesW)
1654 {
1655 WLog_WARN(TAG, "Security module does not provide an implementation");
1656 return SEC_E_UNSUPPORTED_FUNCTION;
1657 }
1658
1659 SECURITY_STATUS status = table->QueryContextAttributesW(phContext, ulAttribute, pBuffer);
1660 return log_status("QueryContextAttributesW", status);
1661}
1662
1663static SECURITY_STATUS SEC_ENTRY winpr_QueryContextAttributesA(PCtxtHandle phContext,
1664 ULONG ulAttribute, void* pBuffer)
1665{
1666 const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByHandle(phContext);
1667
1668 if (!table)
1669 return SEC_E_SECPKG_NOT_FOUND;
1670
1671 if (!table->QueryContextAttributesA)
1672 {
1673 WLog_WARN(TAG, "Security module does not provide an implementation");
1674 return SEC_E_UNSUPPORTED_FUNCTION;
1675 }
1676
1677 SECURITY_STATUS status = table->QueryContextAttributesA(phContext, ulAttribute, pBuffer);
1678 return log_status("QueryContextAttributesA", status);
1679}
1680
1681static SECURITY_STATUS SEC_ENTRY winpr_QuerySecurityContextToken(PCtxtHandle phContext,
1682 HANDLE* phToken)
1683{
1684 const SecurityFunctionTableW* table = sspi_GetSecurityFunctionTableWByHandle(phContext);
1685
1686 if (!table)
1687 return SEC_E_SECPKG_NOT_FOUND;
1688
1689 if (!table->QuerySecurityContextToken)
1690 {
1691 WLog_WARN(TAG, "Security module does not provide an implementation");
1692 return SEC_E_UNSUPPORTED_FUNCTION;
1693 }
1694
1695 SECURITY_STATUS status = table->QuerySecurityContextToken(phContext, phToken);
1696 return log_status("QuerySecurityContextToken", status);
1697}
1698
1699static SECURITY_STATUS SEC_ENTRY winpr_SetContextAttributesW(PCtxtHandle phContext,
1700 ULONG ulAttribute, void* pBuffer,
1701 ULONG cbBuffer)
1702{
1703 const SecurityFunctionTableW* table = sspi_GetSecurityFunctionTableWByHandle(phContext);
1704
1705 if (!table)
1706 return SEC_E_SECPKG_NOT_FOUND;
1707
1708 if (!table->SetContextAttributesW)
1709 {
1710 WLog_WARN(TAG, "Security module does not provide an implementation");
1711 return SEC_E_UNSUPPORTED_FUNCTION;
1712 }
1713
1714 SECURITY_STATUS status =
1715 table->SetContextAttributesW(phContext, ulAttribute, pBuffer, cbBuffer);
1716 return log_status("SetContextAttributesW", status);
1717}
1718
1719static SECURITY_STATUS SEC_ENTRY winpr_SetContextAttributesA(PCtxtHandle phContext,
1720 ULONG ulAttribute, void* pBuffer,
1721 ULONG cbBuffer)
1722{
1723 const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByHandle(phContext);
1724
1725 if (!table)
1726 return SEC_E_SECPKG_NOT_FOUND;
1727
1728 if (!table->SetContextAttributesA)
1729 {
1730 WLog_WARN(TAG, "Security module does not provide an implementation");
1731 return SEC_E_UNSUPPORTED_FUNCTION;
1732 }
1733
1734 SECURITY_STATUS status =
1735 table->SetContextAttributesA(phContext, ulAttribute, pBuffer, cbBuffer);
1736 return log_status("SetContextAttributesA", status);
1737}
1738
1739static SECURITY_STATUS SEC_ENTRY winpr_RevertSecurityContext(PCtxtHandle phContext)
1740{
1741 const SecurityFunctionTableW* table = sspi_GetSecurityFunctionTableWByHandle(phContext);
1742
1743 if (!table)
1744 return SEC_E_SECPKG_NOT_FOUND;
1745
1746 if (!table->RevertSecurityContext)
1747 {
1748 WLog_WARN(TAG, "Security module does not provide an implementation");
1749 return SEC_E_UNSUPPORTED_FUNCTION;
1750 }
1751
1752 SECURITY_STATUS status = table->RevertSecurityContext(phContext);
1753
1754 return log_status("RevertSecurityContext", status);
1755}
1756
1757/* Message Support */
1758
1759static SECURITY_STATUS SEC_ENTRY winpr_DecryptMessage(PCtxtHandle phContext,
1760 PSecBufferDesc pMessage, ULONG MessageSeqNo,
1761 PULONG pfQOP)
1762{
1763 const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByHandle(phContext);
1764
1765 if (!table)
1766 return SEC_E_SECPKG_NOT_FOUND;
1767
1768 if (!table->DecryptMessage)
1769 {
1770 WLog_WARN(TAG, "Security module does not provide an implementation");
1771 return SEC_E_UNSUPPORTED_FUNCTION;
1772 }
1773
1774 const SECURITY_STATUS status = table->DecryptMessage(phContext, pMessage, MessageSeqNo, pfQOP);
1775
1776 return log_status("DecryptMessage", status);
1777}
1778
1779static SECURITY_STATUS SEC_ENTRY winpr_EncryptMessage(PCtxtHandle phContext, ULONG fQOP,
1780 PSecBufferDesc pMessage, ULONG MessageSeqNo)
1781{
1782 const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByHandle(phContext);
1783
1784 if (!table)
1785 return SEC_E_SECPKG_NOT_FOUND;
1786
1787 if (!table->EncryptMessage)
1788 {
1789 WLog_WARN(TAG, "Security module does not provide an implementation");
1790 return SEC_E_UNSUPPORTED_FUNCTION;
1791 }
1792
1793 const SECURITY_STATUS status = table->EncryptMessage(phContext, fQOP, pMessage, MessageSeqNo);
1794 return log_status("EncryptMessage", status);
1795}
1796
1797static SECURITY_STATUS SEC_ENTRY winpr_MakeSignature(PCtxtHandle phContext, ULONG fQOP,
1798 PSecBufferDesc pMessage, ULONG MessageSeqNo)
1799{
1800 const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByHandle(phContext);
1801
1802 if (!table)
1803 return SEC_E_SECPKG_NOT_FOUND;
1804
1805 if (!table->MakeSignature)
1806 {
1807 WLog_WARN(TAG, "Security module does not provide an implementation");
1808 return SEC_E_UNSUPPORTED_FUNCTION;
1809 }
1810
1811 const SECURITY_STATUS status = table->MakeSignature(phContext, fQOP, pMessage, MessageSeqNo);
1812 return log_status("MakeSignature", status);
1813}
1814
1815static SECURITY_STATUS SEC_ENTRY winpr_VerifySignature(PCtxtHandle phContext,
1816 PSecBufferDesc pMessage, ULONG MessageSeqNo,
1817 PULONG pfQOP)
1818{
1819 const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByHandle(phContext);
1820
1821 if (!table)
1822 return SEC_E_SECPKG_NOT_FOUND;
1823
1824 if (!table->VerifySignature)
1825 {
1826 WLog_WARN(TAG, "Security module does not provide an implementation");
1827 return SEC_E_UNSUPPORTED_FUNCTION;
1828 }
1829
1830 SECURITY_STATUS status = table->VerifySignature(phContext, pMessage, MessageSeqNo, pfQOP);
1831
1832 return log_status("VerifySignature", status);
1833}
1834
1835static SecurityFunctionTableA winpr_SecurityFunctionTableA = {
1836 3, /* dwVersion */
1837 winpr_EnumerateSecurityPackagesA, /* EnumerateSecurityPackages */
1838 winpr_QueryCredentialsAttributesA, /* QueryCredentialsAttributes */
1839 winpr_AcquireCredentialsHandleA, /* AcquireCredentialsHandle */
1840 winpr_FreeCredentialsHandle, /* FreeCredentialsHandle */
1841 nullptr, /* Reserved2 */
1842 winpr_InitializeSecurityContextA, /* InitializeSecurityContext */
1843 winpr_AcceptSecurityContext, /* AcceptSecurityContext */
1844 winpr_CompleteAuthToken, /* CompleteAuthToken */
1845 winpr_DeleteSecurityContext, /* DeleteSecurityContext */
1846 winpr_ApplyControlToken, /* ApplyControlToken */
1847 winpr_QueryContextAttributesA, /* QueryContextAttributes */
1848 winpr_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
1849 winpr_RevertSecurityContext, /* RevertSecurityContext */
1850 winpr_MakeSignature, /* MakeSignature */
1851 winpr_VerifySignature, /* VerifySignature */
1852 winpr_FreeContextBuffer, /* FreeContextBuffer */
1853 winpr_QuerySecurityPackageInfoA, /* QuerySecurityPackageInfo */
1854 nullptr, /* Reserved3 */
1855 nullptr, /* Reserved4 */
1856 winpr_ExportSecurityContext, /* ExportSecurityContext */
1857 winpr_ImportSecurityContextA, /* ImportSecurityContext */
1858 nullptr, /* AddCredentials */
1859 nullptr, /* Reserved8 */
1860 winpr_QuerySecurityContextToken, /* QuerySecurityContextToken */
1861 winpr_EncryptMessage, /* EncryptMessage */
1862 winpr_DecryptMessage, /* DecryptMessage */
1863 winpr_SetContextAttributesA, /* SetContextAttributes */
1864 winpr_SetCredentialsAttributesA, /* SetCredentialsAttributes */
1865};
1866
1867static SecurityFunctionTableW winpr_SecurityFunctionTableW = {
1868 3, /* dwVersion */
1869 winpr_EnumerateSecurityPackagesW, /* EnumerateSecurityPackages */
1870 winpr_QueryCredentialsAttributesW, /* QueryCredentialsAttributes */
1871 winpr_AcquireCredentialsHandleW, /* AcquireCredentialsHandle */
1872 winpr_FreeCredentialsHandle, /* FreeCredentialsHandle */
1873 nullptr, /* Reserved2 */
1874 winpr_InitializeSecurityContextW, /* InitializeSecurityContext */
1875 winpr_AcceptSecurityContext, /* AcceptSecurityContext */
1876 winpr_CompleteAuthToken, /* CompleteAuthToken */
1877 winpr_DeleteSecurityContext, /* DeleteSecurityContext */
1878 winpr_ApplyControlToken, /* ApplyControlToken */
1879 winpr_QueryContextAttributesW, /* QueryContextAttributes */
1880 winpr_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
1881 winpr_RevertSecurityContext, /* RevertSecurityContext */
1882 winpr_MakeSignature, /* MakeSignature */
1883 winpr_VerifySignature, /* VerifySignature */
1884 winpr_FreeContextBuffer, /* FreeContextBuffer */
1885 winpr_QuerySecurityPackageInfoW, /* QuerySecurityPackageInfo */
1886 nullptr, /* Reserved3 */
1887 nullptr, /* Reserved4 */
1888 winpr_ExportSecurityContext, /* ExportSecurityContext */
1889 winpr_ImportSecurityContextW, /* ImportSecurityContext */
1890 nullptr, /* AddCredentials */
1891 nullptr, /* Reserved8 */
1892 winpr_QuerySecurityContextToken, /* QuerySecurityContextToken */
1893 winpr_EncryptMessage, /* EncryptMessage */
1894 winpr_DecryptMessage, /* DecryptMessage */
1895 winpr_SetContextAttributesW, /* SetContextAttributes */
1896 winpr_SetCredentialsAttributesW, /* SetCredentialsAttributes */
1897};
1898
1899SecurityFunctionTableW* SEC_ENTRY winpr_InitSecurityInterfaceW(void)
1900{
1901 return &winpr_SecurityFunctionTableW;
1902}
1903
1904SecurityFunctionTableA* SEC_ENTRY winpr_InitSecurityInterfaceA(void)
1905{
1906 return &winpr_SecurityFunctionTableA;
1907}
1908
1909SEC_WINPR_NTLM_SETTINGS_V2* sspi_CloneSecNtlmSettings(const SEC_WINPR_NTLM_SETTINGS_V2* other)
1910{
1911 if (!other)
1912 return nullptr;
1913
1914 const size_t size = sizeof(SEC_WINPR_NTLM_SETTINGS_V2);
1915 if (other->size < size)
1916 {
1917 WLog_ERR(TAG,
1918 "Invalid SEC_WINPR_NTLM_SETTINGS_V2 parameter passed, must be of size >= "
1919 "%" PRIuz,
1920 size);
1921 return nullptr;
1922 }
1923
1924 SEC_WINPR_NTLM_SETTINGS_V2* clone = sspi_AllocSecNtlmSettings();
1925 if (!clone)
1926 return nullptr;
1927
1928 if (other->samFile)
1929 {
1930 if (!sspi_CloneSecSettingsString(&clone->samFile, other->samFile))
1931 goto fail;
1932 }
1933 clone->hashCallback = other->hashCallback;
1934 clone->hashCallbackArg = other->hashCallbackArg;
1935 if (other->targetName)
1936 {
1937 if (!sspi_CloneSecSettingsString(&clone->targetName, other->targetName))
1938 goto fail;
1939 }
1940 if (other->netBiosComputerName)
1941 {
1942 if (!sspi_CloneSecSettingsString(&clone->netBiosComputerName, other->netBiosComputerName))
1943 goto fail;
1944 }
1945 if (other->netBiosDomainName)
1946 {
1947 if (!sspi_CloneSecSettingsString(&clone->netBiosDomainName, other->netBiosDomainName))
1948 goto fail;
1949 }
1950 if (other->dnsComputerName)
1951 {
1952 if (!sspi_CloneSecSettingsString(&clone->dnsComputerName, other->dnsComputerName))
1953 goto fail;
1954 }
1955 if (other->dnsDomainName)
1956 {
1957 if (!sspi_CloneSecSettingsString(&clone->dnsDomainName, other->dnsDomainName))
1958 goto fail;
1959 }
1960
1961 return clone;
1962
1963fail:
1964 sspi_FreeSecNtlmSettings(clone);
1965 return nullptr;
1966}