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