~ubuntu-branches/ubuntu/vivid/freerdp/vivid

« back to all changes in this revision

Viewing changes to winpr/libwinpr/sspi/NTLM/ntlm.c

  • Committer: Package Import Robot
  • Author(s): Iain Lane
  • Date: 2014-11-11 12:20:50 UTC
  • mfrom: (1.2.5)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20141111122050-7z628f4ab38qxad5
Tags: upstream-1.1.0~git20140921.1.440916e+dfsg1
ImportĀ upstreamĀ versionĀ 1.1.0~git20140921.1.440916e+dfsg1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * WinPR: Windows Portable Runtime
 
3
 * NTLM Security Package
 
4
 *
 
5
 * Copyright 2011-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
#include <openssl/des.h>
 
26
#include <openssl/md4.h>
 
27
#include <openssl/hmac.h>
 
28
#include <openssl/rand.h>
 
29
#include <openssl/engine.h>
 
30
 
 
31
#include <winpr/crt.h>
 
32
#include <winpr/sspi.h>
 
33
#include <winpr/print.h>
 
34
#include <winpr/sysinfo.h>
 
35
#include <winpr/registry.h>
 
36
 
 
37
#include "ntlm.h"
 
38
#include "../sspi.h"
 
39
 
 
40
#include "ntlm_message.h"
 
41
 
 
42
char* NTLM_PACKAGE_NAME = "NTLM";
 
43
 
 
44
void ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation)
 
45
{
 
46
        DWORD nSize = 0;
 
47
 
 
48
        if (!Workstation)
 
49
        {
 
50
                GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize);
 
51
                Workstation = malloc(nSize);
 
52
                GetComputerNameExA(ComputerNameNetBIOS, Workstation, &nSize);
 
53
        }
 
54
 
 
55
        context->Workstation.Length = ConvertToUnicode(CP_UTF8, 0,
 
56
                        Workstation, -1, &context->Workstation.Buffer, 0) - 1;
 
57
        context->Workstation.Length *= 2;
 
58
 
 
59
        if (nSize > 0)
 
60
                free(Workstation);
 
61
}
 
62
 
 
63
void ntlm_SetContextServicePrincipalNameW(NTLM_CONTEXT* context, LPWSTR ServicePrincipalName)
 
64
{
 
65
        context->ServicePrincipalName.Length = _wcslen(ServicePrincipalName) * 2;
 
66
        if (!ServicePrincipalName)
 
67
        {
 
68
                context->ServicePrincipalName.Buffer = NULL;
 
69
                return;
 
70
        }
 
71
        context->ServicePrincipalName.Buffer = (PWSTR) malloc(context->ServicePrincipalName.Length + 2);
 
72
        CopyMemory(context->ServicePrincipalName.Buffer, ServicePrincipalName, context->ServicePrincipalName.Length + 2);
 
73
}
 
74
 
 
75
void ntlm_SetContextServicePrincipalNameA(NTLM_CONTEXT* context, char* ServicePrincipalName)
 
76
{
 
77
        context->ServicePrincipalName.Length = ConvertToUnicode(CP_UTF8, 0,
 
78
                        ServicePrincipalName, -1, &context->ServicePrincipalName.Buffer, 0) - 1;
 
79
        context->ServicePrincipalName.Length *= 2;
 
80
}
 
81
 
 
82
void ntlm_SetContextTargetName(NTLM_CONTEXT* context, char* TargetName)
 
83
{
 
84
        DWORD nSize = 0;
 
85
 
 
86
        if (!TargetName)
 
87
        {
 
88
                GetComputerNameExA(ComputerNameDnsHostname, NULL, &nSize);
 
89
                TargetName = malloc(nSize);
 
90
                GetComputerNameExA(ComputerNameDnsHostname, TargetName, &nSize);
 
91
                CharUpperA(TargetName);
 
92
        }
 
93
 
 
94
        context->TargetName.cbBuffer = ConvertToUnicode(CP_UTF8, 0,
 
95
                        TargetName, -1, (LPWSTR*) &context->TargetName.pvBuffer, 0) - 1;
 
96
        context->TargetName.cbBuffer *= 2;
 
97
 
 
98
        if (nSize > 0)
 
99
                free(TargetName);
 
100
}
 
101
 
 
102
NTLM_CONTEXT* ntlm_ContextNew()
 
