Coverage Report

Created: 2026-05-11 06:55

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