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