103
{
 
104
        NTLM_CONTEXT* context;
 
105
 
 
106
        context = (NTLM_CONTEXT*) malloc(sizeof(NTLM_CONTEXT));
 
107
        ZeroMemory(context, sizeof(NTLM_CONTEXT));
 
108
 
 
109
        if (context != NULL)
 
110
        {
 
111
                HKEY hKey;
 
112
                LONG status;
 
113
                DWORD dwType;
 
114
                DWORD dwSize;
 
115
                DWORD dwValue;
 
116
 
 
117
                context->NTLMv2 = TRUE;
 
118
                context->UseMIC = FALSE;
 
119
                context->SendVersionInfo = TRUE;
 
120
                context->SendSingleHostData = FALSE;
 
121
                context->SendWorkstationName = TRUE;
 
122
 
 
123
                status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\WinPR\\NTLM"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
 
124
 
 
125
                if (status == ERROR_SUCCESS)
 
126
                {
 
127
                        if (RegQueryValueEx(hKey, _T("NTLMv2"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
 
128
                                context->NTLMv2 = dwValue ? 1 : 0;
 
129
 
 
130
                        if (RegQueryValueEx(hKey, _T("UseMIC"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
 
131
                                context->UseMIC = dwValue ? 1 : 0;
 
132
 
 
133
                        if (RegQueryValueEx(hKey, _T("SendVersionInfo"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
 
134
                                context->SendVersionInfo = dwValue ? 1 : 0;
 
135
 
 
136
                        if (RegQueryValueEx(hKey, _T("SendSingleHostData"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
 
137
                                context->SendSingleHostData = dwValue ? 1 : 0;
 
138
 
 
139
                        if (RegQueryValueEx(hKey, _T("SendWorkstationName"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
 
140
                                context->SendWorkstationName = dwValue ? 1 : 0;
 
141
 
 
142
                        if (RegQueryValueEx(hKey, _T("WorkstationName"), NULL, &dwType, NULL, &dwSize) == ERROR_SUCCESS)
 
143
                        {
 
144
                                char* workstation = (char*) malloc(dwSize + 1);
 
145
 
 
146
                                status = RegQueryValueExA(hKey, "WorkstationName", NULL, &dwType, (BYTE*) workstation, &dwSize);
 
147
                                workstation[dwSize] = '\0';
 
148
 
 
149
                                ntlm_SetContextWorkstation(context, workstation);
 
150
                                free(workstation);
 
151
                        }
 
152
 
 
153
                        RegCloseKey(hKey);
 
154
                }
 
155
 
 
156
                /*
 
157
                 * Extended Protection is enabled by default in Windows 7,
 
158
                 * but enabling it in WinPR breaks TS Gateway at this point
 
159
                 */
 
160
                context->SuppressExtendedProtection = FALSE;
 
161
 
 
162
                status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("System\\CurrentControlSet\\Control\\LSA"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
 
163
 
 
164
                if (status == ERROR_SUCCESS)
 
165
                {
 
166
                        if (RegQueryValueEx(hKey, _T("SuppressExtendedProtection"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
 
167
                                context->SuppressExtendedProtection = dwValue ? 1 : 0;
 
168
 
 
169
                        RegCloseKey(hKey);
 
170
                }
 
171
 
 
172
                context->NegotiateFlags = 0;
 
173
                context->LmCompatibilityLevel = 3;
 
174
                context->state = NTLM_STATE_INITIAL;
 
175
                memset(context->MachineID, 0xAA, sizeof(context->MachineID));
 
176
 
 
177
                if (context->NTLMv2)
 
178
                        context->UseMIC = TRUE;
 
179
        }
 
180
 
 
181
        return context;
 
182
}
 
183
 
 
184
void ntlm_ContextFree(NTLM_CONTEXT* context)
 
185
{
 
186
        if (!context)
 
187
                return;
 
188
 
 
189
        sspi_SecBufferFree(&context->NegotiateMessage);
 
190
        sspi_SecBufferFree(&context->ChallengeMessage);
 
191
        sspi_SecBufferFree(&context->AuthenticateMessage);
 
192
        sspi_SecBufferFree(&context->ChallengeTargetInfo);
 
193
        sspi_SecBufferFree(&context->TargetName);
 
194
        sspi_SecBufferFree(&context->NtChallengeResponse);
 
195
        sspi_SecBufferFree(&context->LmChallengeResponse);
 
196
 
 
197
        free(context->ServicePrincipalName.Buffer);
 
198
 
 
199
        free(context->identity.User);
 
200
        free(context->identity.Password);
 
201
        free(context->identity.Domain);
 
202
        free(context->Workstation.Buffer);
 
203
        free(context);
 
204
}
 
205
 
 
206
SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(SEC_WCHAR* pszPrincipal, SEC_WCHAR* pszPackage,
 
207
                ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
 
208
                void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
 
209
{
 
210
        CREDENTIALS* credentials;
 
211
        SEC_WINNT_AUTH_IDENTITY* identity;
 
212
 
 
213
        if (fCredentialUse == SECPKG_CRED_OUTBOUND)
 
214
        {
 
215
                credentials = sspi_CredentialsNew();
 
216
 
 
217
                identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
 
218
 
 
219
                if (identity != NULL)
 
220
                        CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
 
221
 
 
222
                sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
 
223
                sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
 
224
 
 
225
                return SEC_E_OK;
 
226
        }
 
227
        else if (fCredentialUse == SECPKG_CRED_INBOUND)
 
228
        {
 
229
                credentials = sspi_CredentialsNew();
 
230
 
 
231
                identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
 
232
 
 
233
                if (identity)
 
234
                        CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
 
235
                else
 
236
                        ZeroMemory(&(credentials->identity), sizeof(SEC_WINNT_AUTH_IDENTITY));
 
237
 
 
238
                sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
 
239
                sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
 
240
 
 
241
                return SEC_E_OK;
 
242
        }
 
243
 
 
244
        return SEC_E_OK;
 
245
}
 
246
 
 
247
SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA(SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage,
 
248
                ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
 
249
                void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
 
250
{
 
251
        CREDENTIALS* credentials;
 
252
        SEC_WINNT_AUTH_IDENTITY* identity;
 
253
 
 
254
        if (fCredentialUse == SECPKG_CRED_OUTBOUND)
 
255
        {
 
256
                credentials = sspi_CredentialsNew();
 
257
 
 
258
                identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
 
259
 
 
260
                if (identity != NULL)
 
261
                        CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
 
262
 
 
263
                sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
 
264
                sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
 
265
 
 
266
                return SEC_E_OK;
 
267
        }
 
268
        else if (fCredentialUse == SECPKG_CRED_INBOUND)
 
269
        {
 
270
                credentials = sspi_CredentialsNew();
 
271
 
 
272
                identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
 
273
 
 
274
                if (identity != NULL)
 
275
                        CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
 
276
 
 
277
                sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
 
278
                sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
 
279
 
 
280
                return SEC_E_OK;
 
281
        }
 
282
 
 
283
        return SEC_E_OK;
 
284
}
 
285
 
 
286
SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(PCredHandle phCredential)
 
287
{
 
288
        CREDENTIALS* credentials;
 
289
 
 
290
        if (!phCredential)
 
291
                return SEC_E_INVALID_HANDLE;
 
292
 
 
293
        credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
 
294
 
 
295
        if (!credentials)
 
296
                return SEC_E_INVALID_HANDLE;
 
297
 
 
298
        sspi_CredentialsFree(credentials);
 
299
 
 
300
        return SEC_E_OK;
 
301
}
 
302
 
 
303
SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesW(PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
 
304
{
 
305
        if (ulAttribute == SECPKG_CRED_ATTR_NAMES)
 
306
        {
 
307
                return SEC_E_OK;
 
308
        }
 
309
 
 
310
        return SEC_E_UNSUPPORTED_FUNCTION;
 
311
}
 
312
 
 
313
SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesA(PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
 
314
{
 
315
        return ntlm_QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
 
316
}
 
317
 
 
318
/**
 
319
 * @see http://msdn.microsoft.com/en-us/library/windows/desktop/aa374707
 
320
 */
 
321
SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext,
 
322
                PSecBufferDesc pInput, ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext,
 
323
                PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsTimeStamp)
 
324
{
 
325
        NTLM_CONTEXT* context;
 
326
        SECURITY_STATUS status;
 
327
        CREDENTIALS* credentials;
 
328
        PSecBuffer input_buffer;
 
329
        PSecBuffer output_buffer;
 
330
 
 
331
        context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
 
332
 
 
333
        if (!context)
 
334
        {
 
335
                context = ntlm_ContextNew();
 
336
 
 
337
                if (!context)
 
338
                        return SEC_E_INSUFFICIENT_MEMORY;
 
339
 
 
340
                context->server = 1;
 
341
 
 
342
                if (fContextReq & ASC_REQ_CONFIDENTIALITY)
 
343
                        context->confidentiality = 1;
 
344
 
 
345
                credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
 
346
                sspi_CopyAuthIdentity(&context->identity, &credentials->identity);
 
347
 
 
348
                ntlm_SetContextTargetName(context, NULL);
 
349
 
 
350
                sspi_SecureHandleSetLowerPointer(phNewContext, context);
 
351
                sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NTLM_PACKAGE_NAME);
 
352
        }
 
353
 
 
354
        if (context->state == NTLM_STATE_INITIAL)
 
355
        {
 
356
                context->state = NTLM_STATE_NEGOTIATE;
 
357
 
 
358
                if (!pInput)
 
359
                        return SEC_E_INVALID_TOKEN;
 
360
 
 
361
                if (pInput->cBuffers < 1)
 
362
                        return SEC_E_INVALID_TOKEN;
 
363
 
 
364
                input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
 
365
 
 
366
                if (!input_buffer)
 
367
                        return SEC_E_INVALID_TOKEN;
 
368
 
 
369
                if (input_buffer->cbBuffer < 1)
 
370
                        return SEC_E_INVALID_TOKEN;
 
371
 
 
372
                status = ntlm_read_NegotiateMessage(context, input_buffer);
 
373
 
 
374
                if (context->state == NTLM_STATE_CHALLENGE)
 
375
                {
 
376
                        if (!pOutput)
 
377
                                return SEC_E_INVALID_TOKEN;
 
378
 
 
379
                        if (pOutput->cBuffers < 1)
 
380
                                return SEC_E_INVALID_TOKEN;
 
381
 
 
382
                        output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
 
383
 
 
384
                        if (!output_buffer->BufferType)
 
385
                                return SEC_E_INVALID_TOKEN;
 
386
 
 
387
                        if (output_buffer->cbBuffer < 1)
 
388
                                return SEC_E_INSUFFICIENT_MEMORY;
 
389
 
 
390
                        return ntlm_write_ChallengeMessage(context, output_buffer);
 
391
                }
 
392
 
 
393
                return SEC_E_OUT_OF_SEQUENCE;
 
394
        }
 
395
        else if (context->state == NTLM_STATE_AUTHENTICATE)
 
396
        {
 
397
                if (!pInput)
 
398
                        return SEC_E_INVALID_TOKEN;
 
399
 
 
400
                if (pInput->cBuffers < 1)
 
401
                        return SEC_E_INVALID_TOKEN;
 
402
 
 
403
                input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
 
404
 
 
405
                if (!input_buffer)
 
406
                        return SEC_E_INVALID_TOKEN;
 
407
 
 
408
                if (input_buffer->cbBuffer < 1)
 
409
                        return SEC_E_INVALID_TOKEN;
 
410
 
 
411
                status = ntlm_read_AuthenticateMessage(context, input_buffer);
 
412
 
 
413
                if (pOutput)
 
414
                {
 
415
                        int i;
 
416
 
 
417
                        for (i = 0; i < pOutput->cBuffers; i++)
 
418
                        {
 
419
                                pOutput->pBuffers[i].cbBuffer = 0;
 
420
                                pOutput->pBuffers[i].BufferType = SECBUFFER_TOKEN;
 
421
                        }
 
422
                }
 
423
 
 
424
                return status;
 
425
        }
 
426
 
 
427
        return SEC_E_OUT_OF_SEQUENCE;
 
428
}
 
429
 
 
430
SECURITY_STATUS SEC_ENTRY ntlm_ImpersonateSecurityContext(PCtxtHandle phContext)
 
431
{
 
432
        return SEC_E_OK;
 
433
}
 
434
 
 
435
SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(PCredHandle phCredential, PCtxtHandle phContext,
 
436
                SEC_WCHAR* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
 
437
                PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
 
438
                PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
 
439
{
 
440
        NTLM_CONTEXT* context;
 
441
        SECURITY_STATUS status;
 
442
        CREDENTIALS* credentials;
 
443
        PSecBuffer input_buffer = NULL;
 
444
        PSecBuffer output_buffer = NULL;
 
445
        PSecBuffer channel_bindings = NULL;
 
446
 
 
447
        context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
 
448
 
 
449
        if (!context)
 
450
        {
 
451
                context = ntlm_ContextNew();
 
452
 
 
453
                if (!context)
 
454
                        return SEC_E_INSUFFICIENT_MEMORY;
 
455
 
 
456
                if (fContextReq & ISC_REQ_CONFIDENTIALITY)
 
457
                        context->confidentiality = 1;
 
458
 
 
459
                credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
 
460
 
 
461
                if (context->Workstation.Length < 1)
 
462
                        ntlm_SetContextWorkstation(context, NULL);
 
463
 
 
464
                ntlm_SetContextServicePrincipalNameW(context, pszTargetName);
 
465
                sspi_CopyAuthIdentity(&context->identity, &credentials->identity);
 
466
 
 
467
                sspi_SecureHandleSetLowerPointer(phNewContext, context);
 
468
                sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NTLM_PACKAGE_NAME);
 
469
        }
 
470
 
 
471
        if ((!pInput) || (context->state == NTLM_STATE_AUTHENTICATE))
 
472
        {
 
473
                if (!pOutput)
 
474
                        return SEC_E_INVALID_TOKEN;
 
475
 
 
476
                if (pOutput->cBuffers < 1)
 
477
                        return SEC_E_INVALID_TOKEN;
 
478
 
 
479
                output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
 
480
 
 
481
                if (!output_buffer)
 
482
                        return SEC_E_INVALID_TOKEN;
 
483
 
 
484
                if (output_buffer->cbBuffer < 1)
 
485
                        return SEC_E_INVALID_TOKEN;
 
486
 
 
487
                if (context->state == NTLM_STATE_INITIAL)
 
488
                        context->state = NTLM_STATE_NEGOTIATE;
 
489
 
 
490
                if (context->state == NTLM_STATE_NEGOTIATE)
 
491
                        return ntlm_write_NegotiateMessage(context, output_buffer);
 
492
 
 
493
                return SEC_E_OUT_OF_SEQUENCE;
 
494
        }
 
495
        else
 
496
        {
 
497
                if (pInput->cBuffers < 1)
 
498
                        return SEC_E_INVALID_TOKEN;
 
499
 
 
500
                input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
 
501
 
 
502
                if (!input_buffer)
 
503
                        return SEC_E_INVALID_TOKEN;
 
504
 
 
505
                if (input_buffer->cbBuffer < 1)
 
506
                        return SEC_E_INVALID_TOKEN;
 
507
 
 
508
                channel_bindings = sspi_FindSecBuffer(pInput, SECBUFFER_CHANNEL_BINDINGS);
 
509
 
 
510
                if (channel_bindings)
 
511
                {
 
512
                        context->Bindings.BindingsLength = channel_bindings->cbBuffer;
 
513
                        context->Bindings.Bindings = (SEC_CHANNEL_BINDINGS*) channel_bindings->pvBuffer;
 
514
                }
 
515
 
 
516
                if (context->state == NTLM_STATE_CHALLENGE)
 
517
                {
 
518
                        status = ntlm_read_ChallengeMessage(context, input_buffer);
 
519
 
 
520
                        if (!pOutput)
 
521
                                return SEC_E_INVALID_TOKEN;
 
522
 
 
523
                        if (pOutput->cBuffers < 1)
 
524
                                return SEC_E_INVALID_TOKEN;
 
525
 
 
526
                        output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
 
527
 
 
528
                        if (!output_buffer)
 
529
                                return SEC_E_INVALID_TOKEN;
 
530
 
 
531
                        if (output_buffer->cbBuffer < 1)
 
532
                                return SEC_E_INSUFFICIENT_MEMORY;
 
533
 
 
534
                        if (context->state == NTLM_STATE_AUTHENTICATE)
 
535
                                return ntlm_write_AuthenticateMessage(context, output_buffer);
 
536
                }
 
537
 
 
538
                return SEC_E_OUT_OF_SEQUENCE;
 
539
        }
 
540
 
 
541
        return SEC_E_OUT_OF_SEQUENCE;
 
542
}
 
543
 
 
544
/**
 
545
 * @see http://msdn.microsoft.com/en-us/library/windows/desktop/aa375512%28v=vs.85%29.aspx
 
546
 */
 
547
SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA(PCredHandle phCredential, PCtxtHandle phContext,
 
548
                SEC_CHAR* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
 
549
                PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
 
550
                PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
 
551
{
 
552
        SECURITY_STATUS status;
 
553
        SEC_WCHAR* pszTargetNameW = NULL;
 
554
 
 
555
        if (pszTargetName != NULL)
 
556
        {
 
557
                ConvertToUnicode(CP_UTF8, 0, pszTargetName, -1, &pszTargetNameW, 0);
 
558
        }
 
559
 
 
560
        status = ntlm_InitializeSecurityContextW(phCredential, phContext, pszTargetNameW, fContextReq,
 
561
                Reserved1, TargetDataRep, pInput, Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
 
562
 
 
563
        if (pszTargetNameW != NULL)
 
564
                free(pszTargetNameW);
 
565
        
 
566
        return status;
 
567
}
 
568
 
 
569
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375354 */
 
570
 
 
571
SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext)
 
572
{
 
573
        NTLM_CONTEXT* context;
 
574
 
 
575
        context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
 
576
 
 
577
        if (!context)
 
578
                return SEC_E_INVALID_HANDLE;
 
579
 
 
580
        ntlm_ContextFree(context);
 
581
 
 
582
        return SEC_E_OK;
 
583
}
 
584
 
 
585
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa379337/ */
 
586
 
 
587
SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer)
 
588
{
 
589
        if (!phContext)
 
590
                return SEC_E_INVALID_HANDLE;
 
591
 
 
592
        if (!pBuffer)
 
593
                return SEC_E_INSUFFICIENT_MEMORY;
 
594
 
 
595
        if (ulAttribute == SECPKG_ATTR_SIZES)
 
596
        {
 
597
                SecPkgContext_Sizes* ContextSizes = (SecPkgContext_Sizes*) pBuffer;
 
598
 
 
599
                ContextSizes->cbMaxToken = 2010;
 
600
                ContextSizes->cbMaxSignature = 16;
 
601
                ContextSizes->cbBlockSize = 0;
 
602
                ContextSizes->cbSecurityTrailer = 16;
 
603
 
 
604
                return SEC_E_OK;
 
605
        }
 
606
 
 
607
        return SEC_E_UNSUPPORTED_FUNCTION;
 
608
}
 
609
 
 
610
SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer)
 
611
{
 
612
        return ntlm_QueryContextAttributesW(phContext, ulAttribute, pBuffer);
 
613
}
 
614
 
 
615
SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(PCtxtHandle phContext)
 
616
{
 
617
        return SEC_E_OK;
 
618
}
 
619
 
 
620
SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
 
621
{
 
622
        int index;
 
623
        int length;
 
624
        void* data;
 
625
        UINT32 SeqNo;
 
626
        HMAC_CTX hmac;
 
627
        BYTE digest[16];
 
628
        BYTE checksum[8];
 
629
        BYTE* signature;
 
630
        ULONG version = 1;
 
631
        NTLM_CONTEXT* context;
 
632
        PSecBuffer data_buffer = NULL;
 
633
        PSecBuffer signature_buffer = NULL;
 
634
 
 
635
        SeqNo = MessageSeqNo;
 
636
        context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
 
637
 
 
638
        for (index = 0; index < (int) pMessage->cBuffers; index++)
 
639
        {
 
640
                if (pMessage->pBuffers[index].BufferType == SECBUFFER_DATA)
 
641
                        data_buffer = &pMessage->pBuffers[index];
 
642
                else if (pMessage->pBuffers[index].BufferType == SECBUFFER_TOKEN)
 
643
                        signature_buffer = &pMessage->pBuffers[index];
 
644
        }
 
645
 
 
646
        if (!data_buffer)
 
647
                return SEC_E_INVALID_TOKEN;
 
648
 
 
649
        if (!signature_buffer)
 
650
                return SEC_E_INVALID_TOKEN;
 
651
 
 
652
        /* Copy original data buffer */
 
653
        length = data_buffer->cbBuffer;
 
654
        data = malloc(length);
 
655
        CopyMemory(data, data_buffer->pvBuffer, length);
 
656
 
 
657
        /* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */
 
658
        HMAC_CTX_init(&hmac);
 
659
        HMAC_Init_ex(&hmac, context->SendSigningKey, 16, EVP_md5(), NULL);
 
660
        HMAC_Update(&hmac, (void*) &(SeqNo), 4);
 
661
        HMAC_Update(&hmac, data, length);
 
662
        HMAC_Final(&hmac, digest, NULL);
 
663
        HMAC_CTX_cleanup(&hmac);
 
664
 
 
665
        /* Encrypt message using with RC4, result overwrites original buffer */
 
666
 
 
667
        if (context->confidentiality)
 
668
                RC4(&context->SendRc4Seal, length, data, data_buffer->pvBuffer);
 
669
        else
 
670
                CopyMemory(data_buffer->pvBuffer, data, length);
 
671
 
 
672
#ifdef WITH_DEBUG_NTLM
 
673
        fprintf(stderr, "Data Buffer (length = %d)\n", length);
 
674
        winpr_HexDump(data, length);
 
675
        fprintf(stderr, "\n");
 
676
 
 
677
        fprintf(stderr, "Encrypted Data Buffer (length = %d)\n", (int) data_buffer->cbBuffer);
 
678
        winpr_HexDump(data_buffer->pvBuffer, data_buffer->cbBuffer);
 
679
        fprintf(stderr, "\n");
 
680
#endif
 
681
 
 
682
        free(data);
 
683
 
 
684
        /* RC4-encrypt first 8 bytes of digest */
 
685
        RC4(&context->SendRc4Seal, 8, digest, checksum);
 
686
 
 
687
        signature = (BYTE*) signature_buffer->pvBuffer;
 
688
 
 
689
        /* Concatenate version, ciphertext and sequence number to build signature */
 
690
        CopyMemory(signature, (void*) &version, 4);
 
691
        CopyMemory(&signature[4], (void*) checksum, 8);
 
692
        CopyMemory(&signature[12], (void*) &(SeqNo), 4);
 
693
        context->SendSeqNum++;
 
694
 
 
695
#ifdef WITH_DEBUG_NTLM
 
696
        fprintf(stderr, "Signature (length = %d)\n", (int) signature_buffer->cbBuffer);
 
697
        winpr_HexDump(signature_buffer->pvBuffer, signature_buffer->cbBuffer);
 
698
        fprintf(stderr, "\n");
 
699
#endif
 
700
 
 
701
        return SEC_E_OK;
 
702
}
 
703
 
 
704
SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
 
705
{
 
706
        int index;
 
707
        int length;
 
708
        void* data;
 
709
        UINT32 SeqNo;
 
710
        HMAC_CTX hmac;
 
711
        BYTE digest[16];
 
712
        BYTE checksum[8];
 
713
        UINT32 version = 1;
 
714
        NTLM_CONTEXT* context;
 
715
        BYTE expected_signature[16];
 
716
        PSecBuffer data_buffer = NULL;
 
717
        PSecBuffer signature_buffer = NULL;
 
718
 
 
719
        SeqNo = (UINT32) MessageSeqNo;
 
720
        context = sspi_SecureHandleGetLowerPointer(phContext);
 
721
 
 
722
        for (index = 0; index < (int) pMessage->cBuffers; index++)
 
723
        {
 
724
                if (pMessage->pBuffers[index].BufferType == SECBUFFER_DATA)
 
725
                        data_buffer = &pMessage->pBuffers[index];
 
726
                else if (pMessage->pBuffers[index].BufferType == SECBUFFER_TOKEN)
 
727
                        signature_buffer = &pMessage->pBuffers[index];
 
728
        }
 
729
 
 
730
        if (!data_buffer)
 
731
                return SEC_E_INVALID_TOKEN;
 
732
 
 
733
        if (!signature_buffer)
 
734
                return SEC_E_INVALID_TOKEN;
 
735
 
 
736
        /* Copy original data buffer */
 
737
        length = data_buffer->cbBuffer;
 
738
        data = malloc(length);
 
739
        CopyMemory(data, data_buffer->pvBuffer, length);
 
740
 
 
741
        /* Decrypt message using with RC4, result overwrites original buffer */
 
742
 
 
743
        if (context->confidentiality)
 
744
                RC4(&context->RecvRc4Seal, length, data, data_buffer->pvBuffer);
 
745
        else
 
746
                CopyMemory(data_buffer->pvBuffer, data, length);
 
747
 
 
748
        /* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */
 
749
        HMAC_CTX_init(&hmac);
 
750
        HMAC_Init_ex(&hmac, context->RecvSigningKey, 16, EVP_md5(), NULL);
 
751
        HMAC_Update(&hmac, (void*) &(SeqNo), 4);
 
752
        HMAC_Update(&hmac, data_buffer->pvBuffer, data_buffer->cbBuffer);
 
753
        HMAC_Final(&hmac, digest, NULL);
 
754
        HMAC_CTX_cleanup(&hmac);
 
755
 
 
756
#ifdef WITH_DEBUG_NTLM
 
757
        fprintf(stderr, "Encrypted Data Buffer (length = %d)\n", length);
 
758
        winpr_HexDump(data, length);
 
759
        fprintf(stderr, "\n");
 
760
 
 
761
        fprintf(stderr, "Data Buffer (length = %d)\n", (int) data_buffer->cbBuffer);
 
762
        winpr_HexDump(data_buffer->pvBuffer, data_buffer->cbBuffer);
 
763
        fprintf(stderr, "\n");
 
764
#endif
 
765
 
 
766
        free(data);
 
767
 
 
768
        /* RC4-encrypt first 8 bytes of digest */
 
769
        RC4(&context->RecvRc4Seal, 8, digest, checksum);
 
770
 
 
771
        /* Concatenate version, ciphertext and sequence number to build signature */
 
772
        CopyMemory(expected_signature, (void*) &version, 4);
 
773
        CopyMemory(&expected_signature[4], (void*) checksum, 8);
 
774
        CopyMemory(&expected_signature[12], (void*) &(SeqNo), 4);
 
775
        context->RecvSeqNum++;
 
776
 
 
777
        if (memcmp(signature_buffer->pvBuffer, expected_signature, 16) != 0)
 
778
        {
 
779
                /* signature verification failed! */
 
780
                fprintf(stderr, "signature verification failed, something nasty is going on!\n");
 
781
 
 
782
                fprintf(stderr, "Expected Signature:\n");
 
783
                winpr_HexDump(expected_signature, 16);
 
784
                fprintf(stderr, "Actual Signature:\n");
 
785
                winpr_HexDump(signature_buffer->pvBuffer, 16);
 
786
 
 
787
                return SEC_E_MESSAGE_ALTERED;
 
788
        }
 
789
 
 
790
        return SEC_E_OK;
 
791
}
 
792
 
 
793
SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
 
794
{
 
795
        return SEC_E_OK;
 
796
}
 
797
 
 
798
SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
 
799
{
 
800
        return SEC_E_OK;
 
801
}
 
802
 
 
803
const SecurityFunctionTableA NTLM_SecurityFunctionTableA =
 
804
{
 
805
        1, /* dwVersion */
 
806
        NULL, /* EnumerateSecurityPackages */
 
807
        ntlm_QueryCredentialsAttributesA, /* QueryCredentialsAttributes */
 
808
        ntlm_AcquireCredentialsHandleA, /* AcquireCredentialsHandle */
 
809
        ntlm_FreeCredentialsHandle, /* FreeCredentialsHandle */
 
810
        NULL, /* Reserved2 */
 
811
        ntlm_InitializeSecurityContextA, /* InitializeSecurityContext */
 
812
        ntlm_AcceptSecurityContext, /* AcceptSecurityContext */
 
813
        NULL, /* CompleteAuthToken */
 
814
        ntlm_DeleteSecurityContext, /* DeleteSecurityContext */
 
815
        NULL, /* ApplyControlToken */
 
816
        ntlm_QueryContextAttributesA, /* QueryContextAttributes */
 
817
        ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
 
818
        ntlm_RevertSecurityContext, /* RevertSecurityContext */
 
819
        ntlm_MakeSignature, /* MakeSignature */
 
820
        ntlm_VerifySignature, /* VerifySignature */
 
821
        NULL, /* FreeContextBuffer */
 
822
        NULL, /* QuerySecurityPackageInfo */
 
823
        NULL, /* Reserved3 */
 
824
        NULL, /* Reserved4 */
 
825
        NULL, /* ExportSecurityContext */
 
826
        NULL, /* ImportSecurityContext */
 
827
        NULL, /* AddCredentials */
 
828
        NULL, /* Reserved8 */
 
829
        NULL, /* QuerySecurityContextToken */
 
830
        ntlm_EncryptMessage, /* EncryptMessage */
 
831
        ntlm_DecryptMessage, /* DecryptMessage */
 
832
        NULL, /* SetContextAttributes */
 
833
};
 
834
 
 
835
const SecurityFunctionTableW NTLM_SecurityFunctionTableW =
 
836
{
 
837
        1, /* dwVersion */
 
838
        NULL, /* EnumerateSecurityPackages */
 
839
        ntlm_QueryCredentialsAttributesW, /* QueryCredentialsAttributes */
 
840
        ntlm_AcquireCredentialsHandleW, /* AcquireCredentialsHandle */
 
841
        ntlm_FreeCredentialsHandle, /* FreeCredentialsHandle */
 
842
        NULL, /* Reserved2 */
 
843
        ntlm_InitializeSecurityContextW, /* InitializeSecurityContext */
 
844
        ntlm_AcceptSecurityContext, /* AcceptSecurityContext */
 
845
        NULL, /* CompleteAuthToken */
 
846
        ntlm_DeleteSecurityContext, /* DeleteSecurityContext */
 
847
        NULL, /* ApplyControlToken */
 
848
        ntlm_QueryContextAttributesW, /* QueryContextAttributes */
 
849
        ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
 
850
        ntlm_RevertSecurityContext, /* RevertSecurityContext */
 
851
        ntlm_MakeSignature, /* MakeSignature */
 
852
        ntlm_VerifySignature, /* VerifySignature */
 
853
        NULL, /* FreeContextBuffer */
 
854
        NULL, /* QuerySecurityPackageInfo */
 
855
        NULL, /* Reserved3 */
 
856
        NULL, /* Reserved4 */
 
857
        NULL, /* ExportSecurityContext */
 
858
        NULL, /* ImportSecurityContext */
 
859
        NULL, /* AddCredentials */
 
860
        NULL, /* Reserved8 */
 
861
        NULL, /* QuerySecurityContextToken */
 
862
        ntlm_EncryptMessage, /* EncryptMessage */
 
863
        ntlm_DecryptMessage, /* DecryptMessage */
 
864
        NULL, /* SetContextAttributes */
 
865
};
 
866
 
 
867
const SecPkgInfoA NTLM_SecPkgInfoA =
 
868
{
 
869
        0x00082B37, /* fCapabilities */
 
870
        1, /* wVersion */
 
871
        0x000A, /* wRPCID */
 
872
        0x00000B48, /* cbMaxToken */
 
873
        "NTLM", /* Name */
 
874
        "NTLM Security Package" /* Comment */
 
875
};
 
876
 
 
877
WCHAR NTLM_SecPkgInfoW_Name[] = { 'N','T','L','M','\0' };
 
878
 
 
879
WCHAR NTLM_SecPkgInfoW_Comment[] =
 
880
{
 
881
        'N','T','L','M',' ',
 
882
        'S','e','c','u','r','i','t','y',' ',
 
883
        'P','a','c','k','a','g','e','\0'
 
884
};
 
885
 
 
886
const SecPkgInfoW NTLM_SecPkgInfoW =
 
887
{
 
888
        0x00082B37, /* fCapabilities */
 
889
        1, /* wVersion */
 
890
        0x000A, /* wRPCID */
 
891
        0x00000B48, /* cbMaxToken */
 
892
        NTLM_SecPkgInfoW_Name, /* Name */
 
893
        NTLM_SecPkgInfoW_Comment /* Comment */
 
894
};