Coverage Report

Created: 2026-05-30 06:41

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