freerdp: add restricted admin option
[platform/upstream/freerdp.git] / libfreerdp / core / nla.c
1 /**
2  * WinPR: Windows Portable Runtime
3  * Network Level Authentication (NLA)
4  *
5  * Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *               http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <time.h>
25
26 #ifndef _WIN32
27 #include <unistd.h>
28 #endif
29
30 #include <freerdp/crypto/tls.h>
31
32 #include <winpr/crt.h>
33 #include <winpr/sspi.h>
34 #include <winpr/print.h>
35 #include <winpr/tchar.h>
36 #include <winpr/library.h>
37 #include <winpr/registry.h>
38
39 #include "nla.h"
40
41 /**
42  * TSRequest ::= SEQUENCE {
43  *      version    [0] INTEGER,
44  *      negoTokens [1] NegoData OPTIONAL,
45  *      authInfo   [2] OCTET STRING OPTIONAL,
46  *      pubKeyAuth [3] OCTET STRING OPTIONAL
47  * }
48  *
49  * NegoData ::= SEQUENCE OF NegoDataItem
50  *
51  * NegoDataItem ::= SEQUENCE {
52  *      negoToken [0] OCTET STRING
53  * }
54  *
55  * TSCredentials ::= SEQUENCE {
56  *      credType    [0] INTEGER,
57  *      credentials [1] OCTET STRING
58  * }
59  *
60  * TSPasswordCreds ::= SEQUENCE {
61  *      domainName  [0] OCTET STRING,
62  *      userName    [1] OCTET STRING,
63  *      password    [2] OCTET STRING
64  * }
65  *
66  * TSSmartCardCreds ::= SEQUENCE {
67  *      pin        [0] OCTET STRING,
68  *      cspData    [1] TSCspDataDetail,
69  *      userHint   [2] OCTET STRING OPTIONAL,
70  *      domainHint [3] OCTET STRING OPTIONAL
71  * }
72  *
73  * TSCspDataDetail ::= SEQUENCE {
74  *      keySpec       [0] INTEGER,
75  *      cardName      [1] OCTET STRING OPTIONAL,
76  *      readerName    [2] OCTET STRING OPTIONAL,
77  *      containerName [3] OCTET STRING OPTIONAL,
78  *      cspName       [4] OCTET STRING OPTIONAL
79  * }
80  *
81  */
82
83 #ifdef WITH_DEBUG_NLA
84 #define WITH_DEBUG_CREDSSP
85 #endif
86
87 #ifdef WITH_NATIVE_SSPI
88 #define NLA_PKG_NAME    NTLMSP_NAME
89 #else
90 #define NLA_PKG_NAME    NTLMSP_NAME
91 #endif
92
93 #define TERMSRV_SPN_PREFIX      "TERMSRV/"
94
95 void credssp_send(rdpCredssp* credssp);
96 int credssp_recv(rdpCredssp* credssp);
97 void credssp_buffer_print(rdpCredssp* credssp);
98 void credssp_buffer_free(rdpCredssp* credssp);
99 SECURITY_STATUS credssp_encrypt_public_key_echo(rdpCredssp* credssp);
100 SECURITY_STATUS credssp_decrypt_public_key_echo(rdpCredssp* credssp);
101 SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp);
102 SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp);
103
104 #define ber_sizeof_sequence_octet_string(length) ber_sizeof_contextual_tag(ber_sizeof_octet_string(length)) + ber_sizeof_octet_string(length)
105 #define ber_write_sequence_octet_string(stream, context, value, length) ber_write_contextual_tag(stream, context, ber_sizeof_octet_string(length), TRUE) + ber_write_octet_string(stream, value, length)
106
107 /**
108  * Initialize NTLMSSP authentication module (client).
109  * @param credssp
110  */
111
112 int credssp_ntlm_client_init(rdpCredssp* credssp)
113 {
114         char* spn;
115         int length;
116         rdpTls* tls = NULL;
117         freerdp* instance;
118         rdpSettings* settings;
119
120         settings = credssp->settings;
121         instance = (freerdp*) settings->instance;
122
123         if ((settings->Password == NULL ) || (settings->Username == NULL)
124                         || (!strlen(settings->Password)) || (!strlen(settings->Username)))
125         {
126                 if (instance->Authenticate)
127                 {
128                         BOOL proceed = instance->Authenticate(instance,
129                                         &settings->Username, &settings->Password, &settings->Domain);
130                         if (!proceed)
131                                 return 0;
132                 }
133         }
134
135         sspi_SetAuthIdentity(&(credssp->identity), settings->Username, settings->Domain, settings->Password);
136
137 #ifdef WITH_DEBUG_NLA
138         _tprintf(_T("User: %s Domain: %s Password: %s\n"),
139                 (char*) credssp->identity.User, (char*) credssp->identity.Domain, (char*) credssp->identity.Password);
140 #endif
141
142         if (credssp->transport->layer == TRANSPORT_LAYER_TLS)
143         {
144                 tls = credssp->transport->TlsIn;
145         }
146         else if (credssp->transport->layer == TRANSPORT_LAYER_TSG_TLS)
147         {
148                 tls = credssp->transport->TsgTls;
149         }
150         else
151         {
152                 fprintf(stderr, "Unknown NLA transport layer\n");
153                 return 0;
154         }
155
156         sspi_SecBufferAlloc(&credssp->PublicKey, tls->PublicKeyLength);
157         CopyMemory(credssp->PublicKey.pvBuffer, tls->PublicKey, tls->PublicKeyLength);
158
159         length = sizeof(TERMSRV_SPN_PREFIX) + strlen(settings->ServerHostname);
160
161         spn = (SEC_CHAR*) malloc(length + 1);
162         sprintf(spn, "%s%s", TERMSRV_SPN_PREFIX, settings->ServerHostname);
163
164 #ifdef UNICODE
165         credssp->ServicePrincipalName = (LPTSTR) malloc(length * 2 + 2);
166         MultiByteToWideChar(CP_UTF8, 0, spn, length,
167                 (LPWSTR) credssp->ServicePrincipalName, length);
168         free(spn);
169 #else
170         credssp->ServicePrincipalName = spn;
171 #endif
172
173         return 1;
174 }
175
176 /**
177  * Initialize NTLMSSP authentication module (server).
178  * @param credssp
179  */
180
181 int credssp_ntlm_server_init(rdpCredssp* credssp)
182 {
183         freerdp* instance;
184         rdpSettings* settings = credssp->settings;
185         instance = (freerdp*) settings->instance;
186
187         sspi_SecBufferAlloc(&credssp->PublicKey, credssp->transport->TlsIn->PublicKeyLength);
188         CopyMemory(credssp->PublicKey.pvBuffer, credssp->transport->TlsIn->PublicKey, credssp->transport->TlsIn->PublicKeyLength);
189
190         return 1;
191 }
192
193 int credssp_client_authenticate(rdpCredssp* credssp)
194 {
195         ULONG cbMaxToken;
196         ULONG fContextReq;
197         ULONG pfContextAttr;
198         SECURITY_STATUS status;
199         CredHandle credentials;
200         TimeStamp expiration;
201         PSecPkgInfo pPackageInfo;
202         SecBuffer input_buffer;
203         SecBuffer output_buffer;
204         SecBufferDesc input_buffer_desc;
205         SecBufferDesc output_buffer_desc;
206         BOOL have_context;
207         BOOL have_input_buffer;
208         BOOL have_pub_key_auth;
209
210         sspi_GlobalInit();
211
212         if (credssp_ntlm_client_init(credssp) == 0)
213                 return 0;
214
215 #ifdef WITH_NATIVE_SSPI
216         {
217                 HMODULE hSSPI;
218                 INIT_SECURITY_INTERFACE InitSecurityInterface;
219                 PSecurityFunctionTable pSecurityInterface = NULL;
220
221                 hSSPI = LoadLibrary(_T("secur32.dll"));
222
223 #ifdef UNICODE
224                 InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceW");
225 #else
226                 InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceA");
227 #endif
228                 credssp->table = (*InitSecurityInterface)();
229         }
230 #else
231         credssp->table = InitSecurityInterface();
232 #endif
233
234         status = credssp->table->QuerySecurityPackageInfo(NLA_PKG_NAME, &pPackageInfo);
235
236         if (status != SEC_E_OK)
237         {
238                 fprintf(stderr, "QuerySecurityPackageInfo status: 0x%08X\n", status);
239                 return 0;
240         }
241
242         cbMaxToken = pPackageInfo->cbMaxToken;
243
244         status = credssp->table->AcquireCredentialsHandle(NULL, NLA_PKG_NAME,
245                         SECPKG_CRED_OUTBOUND, NULL, &credssp->identity, NULL, NULL, &credentials, &expiration);
246
247         if (status != SEC_E_OK)
248         {
249                 fprintf(stderr, "AcquireCredentialsHandle status: 0x%08X\n", status);
250                 return 0;
251         }
252
253         have_context = FALSE;
254         have_input_buffer = FALSE;
255         have_pub_key_auth = FALSE;
256         ZeroMemory(&input_buffer, sizeof(SecBuffer));
257         ZeroMemory(&output_buffer, sizeof(SecBuffer));
258         ZeroMemory(&credssp->ContextSizes, sizeof(SecPkgContext_Sizes));
259
260         /*
261          * from tspkg.dll: 0x00000132
262          * ISC_REQ_MUTUAL_AUTH
263          * ISC_REQ_CONFIDENTIALITY
264          * ISC_REQ_USE_SESSION_KEY
265          * ISC_REQ_ALLOCATE_MEMORY
266          */
267
268         fContextReq = ISC_REQ_MUTUAL_AUTH | ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY;
269
270         while (TRUE)
271         {
272                 output_buffer_desc.ulVersion = SECBUFFER_VERSION;
273                 output_buffer_desc.cBuffers = 1;
274                 output_buffer_desc.pBuffers = &output_buffer;
275                 output_buffer.BufferType = SECBUFFER_TOKEN;
276                 output_buffer.cbBuffer = cbMaxToken;
277                 output_buffer.pvBuffer = malloc(output_buffer.cbBuffer);
278
279                 status = credssp->table->InitializeSecurityContext(&credentials,
280                                 (have_context) ? &credssp->context : NULL,
281                                 credssp->ServicePrincipalName, fContextReq, 0,
282                                 SECURITY_NATIVE_DREP, (have_input_buffer) ? &input_buffer_desc : NULL,
283                                 0, &credssp->context, &output_buffer_desc, &pfContextAttr, &expiration);
284
285                 if (have_input_buffer && (input_buffer.pvBuffer != NULL))
286                 {
287                         free(input_buffer.pvBuffer);
288                         input_buffer.pvBuffer = NULL;
289                 }
290
291                 if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED) || (status == SEC_E_OK))
292                 {
293                         if (credssp->table->CompleteAuthToken != NULL)
294                                 credssp->table->CompleteAuthToken(&credssp->context, &output_buffer_desc);
295
296                         have_pub_key_auth = TRUE;
297
298                         if (credssp->table->QueryContextAttributes(&credssp->context, SECPKG_ATTR_SIZES, &credssp->ContextSizes) != SEC_E_OK)
299                         {
300                                 fprintf(stderr, "QueryContextAttributes SECPKG_ATTR_SIZES failure\n");
301                                 return 0;
302                         }
303
304                         credssp_encrypt_public_key_echo(credssp);
305
306                         if (status == SEC_I_COMPLETE_NEEDED)
307                                 status = SEC_E_OK;
308                         else if (status == SEC_I_COMPLETE_AND_CONTINUE)
309                                 status = SEC_I_CONTINUE_NEEDED;
310                 }
311
312                 /* send authentication token to server */
313
314                 if (output_buffer.cbBuffer > 0)
315                 {
316                         credssp->negoToken.pvBuffer = output_buffer.pvBuffer;
317                         credssp->negoToken.cbBuffer = output_buffer.cbBuffer;
318
319 #ifdef WITH_DEBUG_CREDSSP
320                         fprintf(stderr, "Sending Authentication Token\n");
321                         winpr_HexDump(credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer);
322 #endif
323
324                         credssp_send(credssp);
325                         credssp_buffer_free(credssp);
326                 }
327
328                 if (status != SEC_I_CONTINUE_NEEDED)
329                         break;
330
331                 /* receive server response and place in input buffer */
332
333                 input_buffer_desc.ulVersion = SECBUFFER_VERSION;
334                 input_buffer_desc.cBuffers = 1;
335                 input_buffer_desc.pBuffers = &input_buffer;
336                 input_buffer.BufferType = SECBUFFER_TOKEN;
337
338                 if (credssp_recv(credssp) < 0)
339                         return -1;
340
341 #ifdef WITH_DEBUG_CREDSSP
342                 fprintf(stderr, "Receiving Authentication Token (%d)\n", (int) credssp->negoToken.cbBuffer);
343                 winpr_HexDump(credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer);
344 #endif
345
346                 input_buffer.pvBuffer = credssp->negoToken.pvBuffer;
347                 input_buffer.cbBuffer = credssp->negoToken.cbBuffer;
348
349                 have_input_buffer = TRUE;
350                 have_context = TRUE;
351         }
352
353         /* Encrypted Public Key +1 */
354         if (credssp_recv(credssp) < 0)
355                 return -1;
356
357         /* Verify Server Public Key Echo */
358
359         status = credssp_decrypt_public_key_echo(credssp);
360         credssp_buffer_free(credssp);
361
362         if (status != SEC_E_OK)
363         {
364                 fprintf(stderr, "Could not verify public key echo!\n");
365                 return -1;
366         }
367
368         /* Send encrypted credentials */
369
370         status = credssp_encrypt_ts_credentials(credssp);
371
372         if (status != SEC_E_OK)
373         {
374                 fprintf(stderr, "credssp_encrypt_ts_credentials status: 0x%08X\n", status);
375                 return 0;
376         }
377
378         credssp_send(credssp);
379         credssp_buffer_free(credssp);
380
381         /* Free resources */
382
383         credssp->table->FreeCredentialsHandle(&credentials);
384         credssp->table->FreeContextBuffer(pPackageInfo);
385
386         return 1;
387 }
388
389 /**
390  * Authenticate with client using CredSSP (server).
391  * @param credssp
392  * @return 1 if authentication is successful
393  */
394
395 int credssp_server_authenticate(rdpCredssp* credssp)
396 {
397         UINT32 cbMaxToken;
398         ULONG fContextReq;
399         ULONG pfContextAttr;
400         SECURITY_STATUS status;
401         CredHandle credentials;
402         TimeStamp expiration;
403         PSecPkgInfo pPackageInfo;
404         SecBuffer input_buffer;
405         SecBuffer output_buffer;
406         SecBufferDesc input_buffer_desc;
407         SecBufferDesc output_buffer_desc;
408         BOOL have_context;
409         BOOL have_input_buffer;
410         BOOL have_pub_key_auth;
411
412         sspi_GlobalInit();
413
414         if (credssp_ntlm_server_init(credssp) == 0)
415                 return 0;
416
417 #ifdef WITH_NATIVE_SSPI
418         if (!credssp->SspiModule)
419                 credssp->SspiModule = _tcsdup(_T("secur32.dll"));
420 #endif
421
422         if (credssp->SspiModule)
423         {
424                 HMODULE hSSPI;
425                 INIT_SECURITY_INTERFACE pInitSecurityInterface;
426
427                 hSSPI = LoadLibrary(credssp->SspiModule);
428
429                 if (!hSSPI)
430                 {
431                         _tprintf(_T("Failed to load SSPI module: %s\n"), credssp->SspiModule);
432                         return 0;
433                 }
434
435 #ifdef UNICODE
436                 pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceW");
437 #else
438                 pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceA");
439 #endif
440
441                 credssp->table = (*pInitSecurityInterface)();
442         }
443 #ifndef WITH_NATIVE_SSPI
444         else
445         {
446                 credssp->table = InitSecurityInterface();
447         }
448 #endif
449
450         status = credssp->table->QuerySecurityPackageInfo(NLA_PKG_NAME, &pPackageInfo);
451
452         if (status != SEC_E_OK)
453         {
454                 fprintf(stderr, "QuerySecurityPackageInfo status: 0x%08X\n", status);
455                 return 0;
456         }
457
458         cbMaxToken = pPackageInfo->cbMaxToken;
459
460         status = credssp->table->AcquireCredentialsHandle(NULL, NLA_PKG_NAME,
461                         SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &credentials, &expiration);
462
463         if (status != SEC_E_OK)
464         {
465                 fprintf(stderr, "AcquireCredentialsHandle status: 0x%08X\n", status);
466                 return 0;
467         }
468
469         have_context = FALSE;
470         have_input_buffer = FALSE;
471         have_pub_key_auth = FALSE;
472         ZeroMemory(&input_buffer, sizeof(SecBuffer));
473         ZeroMemory(&output_buffer, sizeof(SecBuffer));
474         ZeroMemory(&input_buffer_desc, sizeof(SecBufferDesc));
475         ZeroMemory(&output_buffer_desc, sizeof(SecBufferDesc));
476         ZeroMemory(&credssp->ContextSizes, sizeof(SecPkgContext_Sizes));
477
478         /*
479          * from tspkg.dll: 0x00000112
480          * ASC_REQ_MUTUAL_AUTH
481          * ASC_REQ_CONFIDENTIALITY
482          * ASC_REQ_ALLOCATE_MEMORY
483          */
484
485         fContextReq = 0;
486         fContextReq |= ASC_REQ_MUTUAL_AUTH;
487         fContextReq |= ASC_REQ_CONFIDENTIALITY;
488
489         fContextReq |= ASC_REQ_CONNECTION;
490         fContextReq |= ASC_REQ_USE_SESSION_KEY;
491
492         fContextReq |= ASC_REQ_REPLAY_DETECT;
493         fContextReq |= ASC_REQ_SEQUENCE_DETECT;
494
495         fContextReq |= ASC_REQ_EXTENDED_ERROR;
496
497         while (TRUE)
498         {
499                 input_buffer_desc.ulVersion = SECBUFFER_VERSION;
500                 input_buffer_desc.cBuffers = 1;
501                 input_buffer_desc.pBuffers = &input_buffer;
502                 input_buffer.BufferType = SECBUFFER_TOKEN;
503
504                 /* receive authentication token */
505
506                 input_buffer_desc.ulVersion = SECBUFFER_VERSION;
507                 input_buffer_desc.cBuffers = 1;
508                 input_buffer_desc.pBuffers = &input_buffer;
509                 input_buffer.BufferType = SECBUFFER_TOKEN;
510
511                 if (credssp_recv(credssp) < 0)
512                         return -1;
513
514 #ifdef WITH_DEBUG_CREDSSP
515                 fprintf(stderr, "Receiving Authentication Token\n");
516                 credssp_buffer_print(credssp);
517 #endif
518
519                 input_buffer.pvBuffer = credssp->negoToken.pvBuffer;
520                 input_buffer.cbBuffer = credssp->negoToken.cbBuffer;
521
522                 if (credssp->negoToken.cbBuffer < 1)
523                 {
524                         fprintf(stderr, "CredSSP: invalid negoToken!\n");
525                         return -1;
526                 }
527
528                 output_buffer_desc.ulVersion = SECBUFFER_VERSION;
529                 output_buffer_desc.cBuffers = 1;
530                 output_buffer_desc.pBuffers = &output_buffer;
531                 output_buffer.BufferType = SECBUFFER_TOKEN;
532                 output_buffer.cbBuffer = cbMaxToken;
533                 output_buffer.pvBuffer = malloc(output_buffer.cbBuffer);
534
535                 status = credssp->table->AcceptSecurityContext(&credentials,
536                         have_context? &credssp->context: NULL,
537                         &input_buffer_desc, fContextReq, SECURITY_NATIVE_DREP, &credssp->context,
538                         &output_buffer_desc, &pfContextAttr, &expiration);
539
540                 credssp->negoToken.pvBuffer = output_buffer.pvBuffer;
541                 credssp->negoToken.cbBuffer = output_buffer.cbBuffer;
542
543                 if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
544                 {
545                         if (credssp->table->CompleteAuthToken != NULL)
546                                 credssp->table->CompleteAuthToken(&credssp->context, &output_buffer_desc);
547
548                         if (status == SEC_I_COMPLETE_NEEDED)
549                                 status = SEC_E_OK;
550                         else if (status == SEC_I_COMPLETE_AND_CONTINUE)
551                                 status = SEC_I_CONTINUE_NEEDED;
552                 }
553
554                 if (status == SEC_E_OK)
555                 {
556                         have_pub_key_auth = TRUE;
557
558                         if (credssp->table->QueryContextAttributes(&credssp->context, SECPKG_ATTR_SIZES, &credssp->ContextSizes) != SEC_E_OK)
559                         {
560                                 fprintf(stderr, "QueryContextAttributes SECPKG_ATTR_SIZES failure\n");
561                                 return 0;
562                         }
563
564                         if (credssp_decrypt_public_key_echo(credssp) != SEC_E_OK)
565                         {
566                                 fprintf(stderr, "Error: could not verify client's public key echo\n");
567                                 return -1;
568                         }
569
570                         sspi_SecBufferFree(&credssp->negoToken);
571                         credssp->negoToken.pvBuffer = NULL;
572                         credssp->negoToken.cbBuffer = 0;
573
574                         credssp_encrypt_public_key_echo(credssp);
575                 }
576
577                 if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED))
578                 {
579                         fprintf(stderr, "AcceptSecurityContext status: 0x%08X\n", status);
580                         return -1;
581                 }
582
583                 /* send authentication token */
584
585 #ifdef WITH_DEBUG_CREDSSP
586                 fprintf(stderr, "Sending Authentication Token\n");
587                 credssp_buffer_print(credssp);
588 #endif
589
590                 credssp_send(credssp);
591                 credssp_buffer_free(credssp);
592
593                 if (status != SEC_I_CONTINUE_NEEDED)
594                         break;
595
596                 have_context = TRUE;
597         }
598
599         /* Receive encrypted credentials */
600
601         if (credssp_recv(credssp) < 0)
602                 return -1;
603
604         if (credssp_decrypt_ts_credentials(credssp) != SEC_E_OK)
605         {
606                 fprintf(stderr, "Could not decrypt TSCredentials status: 0x%08X\n", status);
607                 return 0;
608         }
609
610         if (status != SEC_E_OK)
611         {
612                 fprintf(stderr, "AcceptSecurityContext status: 0x%08X\n", status);
613                 return 0;
614         }
615
616         status = credssp->table->ImpersonateSecurityContext(&credssp->context);
617
618         if (status != SEC_E_OK)
619         {
620                 fprintf(stderr, "ImpersonateSecurityContext status: 0x%08X\n", status);
621                 return 0;
622         }
623         else
624         {
625                 status = credssp->table->RevertSecurityContext(&credssp->context);
626
627                 if (status != SEC_E_OK)
628                 {
629                         fprintf(stderr, "RevertSecurityContext status: 0x%08X\n", status);
630                         return 0;
631                 }
632         }
633
634         credssp->table->FreeContextBuffer(pPackageInfo);
635
636         return 1;
637 }
638
639 /**
640  * Authenticate using CredSSP.
641  * @param credssp
642  * @return 1 if authentication is successful
643  */
644
645 int credssp_authenticate(rdpCredssp* credssp)
646 {
647         if (credssp->server)
648                 return credssp_server_authenticate(credssp);
649         else
650                 return credssp_client_authenticate(credssp);
651 }
652
653 void ap_integer_increment_le(BYTE* number, int size)
654 {
655         int index;
656
657         for (index = 0; index < size; index++)
658         {
659                 if (number[index] < 0xFF)
660                 {
661                         number[index]++;
662                         break;
663                 }
664                 else
665                 {
666                         number[index] = 0;
667                         continue;
668                 }
669         }
670 }
671
672 void ap_integer_decrement_le(BYTE* number, int size)
673 {
674         int index;
675
676         for (index = 0; index < size; index++)
677         {
678                 if (number[index] > 0)
679                 {
680                         number[index]--;
681                         break;
682                 }
683                 else
684                 {
685                         number[index] = 0xFF;
686                         continue;
687                 }
688         }
689 }
690
691 SECURITY_STATUS credssp_encrypt_public_key_echo(rdpCredssp* credssp)
692 {
693         SecBuffer Buffers[2];
694         SecBufferDesc Message;
695         SECURITY_STATUS status;
696         int public_key_length;
697
698         public_key_length = credssp->PublicKey.cbBuffer;
699
700         Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
701         Buffers[1].BufferType = SECBUFFER_DATA; /* TLS Public Key */
702
703         sspi_SecBufferAlloc(&credssp->pubKeyAuth, credssp->ContextSizes.cbMaxSignature + public_key_length);
704
705         Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
706         Buffers[0].pvBuffer = credssp->pubKeyAuth.pvBuffer;
707
708         Buffers[1].cbBuffer = public_key_length;
709         Buffers[1].pvBuffer = ((BYTE*) credssp->pubKeyAuth.pvBuffer) + credssp->ContextSizes.cbMaxSignature;
710         CopyMemory(Buffers[1].pvBuffer, credssp->PublicKey.pvBuffer, Buffers[1].cbBuffer);
711
712         if (credssp->server)
713         {
714                 /* server echos the public key +1 */
715                 ap_integer_increment_le((BYTE*) Buffers[1].pvBuffer, Buffers[1].cbBuffer);
716         }
717
718         Message.cBuffers = 2;
719         Message.ulVersion = SECBUFFER_VERSION;
720         Message.pBuffers = (PSecBuffer) &Buffers;
721
722         status = credssp->table->EncryptMessage(&credssp->context, 0, &Message, credssp->send_seq_num++);
723
724         if (status != SEC_E_OK)
725         {
726                 fprintf(stderr, "EncryptMessage status: 0x%08X\n", status);
727                 return status;
728         }
729
730         return status;
731 }
732
733 SECURITY_STATUS credssp_decrypt_public_key_echo(rdpCredssp* credssp)
734 {
735         int length;
736         BYTE* buffer;
737         ULONG pfQOP = 0;
738         BYTE* public_key1;
739         BYTE* public_key2;
740         int public_key_length;
741         SecBuffer Buffers[2];
742         SecBufferDesc Message;
743         SECURITY_STATUS status;
744
745         if (credssp->PublicKey.cbBuffer + credssp->ContextSizes.cbMaxSignature != credssp->pubKeyAuth.cbBuffer)
746         {
747                 fprintf(stderr, "unexpected pubKeyAuth buffer size:%d\n", (int) credssp->pubKeyAuth.cbBuffer);
748                 return SEC_E_INVALID_TOKEN;
749         }
750
751         length = credssp->pubKeyAuth.cbBuffer;
752         buffer = (BYTE*) malloc(length);
753         CopyMemory(buffer, credssp->pubKeyAuth.pvBuffer, length);
754
755         public_key_length = credssp->PublicKey.cbBuffer;
756
757         Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
758         Buffers[1].BufferType = SECBUFFER_DATA; /* Encrypted TLS Public Key */
759
760         Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
761         Buffers[0].pvBuffer = buffer;
762
763         Buffers[1].cbBuffer = length - credssp->ContextSizes.cbMaxSignature;
764         Buffers[1].pvBuffer = buffer + credssp->ContextSizes.cbMaxSignature;
765
766         Message.cBuffers = 2;
767         Message.ulVersion = SECBUFFER_VERSION;
768         Message.pBuffers = (PSecBuffer) &Buffers;
769
770         status = credssp->table->DecryptMessage(&credssp->context, &Message, credssp->recv_seq_num++, &pfQOP);
771
772         if (status != SEC_E_OK)
773         {
774                 fprintf(stderr, "DecryptMessage failure: 0x%08X\n", status);
775                 return status;
776         }
777
778         public_key1 = (BYTE*) credssp->PublicKey.pvBuffer;
779         public_key2 = (BYTE*) Buffers[1].pvBuffer;
780
781         if (!credssp->server)
782         {
783                 /* server echos the public key +1 */
784                 ap_integer_decrement_le(public_key2, public_key_length);
785         }
786
787         if (memcmp(public_key1, public_key2, public_key_length) != 0)
788         {
789                 fprintf(stderr, "Could not verify server's public key echo\n");
790
791                 fprintf(stderr, "Expected (length = %d):\n", public_key_length);
792                 winpr_HexDump(public_key1, public_key_length);
793
794                 fprintf(stderr, "Actual (length = %d):\n", public_key_length);
795                 winpr_HexDump(public_key2, public_key_length);
796
797                 return SEC_E_MESSAGE_ALTERED; /* DO NOT SEND CREDENTIALS! */
798         }
799
800         free(buffer);
801
802         return SEC_E_OK;
803 }
804
805 int credssp_sizeof_ts_password_creds(rdpCredssp* credssp)
806 {
807         int length = 0;
808
809         length += ber_sizeof_sequence_octet_string(credssp->identity.DomainLength * 2);
810         length += ber_sizeof_sequence_octet_string(credssp->identity.UserLength * 2);
811         length += ber_sizeof_sequence_octet_string(credssp->identity.PasswordLength * 2);
812
813         return length;
814 }
815
816 void credssp_read_ts_password_creds(rdpCredssp* credssp, wStream* s)
817 {
818         int length;
819
820         /* TSPasswordCreds (SEQUENCE) */
821         ber_read_sequence_tag(s, &length);
822
823         /* [0] domainName (OCTET STRING) */
824         ber_read_contextual_tag(s, 0, &length, TRUE);
825         ber_read_octet_string_tag(s, &length);
826         credssp->identity.DomainLength = (UINT32) length;
827         credssp->identity.Domain = (UINT16*) malloc(length);
828         CopyMemory(credssp->identity.Domain, Stream_Pointer(s), credssp->identity.DomainLength);
829         Stream_Seek(s, credssp->identity.DomainLength);
830         credssp->identity.DomainLength /= 2;
831
832         /* [1] userName (OCTET STRING) */
833         ber_read_contextual_tag(s, 1, &length, TRUE);
834         ber_read_octet_string_tag(s, &length);
835         credssp->identity.UserLength = (UINT32) length;
836         credssp->identity.User = (UINT16*) malloc(length);
837         CopyMemory(credssp->identity.User, Stream_Pointer(s), credssp->identity.UserLength);
838         Stream_Seek(s, credssp->identity.UserLength);
839         credssp->identity.UserLength /= 2;
840
841         /* [2] password (OCTET STRING) */
842         ber_read_contextual_tag(s, 2, &length, TRUE);
843         ber_read_octet_string_tag(s, &length);
844         credssp->identity.PasswordLength = (UINT32) length;
845         credssp->identity.Password = (UINT16*) malloc(length);
846         CopyMemory(credssp->identity.Password, Stream_Pointer(s), credssp->identity.PasswordLength);
847         Stream_Seek(s, credssp->identity.PasswordLength);
848         credssp->identity.PasswordLength /= 2;
849
850         credssp->identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
851 }
852
853 int credssp_write_ts_password_creds(rdpCredssp* credssp, wStream* s)
854 {
855         int size = 0;
856         int innerSize = credssp_sizeof_ts_password_creds(credssp);
857
858         /* TSPasswordCreds (SEQUENCE) */
859
860         size += ber_write_sequence_tag(s, innerSize);
861
862         /* [0] domainName (OCTET STRING) */
863         size += ber_write_sequence_octet_string(s, 0, (BYTE*) credssp->identity.Domain, credssp->identity.DomainLength * 2);
864
865         /* [1] userName (OCTET STRING) */
866         size += ber_write_sequence_octet_string(s, 1, (BYTE*) credssp->identity.User, credssp->identity.UserLength * 2);
867
868         /* [2] password (OCTET STRING) */
869         size += ber_write_sequence_octet_string(s, 2, (BYTE*) credssp->identity.Password, credssp->identity.PasswordLength * 2);
870
871         return size;
872 }
873
874 int credssp_sizeof_ts_credentials(rdpCredssp* credssp)
875 {
876         int size = 0;
877
878         size += ber_sizeof_integer(1);
879         size += ber_sizeof_contextual_tag(ber_sizeof_integer(1));
880         size += ber_sizeof_sequence_octet_string(ber_sizeof_sequence(credssp_sizeof_ts_password_creds(credssp)));
881
882         return size;
883 }
884
885 void credssp_read_ts_credentials(rdpCredssp* credssp, PSecBuffer ts_credentials)
886 {
887         wStream* s;
888         int length;
889         int ts_password_creds_length;
890
891         s = Stream_New(ts_credentials->pvBuffer, ts_credentials->cbBuffer);
892
893         /* TSCredentials (SEQUENCE) */
894         ber_read_sequence_tag(s, &length);
895
896         /* [0] credType (INTEGER) */
897         ber_read_contextual_tag(s, 0, &length, TRUE);
898         ber_read_integer(s, NULL);
899
900         /* [1] credentials (OCTET STRING) */
901         ber_read_contextual_tag(s, 1, &length, TRUE);
902         ber_read_octet_string_tag(s, &ts_password_creds_length);
903
904         credssp_read_ts_password_creds(credssp, s);
905
906         Stream_Free(s, FALSE);
907 }
908
909 int credssp_write_ts_credentials(rdpCredssp* credssp, wStream* s)
910 {
911         int size = 0;
912         int innerSize = credssp_sizeof_ts_credentials(credssp);
913         int passwordSize;
914
915         /* TSCredentials (SEQUENCE) */
916         size += ber_write_sequence_tag(s, innerSize);
917
918         /* [0] credType (INTEGER) */
919         size += ber_write_contextual_tag(s, 0, ber_sizeof_integer(1), TRUE);
920         size += ber_write_integer(s, 1);
921
922         /* [1] credentials (OCTET STRING) */
923
924         passwordSize = ber_sizeof_sequence(credssp_sizeof_ts_password_creds(credssp));
925
926         size += ber_write_contextual_tag(s, 1, ber_sizeof_octet_string(passwordSize), TRUE);
927         size += ber_write_octet_string_tag(s, passwordSize);
928         size += credssp_write_ts_password_creds(credssp, s);
929
930         return size;
931 }
932
933 /**
934  * Encode TSCredentials structure.
935  * @param credssp
936  */
937
938 void credssp_encode_ts_credentials(rdpCredssp* credssp)
939 {
940         wStream* s;
941         int length;
942         int DomainLength;
943         int UserLength;
944         int PasswordLength;
945
946         DomainLength = credssp->identity.DomainLength;
947         UserLength = credssp->identity.UserLength;
948         PasswordLength = credssp->identity.PasswordLength;
949
950         if (credssp->settings->RestrictedAdminModeRequired)
951         {
952                 credssp->identity.DomainLength = 0;
953                 credssp->identity.UserLength = 0;
954                 credssp->identity.PasswordLength = 0;
955         }
956
957         length = ber_sizeof_sequence(credssp_sizeof_ts_credentials(credssp));
958         sspi_SecBufferAlloc(&credssp->ts_credentials, length);
959
960         s = Stream_New(credssp->ts_credentials.pvBuffer, length);
961         credssp_write_ts_credentials(credssp, s);
962
963         if (credssp->settings->RestrictedAdminModeRequired)
964         {
965                 credssp->identity.DomainLength = DomainLength;
966                 credssp->identity.UserLength = UserLength;
967                 credssp->identity.PasswordLength = PasswordLength;
968         }
969
970         Stream_Free(s, FALSE);
971 }
972
973 SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp)
974 {
975         SecBuffer Buffers[2];
976         SecBufferDesc Message;
977         SECURITY_STATUS status;
978
979         credssp_encode_ts_credentials(credssp);
980
981         Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
982         Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */
983
984         sspi_SecBufferAlloc(&credssp->authInfo, credssp->ContextSizes.cbMaxSignature + credssp->ts_credentials.cbBuffer);
985
986         Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
987         Buffers[0].pvBuffer = credssp->authInfo.pvBuffer;
988         ZeroMemory(Buffers[0].pvBuffer, Buffers[0].cbBuffer);
989
990         Buffers[1].cbBuffer = credssp->ts_credentials.cbBuffer;
991         Buffers[1].pvBuffer = &((BYTE*) credssp->authInfo.pvBuffer)[Buffers[0].cbBuffer];
992         CopyMemory(Buffers[1].pvBuffer, credssp->ts_credentials.pvBuffer, Buffers[1].cbBuffer);
993
994         Message.cBuffers = 2;
995         Message.ulVersion = SECBUFFER_VERSION;
996         Message.pBuffers = (PSecBuffer) &Buffers;
997
998         status = credssp->table->EncryptMessage(&credssp->context, 0, &Message, credssp->send_seq_num++);
999
1000         if (status != SEC_E_OK)
1001                 return status;
1002
1003         return SEC_E_OK;
1004 }
1005
1006 SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp)
1007 {
1008         int length;
1009         BYTE* buffer;
1010         ULONG pfQOP;
1011         SecBuffer Buffers[2];
1012         SecBufferDesc Message;
1013         SECURITY_STATUS status;
1014
1015         Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
1016         Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */
1017
1018         if (credssp->authInfo.cbBuffer < 1)
1019         {
1020                 fprintf(stderr, "credssp_decrypt_ts_credentials missing authInfo buffer\n");
1021                 return SEC_E_INVALID_TOKEN;
1022         }
1023
1024         length = credssp->authInfo.cbBuffer;
1025         buffer = (BYTE*) malloc(length);
1026         CopyMemory(buffer, credssp->authInfo.pvBuffer, length);
1027
1028         Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
1029         Buffers[0].pvBuffer = buffer;
1030
1031         Buffers[1].cbBuffer = length - credssp->ContextSizes.cbMaxSignature;
1032         Buffers[1].pvBuffer = &buffer[credssp->ContextSizes.cbMaxSignature];
1033
1034         Message.cBuffers = 2;
1035         Message.ulVersion = SECBUFFER_VERSION;
1036         Message.pBuffers = (PSecBuffer) &Buffers;
1037
1038         status = credssp->table->DecryptMessage(&credssp->context, &Message, credssp->recv_seq_num++, &pfQOP);
1039
1040         if (status != SEC_E_OK)
1041                 return status;
1042
1043         credssp_read_ts_credentials(credssp, &Buffers[1]);
1044
1045         free(buffer);
1046
1047         return SEC_E_OK;
1048 }
1049
1050 int credssp_sizeof_nego_token(int length)
1051 {
1052         length = ber_sizeof_octet_string(length);
1053         length += ber_sizeof_contextual_tag(length);
1054         return length;
1055 }
1056
1057 int credssp_sizeof_nego_tokens(int length)
1058 {
1059         length = credssp_sizeof_nego_token(length);
1060         length += ber_sizeof_sequence_tag(length);
1061         length += ber_sizeof_sequence_tag(length);
1062         length += ber_sizeof_contextual_tag(length);
1063         return length;
1064 }
1065
1066 int credssp_sizeof_pub_key_auth(int length)
1067 {
1068         length = ber_sizeof_octet_string(length);
1069         length += ber_sizeof_contextual_tag(length);
1070         return length;
1071 }
1072
1073 int credssp_sizeof_auth_info(int length)
1074 {
1075         length = ber_sizeof_octet_string(length);
1076         length += ber_sizeof_contextual_tag(length);
1077         return length;
1078 }
1079
1080 int credssp_sizeof_ts_request(int length)
1081 {
1082         length += ber_sizeof_integer(2);
1083         length += ber_sizeof_contextual_tag(3);
1084         return length;
1085 }
1086
1087 /**
1088  * Send CredSSP message.
1089  * @param credssp
1090  */
1091
1092 void credssp_send(rdpCredssp* credssp)
1093 {
1094         wStream* s;
1095         int length;
1096         int ts_request_length;
1097         int nego_tokens_length;
1098         int pub_key_auth_length;
1099         int auth_info_length;
1100
1101         nego_tokens_length = (credssp->negoToken.cbBuffer > 0) ? credssp_sizeof_nego_tokens(credssp->negoToken.cbBuffer) : 0;
1102         pub_key_auth_length = (credssp->pubKeyAuth.cbBuffer > 0) ? credssp_sizeof_pub_key_auth(credssp->pubKeyAuth.cbBuffer) : 0;
1103         auth_info_length = (credssp->authInfo.cbBuffer > 0) ? credssp_sizeof_auth_info(credssp->authInfo.cbBuffer) : 0;
1104
1105         length = nego_tokens_length + pub_key_auth_length + auth_info_length;
1106
1107         ts_request_length = credssp_sizeof_ts_request(length);
1108
1109         s = Stream_New(NULL, ber_sizeof_sequence(ts_request_length));
1110
1111         /* TSRequest */
1112         ber_write_sequence_tag(s, ts_request_length); /* SEQUENCE */
1113
1114         /* [0] version */
1115         ber_write_contextual_tag(s, 0, 3, TRUE);
1116         ber_write_integer(s, 2); /* INTEGER */
1117
1118         /* [1] negoTokens (NegoData) */
1119         if (nego_tokens_length > 0)
1120         {
1121                 length = nego_tokens_length;
1122
1123                 length -= ber_write_contextual_tag(s, 1, ber_sizeof_sequence(ber_sizeof_sequence(ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer))), TRUE); /* NegoData */
1124                 length -= ber_write_sequence_tag(s, ber_sizeof_sequence(ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer))); /* SEQUENCE OF NegoDataItem */
1125                 length -= ber_write_sequence_tag(s, ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer)); /* NegoDataItem */
1126                 length -= ber_write_sequence_octet_string(s, 0, (BYTE*) credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer); /* OCTET STRING */
1127
1128                 // assert length == 0
1129         }
1130
1131         /* [2] authInfo (OCTET STRING) */
1132         if (auth_info_length > 0)
1133         {
1134                 length = auth_info_length;
1135                 length -= ber_write_sequence_octet_string(s, 2, credssp->authInfo.pvBuffer, credssp->authInfo.cbBuffer);
1136
1137                 // assert length == 0
1138         }
1139
1140         /* [3] pubKeyAuth (OCTET STRING) */
1141         if (pub_key_auth_length > 0)
1142         {
1143                 length = pub_key_auth_length;
1144                 length -= ber_write_sequence_octet_string(s, 3, credssp->pubKeyAuth.pvBuffer, credssp->pubKeyAuth.cbBuffer);
1145
1146                 // assert length == 0
1147         }
1148
1149         Stream_SealLength(s);
1150
1151         transport_write(credssp->transport, s);
1152
1153         Stream_Free(s, TRUE);
1154 }
1155
1156 /**
1157  * Receive CredSSP message.
1158  * @param credssp
1159  * @return
1160  */
1161
1162 int credssp_recv(rdpCredssp* credssp)
1163 {
1164         wStream* s;
1165         int length;
1166         int status;
1167         UINT32 version;
1168
1169         s = Stream_New(NULL, 4096);
1170
1171         status = transport_read(credssp->transport, s);
1172         Stream_Length(s) = status;
1173
1174         if (status < 0)
1175         {
1176                 fprintf(stderr, "credssp_recv() error: %d\n", status);
1177                 Stream_Free(s, TRUE);
1178                 return -1;
1179         }
1180
1181         /* TSRequest */
1182         if(!ber_read_sequence_tag(s, &length) ||
1183                 !ber_read_contextual_tag(s, 0, &length, TRUE) ||
1184                 !ber_read_integer(s, &version))
1185         {
1186                 Stream_Free(s, TRUE);
1187                 return -1;
1188         }
1189
1190         /* [1] negoTokens (NegoData) */
1191         if (ber_read_contextual_tag(s, 1, &length, TRUE) != FALSE)
1192         {
1193                 if (!ber_read_sequence_tag(s, &length) || /* SEQUENCE OF NegoDataItem */
1194                         !ber_read_sequence_tag(s, &length) || /* NegoDataItem */
1195                         !ber_read_contextual_tag(s, 0, &length, TRUE) || /* [0] negoToken */
1196                         !ber_read_octet_string_tag(s, &length) || /* OCTET STRING */
1197                         Stream_GetRemainingLength(s) < length)
1198                 {
1199                         Stream_Free(s, TRUE);
1200                         return -1;
1201                 }
1202                 sspi_SecBufferAlloc(&credssp->negoToken, length);
1203                 Stream_Read(s, credssp->negoToken.pvBuffer, length);
1204                 credssp->negoToken.cbBuffer = length;
1205         }
1206
1207         /* [2] authInfo (OCTET STRING) */
1208         if (ber_read_contextual_tag(s, 2, &length, TRUE) != FALSE)
1209         {
1210                 if(!ber_read_octet_string_tag(s, &length) || /* OCTET STRING */
1211                         Stream_GetRemainingLength(s) < length)
1212                 {
1213                         Stream_Free(s, TRUE);
1214                         return -1;
1215                 }
1216                 sspi_SecBufferAlloc(&credssp->authInfo, length);
1217                 Stream_Read(s, credssp->authInfo.pvBuffer, length);
1218                 credssp->authInfo.cbBuffer = length;
1219         }
1220
1221         /* [3] pubKeyAuth (OCTET STRING) */
1222         if (ber_read_contextual_tag(s, 3, &length, TRUE) != FALSE)
1223         {
1224                 if(!ber_read_octet_string_tag(s, &length) || /* OCTET STRING */
1225                         Stream_GetRemainingLength(s) < length)
1226                 {
1227                         Stream_Free(s, TRUE);
1228                         return -1;
1229                 }
1230                 sspi_SecBufferAlloc(&credssp->pubKeyAuth, length);
1231                 Stream_Read(s, credssp->pubKeyAuth.pvBuffer, length);
1232                 credssp->pubKeyAuth.cbBuffer = length;
1233         }
1234
1235         Stream_Free(s, TRUE);
1236
1237         return 0;
1238 }
1239
1240 void credssp_buffer_print(rdpCredssp* credssp)
1241 {
1242         if (credssp->negoToken.cbBuffer > 0)
1243         {
1244                 fprintf(stderr, "CredSSP.negoToken (length = %d):\n", (int) credssp->negoToken.cbBuffer);
1245                 winpr_HexDump(credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer);
1246         }
1247
1248         if (credssp->pubKeyAuth.cbBuffer > 0)
1249         {
1250                 fprintf(stderr, "CredSSP.pubKeyAuth (length = %d):\n", (int) credssp->pubKeyAuth.cbBuffer);
1251                 winpr_HexDump(credssp->pubKeyAuth.pvBuffer, credssp->pubKeyAuth.cbBuffer);
1252         }
1253
1254         if (credssp->authInfo.cbBuffer > 0)
1255         {
1256                 fprintf(stderr, "CredSSP.authInfo (length = %d):\n", (int) credssp->authInfo.cbBuffer);
1257                 winpr_HexDump(credssp->authInfo.pvBuffer, credssp->authInfo.cbBuffer);
1258         }
1259 }
1260
1261 void credssp_buffer_free(rdpCredssp* credssp)
1262 {
1263         sspi_SecBufferFree(&credssp->negoToken);
1264         sspi_SecBufferFree(&credssp->pubKeyAuth);
1265         sspi_SecBufferFree(&credssp->authInfo);
1266 }
1267
1268 /**
1269  * Create new CredSSP state machine.
1270  * @param transport
1271  * @return new CredSSP state machine.
1272  */
1273
1274 rdpCredssp* credssp_new(freerdp* instance, rdpTransport* transport, rdpSettings* settings)
1275 {
1276         rdpCredssp* credssp;
1277
1278         credssp = (rdpCredssp*) malloc(sizeof(rdpCredssp));
1279         ZeroMemory(credssp, sizeof(rdpCredssp));
1280
1281         if (credssp != NULL)
1282         {
1283                 HKEY hKey;
1284                 LONG status;
1285                 DWORD dwType;
1286                 DWORD dwSize;
1287
1288                 credssp->instance = instance;
1289                 credssp->settings = settings;
1290                 credssp->server = settings->ServerMode;
1291                 credssp->transport = transport;
1292                 credssp->send_seq_num = 0;
1293                 credssp->recv_seq_num = 0;
1294                 ZeroMemory(&credssp->negoToken, sizeof(SecBuffer));
1295                 ZeroMemory(&credssp->pubKeyAuth, sizeof(SecBuffer));
1296                 ZeroMemory(&credssp->authInfo, sizeof(SecBuffer));
1297                 SecInvalidateHandle(&credssp->context);
1298
1299                 if (credssp->server)
1300                 {
1301                         status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"),
1302                                         0, KEY_READ | KEY_WOW64_64KEY, &hKey);
1303
1304                         if (status == ERROR_SUCCESS)
1305                         {
1306                                 status = RegQueryValueEx(hKey, _T("SspiModule"), NULL, &dwType, NULL, &dwSize);
1307
1308                                 if (status == ERROR_SUCCESS)
1309                                 {
1310                                         credssp->SspiModule = (LPTSTR) malloc(dwSize + sizeof(TCHAR));
1311
1312                                         status = RegQueryValueEx(hKey, _T("SspiModule"), NULL, &dwType,
1313                                                         (BYTE*) credssp->SspiModule, &dwSize);
1314
1315                                         if (status == ERROR_SUCCESS)
1316                                         {
1317                                                 _tprintf(_T("Using SSPI Module: %s\n"), credssp->SspiModule);
1318                                                 RegCloseKey(hKey);
1319                                         }
1320                                 }
1321                         }
1322                 }
1323         }
1324
1325         return credssp;
1326 }
1327
1328 /**
1329  * Free CredSSP state machine.
1330  * @param credssp
1331  */
1332
1333 void credssp_free(rdpCredssp* credssp)
1334 {
1335         if (credssp != NULL)
1336         {
1337                 if (credssp->table)
1338                         credssp->table->DeleteSecurityContext(&credssp->context);
1339
1340                 sspi_SecBufferFree(&credssp->PublicKey);
1341                 sspi_SecBufferFree(&credssp->ts_credentials);
1342
1343                 free(credssp->ServicePrincipalName);
1344
1345                 free(credssp->identity.User);
1346                 free(credssp->identity.Domain);
1347                 free(credssp->identity.Password);
1348                 free(credssp);
1349         }
1350 }