Coverage Report

Created: 2026-10-15 06:26

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