1 /*
2 * Copyright 2005, 2006 Kai Blin
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 *
18 * This file implements the NTLM security provider.
19 */
20
21 #include "precomp.h"
22
23 #include <assert.h>
24 #include <stdio.h>
25 #include <wincred.h>
26 #include <lm.h>
27
28 #include "hmac_md5.h"
29
30 #include <wine/unicode.h>
31 #include <wine/debug.h>
32 WINE_DEFAULT_DEBUG_CHANNEL(ntlm);
33 WINE_DECLARE_DEBUG_CHANNEL(winediag);
34
35 #define NTLM_MAX_BUF 1904
36 #define MIN_NTLM_AUTH_MAJOR_VERSION 3
37 #define MIN_NTLM_AUTH_MINOR_VERSION 0
38 #ifndef __REACTOS__
39 #define MIN_NTLM_AUTH_MICRO_VERSION 25
40 #else
41 #define MIN_NTLM_AUTH_MICRO_VERSION 23
42 #endif
43
44 static CHAR ntlm_auth[] = "ntlm_auth";
45
46 /***********************************************************************
47 * QueryCredentialsAttributesA
48 */
ntlm_QueryCredentialsAttributesA(PCredHandle phCredential,ULONG ulAttribute,PVOID pBuffer)49 static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesA(
50 PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
51 {
52 SECURITY_STATUS ret;
53
54 TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer);
55
56 if(ulAttribute == SECPKG_ATTR_NAMES)
57 {
58 FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
59 ret = SEC_E_UNSUPPORTED_FUNCTION;
60 }
61 else
62 ret = SEC_E_UNSUPPORTED_FUNCTION;
63
64 return ret;
65 }
66
67 /***********************************************************************
68 * QueryCredentialsAttributesW
69 */
ntlm_QueryCredentialsAttributesW(PCredHandle phCredential,ULONG ulAttribute,PVOID pBuffer)70 static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesW(
71 PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
72 {
73 SECURITY_STATUS ret;
74
75 TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer);
76
77 if(ulAttribute == SECPKG_ATTR_NAMES)
78 {
79 FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
80 ret = SEC_E_UNSUPPORTED_FUNCTION;
81 }
82 else
83 ret = SEC_E_UNSUPPORTED_FUNCTION;
84
85 return ret;
86 }
87
ntlm_GetUsernameArg(LPCWSTR userW,INT userW_length)88 static char *ntlm_GetUsernameArg(LPCWSTR userW, INT userW_length)
89 {
90 static const char username_arg[] = "--username=";
91 char *user;
92 int unixcp_size;
93
94 unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
95 userW, userW_length, NULL, 0, NULL, NULL) + sizeof(username_arg);
96 user = HeapAlloc(GetProcessHeap(), 0, unixcp_size);
97 if (!user) return NULL;
98 memcpy(user, username_arg, sizeof(username_arg) - 1);
99 WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, userW, userW_length,
100 user + sizeof(username_arg) - 1,
101 unixcp_size - sizeof(username_arg) + 1, NULL, NULL);
102 user[unixcp_size - 1] = '\0';
103 return user;
104 }
105
ntlm_GetDomainArg(LPCWSTR domainW,INT domainW_length)106 static char *ntlm_GetDomainArg(LPCWSTR domainW, INT domainW_length)
107 {
108 static const char domain_arg[] = "--domain=";
109 char *domain;
110 int unixcp_size;
111
112 unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
113 domainW, domainW_length, NULL, 0, NULL, NULL) + sizeof(domain_arg);
114 domain = HeapAlloc(GetProcessHeap(), 0, unixcp_size);
115 if (!domain) return NULL;
116 memcpy(domain, domain_arg, sizeof(domain_arg) - 1);
117 WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, domainW,
118 domainW_length, domain + sizeof(domain_arg) - 1,
119 unixcp_size - sizeof(domain) + 1, NULL, NULL);
120 domain[unixcp_size - 1] = '\0';
121 return domain;
122 }
123
124 /***********************************************************************
125 * AcquireCredentialsHandleW
126 */
ntlm_AcquireCredentialsHandleW(SEC_WCHAR * pszPrincipal,SEC_WCHAR * pszPackage,ULONG fCredentialUse,PLUID pLogonID,PVOID pAuthData,SEC_GET_KEY_FN pGetKeyFn,PVOID pGetKeyArgument,PCredHandle phCredential,PTimeStamp ptsExpiry)127 SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(
128 SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse,
129 PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
130 PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
131 {
132 SECURITY_STATUS ret;
133 PNtlmCredentials ntlm_cred;
134 LPWSTR domain = NULL, user = NULL, password = NULL;
135 PSEC_WINNT_AUTH_IDENTITY_W auth_data = NULL;
136
137 TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n",
138 debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse,
139 pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
140
141 switch(fCredentialUse)
142 {
143 case SECPKG_CRED_INBOUND:
144 ntlm_cred = HeapAlloc(GetProcessHeap(), 0, sizeof(*ntlm_cred));
145 if (!ntlm_cred)
146 ret = SEC_E_INSUFFICIENT_MEMORY;
147 else
148 {
149 ntlm_cred->mode = NTLM_SERVER;
150 ntlm_cred->username_arg = NULL;
151 ntlm_cred->domain_arg = NULL;
152 ntlm_cred->password = NULL;
153 ntlm_cred->pwlen = 0;
154 ntlm_cred->no_cached_credentials = 0;
155
156 phCredential->dwUpper = fCredentialUse;
157 phCredential->dwLower = (ULONG_PTR)ntlm_cred;
158 ret = SEC_E_OK;
159 }
160 break;
161 case SECPKG_CRED_OUTBOUND:
162 {
163 auth_data = pAuthData;
164 ntlm_cred = HeapAlloc(GetProcessHeap(), 0, sizeof(*ntlm_cred));
165 if (!ntlm_cred)
166 {
167 ret = SEC_E_INSUFFICIENT_MEMORY;
168 break;
169 }
170 ntlm_cred->mode = NTLM_CLIENT;
171 ntlm_cred->username_arg = NULL;
172 ntlm_cred->domain_arg = NULL;
173 ntlm_cred->password = NULL;
174 ntlm_cred->pwlen = 0;
175 ntlm_cred->no_cached_credentials = 0;
176
177 if(pAuthData != NULL)
178 {
179 int domain_len = 0, user_len = 0, password_len = 0;
180
181 if (auth_data->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI)
182 {
183 if (auth_data->DomainLength)
184 {
185 domain_len = MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->Domain,
186 auth_data->DomainLength, NULL, 0);
187 domain = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * domain_len);
188 if(!domain)
189 {
190 ret = SEC_E_INSUFFICIENT_MEMORY;
191 break;
192 }
193 MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->Domain, auth_data->DomainLength,
194 domain, domain_len);
195 }
196
197 if (auth_data->UserLength)
198 {
199 user_len = MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->User,
200 auth_data->UserLength, NULL, 0);
201 user = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * user_len);
202 if(!user)
203 {
204 ret = SEC_E_INSUFFICIENT_MEMORY;
205 break;
206 }
207 MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->User, auth_data->UserLength,
208 user, user_len);
209 }
210
211 if (auth_data->PasswordLength)
212 {
213 password_len = MultiByteToWideChar(CP_ACP, 0,(char *)auth_data->Password,
214 auth_data->PasswordLength, NULL, 0);
215 password = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * password_len);
216 if(!password)
217 {
218 ret = SEC_E_INSUFFICIENT_MEMORY;
219 break;
220 }
221 MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->Password, auth_data->PasswordLength,
222 password, password_len);
223 }
224 }
225 else
226 {
227 domain = auth_data->Domain;
228 domain_len = auth_data->DomainLength;
229
230 user = auth_data->User;
231 user_len = auth_data->UserLength;
232
233 password = auth_data->Password;
234 password_len = auth_data->PasswordLength;
235 }
236
237 TRACE("Username is %s\n", debugstr_wn(user, user_len));
238 TRACE("Domain name is %s\n", debugstr_wn(domain, domain_len));
239
240 ntlm_cred->username_arg = ntlm_GetUsernameArg(user, user_len);
241 ntlm_cred->domain_arg = ntlm_GetDomainArg(domain, domain_len);
242
243 if(password_len != 0)
244 {
245 ntlm_cred->pwlen = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, password,
246 password_len, NULL, 0, NULL, NULL);
247
248 ntlm_cred->password = HeapAlloc(GetProcessHeap(), 0,
249 ntlm_cred->pwlen);
250 if(!ntlm_cred->password)
251 {
252 ret = SEC_E_INSUFFICIENT_MEMORY;
253 break;
254 }
255
256 WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, password, password_len,
257 ntlm_cred->password, ntlm_cred->pwlen, NULL, NULL);
258 }
259 }
260
261 phCredential->dwUpper = fCredentialUse;
262 phCredential->dwLower = (ULONG_PTR)ntlm_cred;
263 TRACE("ACH phCredential->dwUpper: 0x%08lx, dwLower: 0x%08lx\n",
264 phCredential->dwUpper, phCredential->dwLower);
265 ret = SEC_E_OK;
266 break;
267 }
268 case SECPKG_CRED_BOTH:
269 FIXME("AcquireCredentialsHandle: SECPKG_CRED_BOTH stub\n");
270 ret = SEC_E_UNSUPPORTED_FUNCTION;
271 phCredential = NULL;
272 break;
273 default:
274 phCredential = NULL;
275 ret = SEC_E_UNKNOWN_CREDENTIALS;
276 }
277
278 if (auth_data && auth_data->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI)
279 {
280 HeapFree(GetProcessHeap(), 0, domain);
281 HeapFree(GetProcessHeap(), 0, user);
282 HeapFree(GetProcessHeap(), 0, password);
283 }
284 return ret;
285 }
286
287 /***********************************************************************
288 * AcquireCredentialsHandleA
289 */
ntlm_AcquireCredentialsHandleA(SEC_CHAR * pszPrincipal,SEC_CHAR * pszPackage,ULONG fCredentialUse,PLUID pLogonID,PVOID pAuthData,SEC_GET_KEY_FN pGetKeyFn,PVOID pGetKeyArgument,PCredHandle phCredential,PTimeStamp ptsExpiry)290 static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA(
291 SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse,
292 PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
293 PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
294 {
295 SECURITY_STATUS ret;
296 int user_sizeW, domain_sizeW, passwd_sizeW;
297
298 SEC_WCHAR *user = NULL, *domain = NULL, *passwd = NULL, *package = NULL;
299
300 PSEC_WINNT_AUTH_IDENTITY_W pAuthDataW = NULL;
301 PSEC_WINNT_AUTH_IDENTITY_A identity = NULL;
302
303 TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n",
304 debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse,
305 pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
306
307 if(pszPackage != NULL)
308 {
309 int package_sizeW = MultiByteToWideChar(CP_ACP, 0, pszPackage, -1,
310 NULL, 0);
311
312 package = HeapAlloc(GetProcessHeap(), 0, package_sizeW *
313 sizeof(SEC_WCHAR));
314 MultiByteToWideChar(CP_ACP, 0, pszPackage, -1, package, package_sizeW);
315 }
316
317
318 if(pAuthData != NULL)
319 {
320 identity = pAuthData;
321
322 if(identity->Flags == SEC_WINNT_AUTH_IDENTITY_ANSI)
323 {
324 pAuthDataW = HeapAlloc(GetProcessHeap(), 0,
325 sizeof(SEC_WINNT_AUTH_IDENTITY_W));
326
327 if(identity->UserLength != 0)
328 {
329 user_sizeW = MultiByteToWideChar(CP_ACP, 0,
330 (LPCSTR)identity->User, identity->UserLength, NULL, 0);
331 user = HeapAlloc(GetProcessHeap(), 0, user_sizeW *
332 sizeof(SEC_WCHAR));
333 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->User,
334 identity->UserLength, user, user_sizeW);
335 }
336 else
337 {
338 user_sizeW = 0;
339 }
340
341 if(identity->DomainLength != 0)
342 {
343 domain_sizeW = MultiByteToWideChar(CP_ACP, 0,
344 (LPCSTR)identity->Domain, identity->DomainLength, NULL, 0);
345 domain = HeapAlloc(GetProcessHeap(), 0, domain_sizeW
346 * sizeof(SEC_WCHAR));
347 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->Domain,
348 identity->DomainLength, domain, domain_sizeW);
349 }
350 else
351 {
352 domain_sizeW = 0;
353 }
354
355 if(identity->PasswordLength != 0)
356 {
357 passwd_sizeW = MultiByteToWideChar(CP_ACP, 0,
358 (LPCSTR)identity->Password, identity->PasswordLength,
359 NULL, 0);
360 passwd = HeapAlloc(GetProcessHeap(), 0, passwd_sizeW
361 * sizeof(SEC_WCHAR));
362 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->Password,
363 identity->PasswordLength, passwd, passwd_sizeW);
364 }
365 else
366 {
367 passwd_sizeW = 0;
368 }
369
370 pAuthDataW->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
371 pAuthDataW->User = user;
372 pAuthDataW->UserLength = user_sizeW;
373 pAuthDataW->Domain = domain;
374 pAuthDataW->DomainLength = domain_sizeW;
375 pAuthDataW->Password = passwd;
376 pAuthDataW->PasswordLength = passwd_sizeW;
377 }
378 else
379 {
380 pAuthDataW = (PSEC_WINNT_AUTH_IDENTITY_W)identity;
381 }
382 }
383
384 ret = ntlm_AcquireCredentialsHandleW(NULL, package, fCredentialUse,
385 pLogonID, pAuthDataW, pGetKeyFn, pGetKeyArgument, phCredential,
386 ptsExpiry);
387
388 HeapFree(GetProcessHeap(), 0, package);
389 HeapFree(GetProcessHeap(), 0, user);
390 HeapFree(GetProcessHeap(), 0, domain);
391 HeapFree(GetProcessHeap(), 0, passwd);
392 if(pAuthDataW != (PSEC_WINNT_AUTH_IDENTITY_W)identity)
393 HeapFree(GetProcessHeap(), 0, pAuthDataW);
394
395 return ret;
396 }
397
398 /*************************************************************************
399 * ntlm_GetTokenBufferIndex
400 * Calculates the index of the secbuffer with BufferType == SECBUFFER_TOKEN
401 * Returns index if found or -1 if not found.
402 */
ntlm_GetTokenBufferIndex(PSecBufferDesc pMessage)403 static int ntlm_GetTokenBufferIndex(PSecBufferDesc pMessage)
404 {
405 UINT i;
406
407 TRACE("%p\n", pMessage);
408
409 for( i = 0; i < pMessage->cBuffers; ++i )
410 {
411 if(pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN)
412 return i;
413 }
414
415 return -1;
416 }
417
418 /*************************************************************************
419 * ntlm_GetDataBufferIndex
420 * Calculates the index of the first secbuffer with BufferType == SECBUFFER_DATA
421 * Returns index if found or -1 if not found.
422 */
ntlm_GetDataBufferIndex(PSecBufferDesc pMessage)423 static int ntlm_GetDataBufferIndex(PSecBufferDesc pMessage)
424 {
425 UINT i;
426
427 TRACE("%p\n", pMessage);
428
429 for( i = 0; i < pMessage->cBuffers; ++i )
430 {
431 if(pMessage->pBuffers[i].BufferType == SECBUFFER_DATA)
432 return i;
433 }
434
435 return -1;
436 }
437
ntlm_GetCachedCredential(const SEC_WCHAR * pszTargetName,PCREDENTIALW * cred)438 static BOOL ntlm_GetCachedCredential(const SEC_WCHAR *pszTargetName, PCREDENTIALW *cred)
439 {
440 LPCWSTR p;
441 LPCWSTR pszHost;
442 LPWSTR pszHostOnly;
443 BOOL ret;
444
445 if (!pszTargetName)
446 return FALSE;
447
448 /* try to get the start of the hostname from service principal name (SPN) */
449 pszHost = strchrW(pszTargetName, '/');
450 if (pszHost)
451 {
452 /* skip slash character */
453 pszHost++;
454
455 /* find end of host by detecting start of instance port or start of referrer */
456 p = strchrW(pszHost, ':');
457 if (!p)
458 p = strchrW(pszHost, '/');
459 if (!p)
460 p = pszHost + strlenW(pszHost);
461 }
462 else /* otherwise not an SPN, just a host */
463 {
464 pszHost = pszTargetName;
465 p = pszHost + strlenW(pszHost);
466 }
467
468 pszHostOnly = HeapAlloc(GetProcessHeap(), 0, (p - pszHost + 1) * sizeof(WCHAR));
469 if (!pszHostOnly)
470 return FALSE;
471
472 memcpy(pszHostOnly, pszHost, (p - pszHost) * sizeof(WCHAR));
473 pszHostOnly[p - pszHost] = '\0';
474
475 ret = CredReadW(pszHostOnly, CRED_TYPE_DOMAIN_PASSWORD, 0, cred);
476
477 HeapFree(GetProcessHeap(), 0, pszHostOnly);
478 return ret;
479 }
480
481 /***********************************************************************
482 * InitializeSecurityContextW
483 */
ntlm_InitializeSecurityContextW(PCredHandle phCredential,PCtxtHandle phContext,SEC_WCHAR * pszTargetName,ULONG fContextReq,ULONG Reserved1,ULONG TargetDataRep,PSecBufferDesc pInput,ULONG Reserved2,PCtxtHandle phNewContext,PSecBufferDesc pOutput,ULONG * pfContextAttr,PTimeStamp ptsExpiry)484 SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
485 PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName,
486 ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
487 PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
488 PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
489 {
490 SECURITY_STATUS ret;
491 PNtlmCredentials ntlm_cred;
492 PNegoHelper helper = NULL;
493 ULONG ctxt_attr = 0;
494 char* buffer, *want_flags = NULL;
495 PBYTE bin;
496 int buffer_len, bin_len, max_len = NTLM_MAX_BUF;
497 int token_idx;
498 SEC_CHAR *username = NULL;
499 SEC_CHAR *domain = NULL;
500 SEC_CHAR *password = NULL;
501
502 TRACE("%p %p %s 0x%08x %d %d %p %d %p %p %p %p\n", phCredential, phContext,
503 debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
504 Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
505
506 /****************************************
507 * When communicating with the client, there can be the
508 * following reply packets:
509 * YR <base64 blob> should be sent to the server
510 * PW should be sent back to helper with
511 * base64 encoded password
512 * AF <base64 blob> client is done, blob should be
513 * sent to server with KK prefixed
514 * GF <string list> A string list of negotiated flags
515 * GK <base64 blob> base64 encoded session key
516 * BH <char reason> something broke
517 */
518 /* The squid cache size is 2010 chars, and that's what ntlm_auth uses */
519
520 if(TargetDataRep == SECURITY_NETWORK_DREP){
521 TRACE("Setting SECURITY_NETWORK_DREP\n");
522 }
523
524 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(char) * NTLM_MAX_BUF);
525 bin = HeapAlloc(GetProcessHeap(), 0, sizeof(BYTE) * NTLM_MAX_BUF);
526
527 if((phContext == NULL) && (pInput == NULL))
528 {
529 static char helper_protocol[] = "--helper-protocol=ntlmssp-client-1";
530 static CHAR credentials_argv[] = "--use-cached-creds";
531 SEC_CHAR *client_argv[5];
532 int pwlen = 0;
533
534 TRACE("First time in ISC()\n");
535
536 if(!phCredential)
537 {
538 ret = SEC_E_INVALID_HANDLE;
539 goto isc_end;
540 }
541
542 /* As the server side of sspi never calls this, make sure that
543 * the handler is a client handler.
544 */
545 ntlm_cred = (PNtlmCredentials)phCredential->dwLower;
546 if(ntlm_cred->mode != NTLM_CLIENT)
547 {
548 TRACE("Cred mode = %d\n", ntlm_cred->mode);
549 ret = SEC_E_INVALID_HANDLE;
550 goto isc_end;
551 }
552
553 client_argv[0] = ntlm_auth;
554 client_argv[1] = helper_protocol;
555 if (!ntlm_cred->username_arg && !ntlm_cred->domain_arg)
556 {
557 LPWKSTA_USER_INFO_1 ui = NULL;
558 NET_API_STATUS status;
559 PCREDENTIALW cred;
560
561 if (ntlm_GetCachedCredential(pszTargetName, &cred))
562 {
563 LPWSTR p;
564 p = strchrW(cred->UserName, '\\');
565 if (p)
566 {
567 domain = ntlm_GetDomainArg(cred->UserName, p - cred->UserName);
568 p++;
569 }
570 else
571 {
572 domain = ntlm_GetDomainArg(NULL, 0);
573 p = cred->UserName;
574 }
575
576 username = ntlm_GetUsernameArg(p, -1);
577
578 if(cred->CredentialBlobSize != 0)
579 {
580 pwlen = WideCharToMultiByte(CP_UNIXCP,
581 WC_NO_BEST_FIT_CHARS, (LPWSTR)cred->CredentialBlob,
582 cred->CredentialBlobSize / sizeof(WCHAR), NULL, 0,
583 NULL, NULL);
584
585 password = HeapAlloc(GetProcessHeap(), 0, pwlen);
586
587 WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
588 (LPWSTR)cred->CredentialBlob,
589 cred->CredentialBlobSize / sizeof(WCHAR),
590 password, pwlen, NULL, NULL);
591 }
592
593 CredFree(cred);
594
595 client_argv[2] = username;
596 client_argv[3] = domain;
597 client_argv[4] = NULL;
598 }
599 else
600 {
601 status = NetWkstaUserGetInfo(NULL, 1, (LPBYTE *)&ui);
602 if (status != NERR_Success || ui == NULL || ntlm_cred->no_cached_credentials)
603 {
604 ret = SEC_E_NO_CREDENTIALS;
605 goto isc_end;
606 }
607 username = ntlm_GetUsernameArg(ui->wkui1_username, -1);
608 NetApiBufferFree(ui);
609
610 TRACE("using cached credentials\n");
611
612 client_argv[2] = username;
613 client_argv[3] = credentials_argv;
614 client_argv[4] = NULL;
615 }
616 }
617 else
618 {
619 client_argv[2] = ntlm_cred->username_arg;
620 client_argv[3] = ntlm_cred->domain_arg;
621 client_argv[4] = NULL;
622 }
623
624 if((ret = fork_helper(&helper, ntlm_auth, client_argv)) != SEC_E_OK)
625 goto isc_end;
626
627 helper->mode = NTLM_CLIENT;
628 helper->session_key = HeapAlloc(GetProcessHeap(), 0, 16);
629 if (!helper->session_key)
630 {
631 cleanup_helper(helper);
632 ret = SEC_E_INSUFFICIENT_MEMORY;
633 goto isc_end;
634 }
635
636 /* Generate the dummy session key = MD4(MD4(password))*/
637 if(password || ntlm_cred->password)
638 {
639 SEC_WCHAR *unicode_password;
640 int passwd_lenW;
641
642 TRACE("Converting password to unicode.\n");
643 passwd_lenW = MultiByteToWideChar(CP_ACP, 0,
644 password ? password : ntlm_cred->password,
645 password ? pwlen : ntlm_cred->pwlen,
646 NULL, 0);
647 unicode_password = HeapAlloc(GetProcessHeap(), 0,
648 passwd_lenW * sizeof(SEC_WCHAR));
649 MultiByteToWideChar(CP_ACP, 0, password ? password : ntlm_cred->password,
650 password ? pwlen : ntlm_cred->pwlen, unicode_password, passwd_lenW);
651
652 SECUR32_CreateNTLM1SessionKey((PBYTE)unicode_password,
653 passwd_lenW * sizeof(SEC_WCHAR), helper->session_key);
654
655 HeapFree(GetProcessHeap(), 0, unicode_password);
656 }
657 else
658 memset(helper->session_key, 0, 16);
659
660 /* Allocate space for a maximal string of
661 * "SF NTLMSSP_FEATURE_SIGN NTLMSSP_FEATURE_SEAL
662 * NTLMSSP_FEATURE_SESSION_KEY"
663 */
664 want_flags = HeapAlloc(GetProcessHeap(), 0, 73);
665 if(want_flags == NULL)
666 {
667 cleanup_helper(helper);
668 ret = SEC_E_INSUFFICIENT_MEMORY;
669 goto isc_end;
670 }
671 lstrcpyA(want_flags, "SF");
672 if(fContextReq & ISC_REQ_CONFIDENTIALITY)
673 {
674 if(strstr(want_flags, "NTLMSSP_FEATURE_SEAL") == NULL)
675 lstrcatA(want_flags, " NTLMSSP_FEATURE_SEAL");
676 }
677 if(fContextReq & ISC_REQ_CONNECTION)
678 ctxt_attr |= ISC_RET_CONNECTION;
679 if(fContextReq & ISC_REQ_EXTENDED_ERROR)
680 ctxt_attr |= ISC_RET_EXTENDED_ERROR;
681 if(fContextReq & ISC_REQ_INTEGRITY)
682 {
683 if(strstr(want_flags, "NTLMSSP_FEATURE_SIGN") == NULL)
684 lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN");
685 }
686 if(fContextReq & ISC_REQ_MUTUAL_AUTH)
687 ctxt_attr |= ISC_RET_MUTUAL_AUTH;
688 if(fContextReq & ISC_REQ_REPLAY_DETECT)
689 {
690 if(strstr(want_flags, "NTLMSSP_FEATURE_SIGN") == NULL)
691 lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN");
692 }
693 if(fContextReq & ISC_REQ_SEQUENCE_DETECT)
694 {
695 if(strstr(want_flags, "NTLMSSP_FEATURE_SIGN") == NULL)
696 lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN");
697 }
698 if(fContextReq & ISC_REQ_STREAM)
699 FIXME("ISC_REQ_STREAM\n");
700 if(fContextReq & ISC_REQ_USE_DCE_STYLE)
701 ctxt_attr |= ISC_RET_USED_DCE_STYLE;
702 if(fContextReq & ISC_REQ_DELEGATE)
703 ctxt_attr |= ISC_RET_DELEGATE;
704
705 /* If no password is given, try to use cached credentials. Fall back to an empty
706 * password if this failed. */
707 if(!password && !ntlm_cred->password)
708 {
709 lstrcpynA(buffer, "OK", max_len-1);
710 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
711 {
712 cleanup_helper(helper);
713 goto isc_end;
714 }
715 /* If the helper replied with "PW", using cached credentials failed */
716 if(!strncmp(buffer, "PW", 2))
717 {
718 TRACE("Using cached credentials failed.\n");
719 lstrcpynA(buffer, "PW AA==", max_len-1);
720 }
721 else /* Just do a noop on the next run */
722 lstrcpynA(buffer, "OK", max_len-1);
723 }
724 else
725 {
726 lstrcpynA(buffer, "PW ", max_len-1);
727 if((ret = encodeBase64(password ? (unsigned char *)password : (unsigned char *)ntlm_cred->password,
728 password ? pwlen : ntlm_cred->pwlen, buffer+3,
729 max_len-3, &buffer_len)) != SEC_E_OK)
730 {
731 cleanup_helper(helper);
732 goto isc_end;
733 }
734
735 }
736
737 TRACE("Sending to helper: %s\n", debugstr_a(buffer));
738 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
739 {
740 cleanup_helper(helper);
741 goto isc_end;
742 }
743
744 TRACE("Helper returned %s\n", debugstr_a(buffer));
745
746 if(lstrlenA(want_flags) > 2)
747 {
748 TRACE("Want flags are %s\n", debugstr_a(want_flags));
749 lstrcpynA(buffer, want_flags, max_len-1);
750 if((ret = run_helper(helper, buffer, max_len, &buffer_len))
751 != SEC_E_OK)
752 {
753 cleanup_helper(helper);
754 goto isc_end;
755 }
756 if(!strncmp(buffer, "BH", 2))
757 ERR("Helper doesn't understand new command set. Expect more things to fail.\n");
758 }
759
760 lstrcpynA(buffer, "YR", max_len-1);
761
762 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
763 {
764 cleanup_helper(helper);
765 goto isc_end;
766 }
767
768 TRACE("%s\n", buffer);
769
770 if(strncmp(buffer, "YR ", 3) != 0)
771 {
772 /* Something borked */
773 TRACE("Helper returned %c%c\n", buffer[0], buffer[1]);
774 ret = SEC_E_INTERNAL_ERROR;
775 cleanup_helper(helper);
776 goto isc_end;
777 }
778 if((ret = decodeBase64(buffer+3, buffer_len-3, bin,
779 max_len-1, &bin_len)) != SEC_E_OK)
780 {
781 cleanup_helper(helper);
782 goto isc_end;
783 }
784
785 /* put the decoded client blob into the out buffer */
786
787 phNewContext->dwUpper = ctxt_attr;
788 phNewContext->dwLower = (ULONG_PTR)helper;
789
790 ret = SEC_I_CONTINUE_NEEDED;
791 }
792 else
793 {
794 int input_token_idx;
795
796 /* handle second call here */
797 /* encode server data to base64 */
798 if (!pInput || ((input_token_idx = ntlm_GetTokenBufferIndex(pInput)) == -1))
799 {
800 ret = SEC_E_INVALID_TOKEN;
801 goto isc_end;
802 }
803
804 if(!phContext)
805 {
806 ret = SEC_E_INVALID_HANDLE;
807 goto isc_end;
808 }
809
810 /* As the server side of sspi never calls this, make sure that
811 * the handler is a client handler.
812 */
813 helper = (PNegoHelper)phContext->dwLower;
814 if(helper->mode != NTLM_CLIENT)
815 {
816 TRACE("Helper mode = %d\n", helper->mode);
817 ret = SEC_E_INVALID_HANDLE;
818 goto isc_end;
819 }
820
821 if (!pInput->pBuffers[input_token_idx].pvBuffer)
822 {
823 ret = SEC_E_INTERNAL_ERROR;
824 goto isc_end;
825 }
826
827 if(pInput->pBuffers[input_token_idx].cbBuffer > max_len)
828 {
829 TRACE("pInput->pBuffers[%d].cbBuffer is: %d\n",
830 input_token_idx,
831 pInput->pBuffers[input_token_idx].cbBuffer);
832 ret = SEC_E_INVALID_TOKEN;
833 goto isc_end;
834 }
835 else
836 bin_len = pInput->pBuffers[input_token_idx].cbBuffer;
837
838 memcpy(bin, pInput->pBuffers[input_token_idx].pvBuffer, bin_len);
839
840 lstrcpynA(buffer, "TT ", max_len-1);
841
842 if((ret = encodeBase64(bin, bin_len, buffer+3,
843 max_len-3, &buffer_len)) != SEC_E_OK)
844 goto isc_end;
845
846 TRACE("Server sent: %s\n", debugstr_a(buffer));
847
848 /* send TT base64 blob to ntlm_auth */
849 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
850 goto isc_end;
851
852 TRACE("Helper replied: %s\n", debugstr_a(buffer));
853
854 if( (strncmp(buffer, "KK ", 3) != 0) &&
855 (strncmp(buffer, "AF ", 3) !=0))
856 {
857 TRACE("Helper returned %c%c\n", buffer[0], buffer[1]);
858 ret = SEC_E_INVALID_TOKEN;
859 goto isc_end;
860 }
861
862 /* decode the blob and send it to server */
863 if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len,
864 &bin_len)) != SEC_E_OK)
865 {
866 goto isc_end;
867 }
868
869 phNewContext->dwUpper = ctxt_attr;
870 phNewContext->dwLower = (ULONG_PTR)helper;
871
872 ret = SEC_E_OK;
873 }
874
875 /* put the decoded client blob into the out buffer */
876
877 if (!pOutput || ((token_idx = ntlm_GetTokenBufferIndex(pOutput)) == -1))
878 {
879 TRACE("no SECBUFFER_TOKEN buffer could be found\n");
880 ret = SEC_E_BUFFER_TOO_SMALL;
881 if ((phContext == NULL) && (pInput == NULL))
882 {
883 cleanup_helper(helper);
884 phNewContext->dwUpper = 0;
885 phNewContext->dwLower = 0;
886 }
887 goto isc_end;
888 }
889
890 if (fContextReq & ISC_REQ_ALLOCATE_MEMORY)
891 {
892 pOutput->pBuffers[token_idx].pvBuffer = HeapAlloc(GetProcessHeap(), 0, bin_len);
893 pOutput->pBuffers[token_idx].cbBuffer = bin_len;
894 }
895 else if (pOutput->pBuffers[token_idx].cbBuffer < bin_len)
896 {
897 TRACE("out buffer is NULL or has not enough space\n");
898 ret = SEC_E_BUFFER_TOO_SMALL;
899 if ((phContext == NULL) && (pInput == NULL))
900 {
901 cleanup_helper(helper);
902 phNewContext->dwUpper = 0;
903 phNewContext->dwLower = 0;
904 }
905 goto isc_end;
906 }
907
908 if (!pOutput->pBuffers[token_idx].pvBuffer)
909 {
910 TRACE("out buffer is NULL\n");
911 ret = SEC_E_INTERNAL_ERROR;
912 if ((phContext == NULL) && (pInput == NULL))
913 {
914 cleanup_helper(helper);
915 phNewContext->dwUpper = 0;
916 phNewContext->dwLower = 0;
917 }
918 goto isc_end;
919 }
920
921 pOutput->pBuffers[token_idx].cbBuffer = bin_len;
922 memcpy(pOutput->pBuffers[token_idx].pvBuffer, bin, bin_len);
923
924 if(ret == SEC_E_OK)
925 {
926 TRACE("Getting negotiated flags\n");
927 lstrcpynA(buffer, "GF", max_len - 1);
928 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
929 goto isc_end;
930
931 if(buffer_len < 3)
932 {
933 TRACE("No flags negotiated.\n");
934 helper->neg_flags = 0l;
935 }
936 else
937 {
938 TRACE("Negotiated %s\n", debugstr_a(buffer));
939 sscanf(buffer + 3, "%lx", &(helper->neg_flags));
940 TRACE("Stored 0x%08x as flags\n", helper->neg_flags);
941 }
942
943 TRACE("Getting session key\n");
944 lstrcpynA(buffer, "GK", max_len - 1);
945 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
946 goto isc_end;
947
948 if(strncmp(buffer, "BH", 2) == 0)
949 TRACE("No key negotiated.\n");
950 else if(strncmp(buffer, "GK ", 3) == 0)
951 {
952 if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len,
953 &bin_len)) != SEC_E_OK)
954 {
955 TRACE("Failed to decode session key\n");
956 }
957 TRACE("Session key is %s\n", debugstr_a(buffer+3));
958 HeapFree(GetProcessHeap(), 0, helper->session_key);
959 helper->session_key = HeapAlloc(GetProcessHeap(), 0, bin_len);
960 if(!helper->session_key)
961 {
962 ret = SEC_E_INSUFFICIENT_MEMORY;
963 goto isc_end;
964 }
965 memcpy(helper->session_key, bin, bin_len);
966 }
967
968 helper->crypt.ntlm.a4i = SECUR32_arc4Alloc();
969 SECUR32_arc4Init(helper->crypt.ntlm.a4i, helper->session_key, 16);
970 helper->crypt.ntlm.seq_num = 0l;
971 SECUR32_CreateNTLM2SubKeys(helper);
972 helper->crypt.ntlm2.send_a4i = SECUR32_arc4Alloc();
973 helper->crypt.ntlm2.recv_a4i = SECUR32_arc4Alloc();
974 SECUR32_arc4Init(helper->crypt.ntlm2.send_a4i,
975 helper->crypt.ntlm2.send_seal_key, 16);
976 SECUR32_arc4Init(helper->crypt.ntlm2.recv_a4i,
977 helper->crypt.ntlm2.recv_seal_key, 16);
978 helper->crypt.ntlm2.send_seq_no = 0l;
979 helper->crypt.ntlm2.recv_seq_no = 0l;
980 }
981
982 isc_end:
983 HeapFree(GetProcessHeap(), 0, username);
984 HeapFree(GetProcessHeap(), 0, domain);
985 HeapFree(GetProcessHeap(), 0, password);
986 HeapFree(GetProcessHeap(), 0, want_flags);
987 HeapFree(GetProcessHeap(), 0, buffer);
988 HeapFree(GetProcessHeap(), 0, bin);
989 return ret;
990 }
991
992 /***********************************************************************
993 * InitializeSecurityContextA
994 */
ntlm_InitializeSecurityContextA(PCredHandle phCredential,PCtxtHandle phContext,SEC_CHAR * pszTargetName,ULONG fContextReq,ULONG Reserved1,ULONG TargetDataRep,PSecBufferDesc pInput,ULONG Reserved2,PCtxtHandle phNewContext,PSecBufferDesc pOutput,ULONG * pfContextAttr,PTimeStamp ptsExpiry)995 static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA(
996 PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName,
997 ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
998 PSecBufferDesc pInput,ULONG Reserved2, PCtxtHandle phNewContext,
999 PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
1000 {
1001 SECURITY_STATUS ret;
1002 SEC_WCHAR *target = NULL;
1003
1004 TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential, phContext,
1005 debugstr_a(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
1006 Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
1007
1008 if(pszTargetName != NULL)
1009 {
1010 int target_size = MultiByteToWideChar(CP_ACP, 0, pszTargetName,
1011 strlen(pszTargetName)+1, NULL, 0);
1012 target = HeapAlloc(GetProcessHeap(), 0, target_size *
1013 sizeof(SEC_WCHAR));
1014 MultiByteToWideChar(CP_ACP, 0, pszTargetName, strlen(pszTargetName)+1,
1015 target, target_size);
1016 }
1017
1018 ret = ntlm_InitializeSecurityContextW(phCredential, phContext, target,
1019 fContextReq, Reserved1, TargetDataRep, pInput, Reserved2,
1020 phNewContext, pOutput, pfContextAttr, ptsExpiry);
1021
1022 HeapFree(GetProcessHeap(), 0, target);
1023 return ret;
1024 }
1025
1026 /***********************************************************************
1027 * AcceptSecurityContext
1028 */
ntlm_AcceptSecurityContext(PCredHandle phCredential,PCtxtHandle phContext,PSecBufferDesc pInput,ULONG fContextReq,ULONG TargetDataRep,PCtxtHandle phNewContext,PSecBufferDesc pOutput,ULONG * pfContextAttr,PTimeStamp ptsExpiry)1029 SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(
1030 PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput,
1031 ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext,
1032 PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
1033 {
1034 SECURITY_STATUS ret;
1035 char *buffer, *want_flags = NULL;
1036 PBYTE bin;
1037 int buffer_len, bin_len, max_len = NTLM_MAX_BUF;
1038 ULONG ctxt_attr = 0;
1039 PNegoHelper helper;
1040 PNtlmCredentials ntlm_cred;
1041
1042 TRACE("%p %p %p %d %d %p %p %p %p\n", phCredential, phContext, pInput,
1043 fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr,
1044 ptsExpiry);
1045
1046 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(char) * NTLM_MAX_BUF);
1047 bin = HeapAlloc(GetProcessHeap(),0, sizeof(BYTE) * NTLM_MAX_BUF);
1048
1049 if(TargetDataRep == SECURITY_NETWORK_DREP){
1050 TRACE("Using SECURITY_NETWORK_DREP\n");
1051 }
1052
1053 if(phContext == NULL)
1054 {
1055 static CHAR server_helper_protocol[] = "--helper-protocol=squid-2.5-ntlmssp";
1056 SEC_CHAR *server_argv[] = { ntlm_auth,
1057 server_helper_protocol,
1058 NULL };
1059
1060 if (!phCredential)
1061 {
1062 ret = SEC_E_INVALID_HANDLE;
1063 goto asc_end;
1064 }
1065
1066 ntlm_cred = (PNtlmCredentials)phCredential->dwLower;
1067
1068 if(ntlm_cred->mode != NTLM_SERVER)
1069 {
1070 ret = SEC_E_INVALID_HANDLE;
1071 goto asc_end;
1072 }
1073
1074 /* This is the first call to AcceptSecurityHandle */
1075 if(pInput == NULL)
1076 {
1077 ret = SEC_E_INCOMPLETE_MESSAGE;
1078 goto asc_end;
1079 }
1080
1081 if(pInput->cBuffers < 1)
1082 {
1083 ret = SEC_E_INCOMPLETE_MESSAGE;
1084 goto asc_end;
1085 }
1086
1087 if(pInput->pBuffers[0].cbBuffer > max_len)
1088 {
1089 ret = SEC_E_INVALID_TOKEN;
1090 goto asc_end;
1091 }
1092 else
1093 bin_len = pInput->pBuffers[0].cbBuffer;
1094
1095 if( (ret = fork_helper(&helper, ntlm_auth, server_argv)) !=
1096 SEC_E_OK)
1097 {
1098 ret = SEC_E_INTERNAL_ERROR;
1099 goto asc_end;
1100 }
1101 helper->mode = NTLM_SERVER;
1102
1103 /* Handle all the flags */
1104 want_flags = HeapAlloc(GetProcessHeap(), 0, 73);
1105 if(want_flags == NULL)
1106 {
1107 TRACE("Failed to allocate memory for the want_flags!\n");
1108 ret = SEC_E_INSUFFICIENT_MEMORY;
1109 cleanup_helper(helper);
1110 goto asc_end;
1111 }
1112 lstrcpyA(want_flags, "SF");
1113 if(fContextReq & ASC_REQ_ALLOCATE_MEMORY)
1114 {
1115 FIXME("ASC_REQ_ALLOCATE_MEMORY stub\n");
1116 }
1117 if(fContextReq & ASC_REQ_CONFIDENTIALITY)
1118 {
1119 lstrcatA(want_flags, " NTLMSSP_FEATURE_SEAL");
1120 }
1121 if(fContextReq & ASC_REQ_CONNECTION)
1122 {
1123 /* This is default, so we'll enable it */
1124 lstrcatA(want_flags, " NTLMSSP_FEATURE_SESSION_KEY");
1125 ctxt_attr |= ASC_RET_CONNECTION;
1126 }
1127 if(fContextReq & ASC_REQ_EXTENDED_ERROR)
1128 {
1129 FIXME("ASC_REQ_EXTENDED_ERROR stub\n");
1130 }
1131 if(fContextReq & ASC_REQ_INTEGRITY)
1132 {
1133 lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN");
1134 }
1135 if(fContextReq & ASC_REQ_MUTUAL_AUTH)
1136 {
1137 FIXME("ASC_REQ_MUTUAL_AUTH stub\n");
1138 }
1139 if(fContextReq & ASC_REQ_REPLAY_DETECT)
1140 {
1141 FIXME("ASC_REQ_REPLAY_DETECT stub\n");
1142 }
1143 if(fContextReq & ISC_REQ_SEQUENCE_DETECT)
1144 {
1145 FIXME("ASC_REQ_SEQUENCE_DETECT stub\n");
1146 }
1147 if(fContextReq & ISC_REQ_STREAM)
1148 {
1149 FIXME("ASC_REQ_STREAM stub\n");
1150 }
1151 /* Done with the flags */
1152
1153 if(lstrlenA(want_flags) > 3)
1154 {
1155 TRACE("Server set want_flags: %s\n", debugstr_a(want_flags));
1156 lstrcpynA(buffer, want_flags, max_len - 1);
1157 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) !=
1158 SEC_E_OK)
1159 {
1160 cleanup_helper(helper);
1161 goto asc_end;
1162 }
1163 if(!strncmp(buffer, "BH", 2))
1164 TRACE("Helper doesn't understand new command set\n");
1165 }
1166
1167 /* This is the YR request from the client, encode to base64 */
1168
1169 memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len);
1170
1171 lstrcpynA(buffer, "YR ", max_len-1);
1172
1173 if((ret = encodeBase64(bin, bin_len, buffer+3, max_len-3,
1174 &buffer_len)) != SEC_E_OK)
1175 {
1176 cleanup_helper(helper);
1177 goto asc_end;
1178 }
1179
1180 TRACE("Client sent: %s\n", debugstr_a(buffer));
1181
1182 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) !=
1183 SEC_E_OK)
1184 {
1185 cleanup_helper(helper);
1186 goto asc_end;
1187 }
1188
1189 TRACE("Reply from ntlm_auth: %s\n", debugstr_a(buffer));
1190 /* The expected answer is TT <base64 blob> */
1191
1192 if(strncmp(buffer, "TT ", 3) != 0)
1193 {
1194 ret = SEC_E_INTERNAL_ERROR;
1195 cleanup_helper(helper);
1196 goto asc_end;
1197 }
1198
1199 if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len,
1200 &bin_len)) != SEC_E_OK)
1201 {
1202 cleanup_helper(helper);
1203 goto asc_end;
1204 }
1205
1206 /* send this to the client */
1207 if(pOutput == NULL)
1208 {
1209 ret = SEC_E_INSUFFICIENT_MEMORY;
1210 cleanup_helper(helper);
1211 goto asc_end;
1212 }
1213
1214 if(pOutput->cBuffers < 1)
1215 {
1216 ret = SEC_E_INSUFFICIENT_MEMORY;
1217 cleanup_helper(helper);
1218 goto asc_end;
1219 }
1220
1221 pOutput->pBuffers[0].cbBuffer = bin_len;
1222 pOutput->pBuffers[0].BufferType = SECBUFFER_DATA;
1223 memcpy(pOutput->pBuffers[0].pvBuffer, bin, bin_len);
1224 ret = SEC_I_CONTINUE_NEEDED;
1225
1226 }
1227 else
1228 {
1229 /* we expect a KK request from client */
1230 if(pInput == NULL)
1231 {
1232 ret = SEC_E_INCOMPLETE_MESSAGE;
1233 goto asc_end;
1234 }
1235
1236 if(pInput->cBuffers < 1)
1237 {
1238 ret = SEC_E_INCOMPLETE_MESSAGE;
1239 goto asc_end;
1240 }
1241
1242 helper = (PNegoHelper)phContext->dwLower;
1243
1244 if(helper->mode != NTLM_SERVER)
1245 {
1246 ret = SEC_E_INVALID_HANDLE;
1247 goto asc_end;
1248 }
1249
1250 if(pInput->pBuffers[0].cbBuffer > max_len)
1251 {
1252 ret = SEC_E_INVALID_TOKEN;
1253 goto asc_end;
1254 }
1255 else
1256 bin_len = pInput->pBuffers[0].cbBuffer;
1257
1258 memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len);
1259
1260 lstrcpynA(buffer, "KK ", max_len-1);
1261
1262 if((ret = encodeBase64(bin, bin_len, buffer+3, max_len-3,
1263 &buffer_len)) != SEC_E_OK)
1264 {
1265 goto asc_end;
1266 }
1267
1268 TRACE("Client sent: %s\n", debugstr_a(buffer));
1269
1270 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) !=
1271 SEC_E_OK)
1272 {
1273 goto asc_end;
1274 }
1275
1276 TRACE("Reply from ntlm_auth: %s\n", debugstr_a(buffer));
1277
1278 /* At this point, we get a NA if the user didn't authenticate, but a BH
1279 * if ntlm_auth could not connect to winbindd. Apart from running Wine
1280 * as root, there is no way to fix this for now, so just handle this as
1281 * a failed login. */
1282 if(strncmp(buffer, "AF ", 3) != 0)
1283 {
1284 if(strncmp(buffer, "NA ", 3) == 0)
1285 {
1286 ret = SEC_E_LOGON_DENIED;
1287 goto asc_end;
1288 }
1289 else
1290 {
1291 size_t ntlm_pipe_err_v3_len = strlen("BH NT_STATUS_ACCESS_DENIED");
1292 size_t ntlm_pipe_err_v4_len = strlen("BH NT_STATUS_UNSUCCESSFUL");
1293
1294 if( (buffer_len >= ntlm_pipe_err_v3_len &&
1295 strncmp(buffer, "BH NT_STATUS_ACCESS_DENIED", ntlm_pipe_err_v3_len) == 0) ||
1296 (buffer_len >= ntlm_pipe_err_v4_len &&
1297 strncmp(buffer, "BH NT_STATUS_UNSUCCESSFUL", ntlm_pipe_err_v4_len) == 0) )
1298 {
1299 TRACE("Connection to winbindd failed\n");
1300 ret = SEC_E_LOGON_DENIED;
1301 }
1302 else
1303 ret = SEC_E_INTERNAL_ERROR;
1304
1305 goto asc_end;
1306 }
1307 }
1308 pOutput->pBuffers[0].cbBuffer = 0;
1309
1310 TRACE("Getting negotiated flags\n");
1311 lstrcpynA(buffer, "GF", max_len - 1);
1312 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
1313 goto asc_end;
1314
1315 if(buffer_len < 3)
1316 {
1317 TRACE("No flags negotiated, or helper does not support GF command\n");
1318 }
1319 else
1320 {
1321 TRACE("Negotiated %s\n", debugstr_a(buffer));
1322 sscanf(buffer + 3, "%lx", &(helper->neg_flags));
1323 TRACE("Stored 0x%08x as flags\n", helper->neg_flags);
1324 }
1325
1326 TRACE("Getting session key\n");
1327 lstrcpynA(buffer, "GK", max_len - 1);
1328 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
1329 goto asc_end;
1330
1331 if(buffer_len < 3)
1332 TRACE("Helper does not support GK command\n");
1333 else
1334 {
1335 if(strncmp(buffer, "BH ", 3) == 0)
1336 {
1337 TRACE("Helper sent %s\n", debugstr_a(buffer+3));
1338 HeapFree(GetProcessHeap(), 0, helper->session_key);
1339 helper->session_key = HeapAlloc(GetProcessHeap(), 0, 16);
1340 if (!helper->session_key)
1341 {
1342 ret = SEC_E_INSUFFICIENT_MEMORY;
1343 goto asc_end;
1344 }
1345 /*FIXME: Generate the dummy session key = MD4(MD4(password))*/
1346 memset(helper->session_key, 0 , 16);
1347 }
1348 else if(strncmp(buffer, "GK ", 3) == 0)
1349 {
1350 if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len,
1351 &bin_len)) != SEC_E_OK)
1352 {
1353 TRACE("Failed to decode session key\n");
1354 }
1355 TRACE("Session key is %s\n", debugstr_a(buffer+3));
1356 HeapFree(GetProcessHeap(), 0, helper->session_key);
1357 helper->session_key = HeapAlloc(GetProcessHeap(), 0, 16);
1358 if(!helper->session_key)
1359 {
1360 ret = SEC_E_INSUFFICIENT_MEMORY;
1361 goto asc_end;
1362 }
1363 memcpy(helper->session_key, bin, 16);
1364 }
1365 }
1366 helper->crypt.ntlm.a4i = SECUR32_arc4Alloc();
1367 SECUR32_arc4Init(helper->crypt.ntlm.a4i, helper->session_key, 16);
1368 helper->crypt.ntlm.seq_num = 0l;
1369 }
1370
1371 phNewContext->dwUpper = ctxt_attr;
1372 phNewContext->dwLower = (ULONG_PTR)helper;
1373
1374 asc_end:
1375 HeapFree(GetProcessHeap(), 0, want_flags);
1376 HeapFree(GetProcessHeap(), 0, buffer);
1377 HeapFree(GetProcessHeap(), 0, bin);
1378 return ret;
1379 }
1380
1381 /***********************************************************************
1382 * CompleteAuthToken
1383 */
ntlm_CompleteAuthToken(PCtxtHandle phContext,PSecBufferDesc pToken)1384 static SECURITY_STATUS SEC_ENTRY ntlm_CompleteAuthToken(PCtxtHandle phContext,
1385 PSecBufferDesc pToken)
1386 {
1387 /* We never need to call CompleteAuthToken anyway */
1388 TRACE("%p %p\n", phContext, pToken);
1389 if (!phContext)
1390 return SEC_E_INVALID_HANDLE;
1391
1392 return SEC_E_OK;
1393 }
1394
1395 /***********************************************************************
1396 * DeleteSecurityContext
1397 */
ntlm_DeleteSecurityContext(PCtxtHandle phContext)1398 SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext)
1399 {
1400 PNegoHelper helper;
1401
1402 TRACE("%p\n", phContext);
1403 if (!phContext)
1404 return SEC_E_INVALID_HANDLE;
1405
1406 helper = (PNegoHelper)phContext->dwLower;
1407
1408 phContext->dwUpper = 0;
1409 phContext->dwLower = 0;
1410
1411 SECUR32_arc4Cleanup(helper->crypt.ntlm.a4i);
1412 SECUR32_arc4Cleanup(helper->crypt.ntlm2.send_a4i);
1413 SECUR32_arc4Cleanup(helper->crypt.ntlm2.recv_a4i);
1414 HeapFree(GetProcessHeap(), 0, helper->crypt.ntlm2.send_sign_key);
1415 HeapFree(GetProcessHeap(), 0, helper->crypt.ntlm2.send_seal_key);
1416 HeapFree(GetProcessHeap(), 0, helper->crypt.ntlm2.recv_sign_key);
1417 HeapFree(GetProcessHeap(), 0, helper->crypt.ntlm2.recv_seal_key);
1418
1419 cleanup_helper(helper);
1420
1421 return SEC_E_OK;
1422 }
1423
1424 /***********************************************************************
1425 * QueryContextAttributesW
1426 */
ntlm_QueryContextAttributesW(PCtxtHandle phContext,ULONG ulAttribute,void * pBuffer)1427 SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext,
1428 ULONG ulAttribute, void *pBuffer)
1429 {
1430 TRACE("%p %d %p\n", phContext, ulAttribute, pBuffer);
1431 if (!phContext)
1432 return SEC_E_INVALID_HANDLE;
1433
1434 switch(ulAttribute)
1435 {
1436 #define _x(x) case (x) : FIXME(#x" stub\n"); break
1437 _x(SECPKG_ATTR_ACCESS_TOKEN);
1438 _x(SECPKG_ATTR_AUTHORITY);
1439 _x(SECPKG_ATTR_DCE_INFO);
1440 case SECPKG_ATTR_FLAGS:
1441 {
1442 PSecPkgContext_Flags spcf = (PSecPkgContext_Flags)pBuffer;
1443 PNegoHelper helper = (PNegoHelper)phContext->dwLower;
1444
1445 spcf->Flags = 0;
1446 if(helper->neg_flags & NTLMSSP_NEGOTIATE_SIGN)
1447 spcf->Flags |= ISC_RET_INTEGRITY;
1448 if(helper->neg_flags & NTLMSSP_NEGOTIATE_SEAL)
1449 spcf->Flags |= ISC_RET_CONFIDENTIALITY;
1450 return SEC_E_OK;
1451 }
1452 _x(SECPKG_ATTR_KEY_INFO);
1453 _x(SECPKG_ATTR_LIFESPAN);
1454 _x(SECPKG_ATTR_NAMES);
1455 _x(SECPKG_ATTR_NATIVE_NAMES);
1456 _x(SECPKG_ATTR_NEGOTIATION_INFO);
1457 _x(SECPKG_ATTR_PACKAGE_INFO);
1458 _x(SECPKG_ATTR_PASSWORD_EXPIRY);
1459 _x(SECPKG_ATTR_SESSION_KEY);
1460 case SECPKG_ATTR_SIZES:
1461 {
1462 PSecPkgContext_Sizes spcs = (PSecPkgContext_Sizes)pBuffer;
1463 spcs->cbMaxToken = NTLM_MAX_BUF;
1464 spcs->cbMaxSignature = 16;
1465 spcs->cbBlockSize = 0;
1466 spcs->cbSecurityTrailer = 16;
1467 return SEC_E_OK;
1468 }
1469 _x(SECPKG_ATTR_STREAM_SIZES);
1470 _x(SECPKG_ATTR_TARGET_INFORMATION);
1471 #undef _x
1472 default:
1473 TRACE("Unknown value %d passed for ulAttribute\n", ulAttribute);
1474 }
1475
1476 return SEC_E_UNSUPPORTED_FUNCTION;
1477 }
1478
1479 /***********************************************************************
1480 * QueryContextAttributesA
1481 */
ntlm_QueryContextAttributesA(PCtxtHandle phContext,ULONG ulAttribute,void * pBuffer)1482 SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(PCtxtHandle phContext,
1483 ULONG ulAttribute, void *pBuffer)
1484 {
1485 return ntlm_QueryContextAttributesW(phContext, ulAttribute, pBuffer);
1486 }
1487
1488 /***********************************************************************
1489 * ImpersonateSecurityContext
1490 */
ntlm_ImpersonateSecurityContext(PCtxtHandle phContext)1491 static SECURITY_STATUS SEC_ENTRY ntlm_ImpersonateSecurityContext(PCtxtHandle phContext)
1492 {
1493 SECURITY_STATUS ret;
1494
1495 TRACE("%p\n", phContext);
1496 if (phContext)
1497 {
1498 ret = SEC_E_UNSUPPORTED_FUNCTION;
1499 }
1500 else
1501 {
1502 ret = SEC_E_INVALID_HANDLE;
1503 }
1504 return ret;
1505 }
1506
1507 /***********************************************************************
1508 * RevertSecurityContext
1509 */
ntlm_RevertSecurityContext(PCtxtHandle phContext)1510 static SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(PCtxtHandle phContext)
1511 {
1512 SECURITY_STATUS ret;
1513
1514 TRACE("%p\n", phContext);
1515 if (phContext)
1516 {
1517 ret = SEC_E_UNSUPPORTED_FUNCTION;
1518 }
1519 else
1520 {
1521 ret = SEC_E_INVALID_HANDLE;
1522 }
1523 return ret;
1524 }
1525
1526 /***********************************************************************
1527 * ntlm_CreateSignature
1528 * As both MakeSignature and VerifySignature need this, but different keys
1529 * are needed for NTLM2, the logic goes into a helper function.
1530 * To ensure maximal reusability, we can specify the direction as NTLM_SEND for
1531 * signing/encrypting and NTLM_RECV for verifying/decrypting. When encrypting,
1532 * the signature is encrypted after the message was encrypted, so
1533 * CreateSignature shouldn't do it. In this case, encrypt_sig can be set to
1534 * false.
1535 */
ntlm_CreateSignature(PNegoHelper helper,PSecBufferDesc pMessage,int token_idx,SignDirection direction,BOOL encrypt_sig)1536 static SECURITY_STATUS ntlm_CreateSignature(PNegoHelper helper, PSecBufferDesc pMessage,
1537 int token_idx, SignDirection direction, BOOL encrypt_sig)
1538 {
1539 ULONG sign_version = 1;
1540 UINT i;
1541 PBYTE sig;
1542 TRACE("%p, %p, %d, %d, %d\n", helper, pMessage, token_idx, direction,
1543 encrypt_sig);
1544
1545 sig = pMessage->pBuffers[token_idx].pvBuffer;
1546
1547 if(helper->neg_flags & NTLMSSP_NEGOTIATE_NTLM2 &&
1548 helper->neg_flags & NTLMSSP_NEGOTIATE_SIGN)
1549 {
1550 BYTE digest[16];
1551 BYTE seq_no[4];
1552 HMAC_MD5_CTX hmac_md5_ctx;
1553
1554 TRACE("Signing NTLM2 style\n");
1555
1556 if(direction == NTLM_SEND)
1557 {
1558 seq_no[0] = (helper->crypt.ntlm2.send_seq_no >> 0) & 0xff;
1559 seq_no[1] = (helper->crypt.ntlm2.send_seq_no >> 8) & 0xff;
1560 seq_no[2] = (helper->crypt.ntlm2.send_seq_no >> 16) & 0xff;
1561 seq_no[3] = (helper->crypt.ntlm2.send_seq_no >> 24) & 0xff;
1562
1563 ++(helper->crypt.ntlm2.send_seq_no);
1564
1565 HMACMD5Init(&hmac_md5_ctx, helper->crypt.ntlm2.send_sign_key, 16);
1566 }
1567 else
1568 {
1569 seq_no[0] = (helper->crypt.ntlm2.recv_seq_no >> 0) & 0xff;
1570 seq_no[1] = (helper->crypt.ntlm2.recv_seq_no >> 8) & 0xff;
1571 seq_no[2] = (helper->crypt.ntlm2.recv_seq_no >> 16) & 0xff;
1572 seq_no[3] = (helper->crypt.ntlm2.recv_seq_no >> 24) & 0xff;
1573
1574 ++(helper->crypt.ntlm2.recv_seq_no);
1575
1576 HMACMD5Init(&hmac_md5_ctx, helper->crypt.ntlm2.recv_sign_key, 16);
1577 }
1578
1579 HMACMD5Update(&hmac_md5_ctx, seq_no, 4);
1580 for( i = 0; i < pMessage->cBuffers; ++i )
1581 {
1582 if(pMessage->pBuffers[i].BufferType & SECBUFFER_DATA)
1583 HMACMD5Update(&hmac_md5_ctx, pMessage->pBuffers[i].pvBuffer,
1584 pMessage->pBuffers[i].cbBuffer);
1585 }
1586
1587 HMACMD5Final(&hmac_md5_ctx, digest);
1588
1589 if(encrypt_sig && helper->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCHANGE)
1590 {
1591 if(direction == NTLM_SEND)
1592 SECUR32_arc4Process(helper->crypt.ntlm2.send_a4i, digest, 8);
1593 else
1594 SECUR32_arc4Process(helper->crypt.ntlm2.recv_a4i, digest, 8);
1595 }
1596
1597 /* The NTLM2 signature is the sign version */
1598 sig[ 0] = (sign_version >> 0) & 0xff;
1599 sig[ 1] = (sign_version >> 8) & 0xff;
1600 sig[ 2] = (sign_version >> 16) & 0xff;
1601 sig[ 3] = (sign_version >> 24) & 0xff;
1602 /* The first 8 bytes of the digest */
1603 memcpy(sig+4, digest, 8);
1604 /* And the sequence number */
1605 memcpy(sig+12, seq_no, 4);
1606
1607 pMessage->pBuffers[token_idx].cbBuffer = 16;
1608
1609 return SEC_E_OK;
1610 }
1611 if(helper->neg_flags & NTLMSSP_NEGOTIATE_SIGN)
1612 {
1613 ULONG crc = 0U;
1614 TRACE("Signing NTLM1 style\n");
1615
1616 for(i=0; i < pMessage->cBuffers; ++i)
1617 {
1618 if(pMessage->pBuffers[i].BufferType & SECBUFFER_DATA)
1619 {
1620 crc = ComputeCrc32(pMessage->pBuffers[i].pvBuffer,
1621 pMessage->pBuffers[i].cbBuffer, crc);
1622 }
1623 }
1624
1625 sig[ 0] = (sign_version >> 0) & 0xff;
1626 sig[ 1] = (sign_version >> 8) & 0xff;
1627 sig[ 2] = (sign_version >> 16) & 0xff;
1628 sig[ 3] = (sign_version >> 24) & 0xff;
1629 memset(sig+4, 0, 4);
1630 sig[ 8] = (crc >> 0) & 0xff;
1631 sig[ 9] = (crc >> 8) & 0xff;
1632 sig[10] = (crc >> 16) & 0xff;
1633 sig[11] = (crc >> 24) & 0xff;
1634 sig[12] = (helper->crypt.ntlm.seq_num >> 0) & 0xff;
1635 sig[13] = (helper->crypt.ntlm.seq_num >> 8) & 0xff;
1636 sig[14] = (helper->crypt.ntlm.seq_num >> 16) & 0xff;
1637 sig[15] = (helper->crypt.ntlm.seq_num >> 24) & 0xff;
1638
1639 ++(helper->crypt.ntlm.seq_num);
1640
1641 if(encrypt_sig)
1642 SECUR32_arc4Process(helper->crypt.ntlm.a4i, sig+4, 12);
1643 return SEC_E_OK;
1644 }
1645
1646 if(helper->neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN || helper->neg_flags == 0)
1647 {
1648 TRACE("Creating a dummy signature.\n");
1649 /* A dummy signature is 0x01 followed by 15 bytes of 0x00 */
1650 memset(pMessage->pBuffers[token_idx].pvBuffer, 0, 16);
1651 memset(pMessage->pBuffers[token_idx].pvBuffer, 0x01, 1);
1652 pMessage->pBuffers[token_idx].cbBuffer = 16;
1653 return SEC_E_OK;
1654 }
1655
1656 return SEC_E_UNSUPPORTED_FUNCTION;
1657 }
1658
1659 /***********************************************************************
1660 * MakeSignature
1661 */
ntlm_MakeSignature(PCtxtHandle phContext,ULONG fQOP,PSecBufferDesc pMessage,ULONG MessageSeqNo)1662 SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext,
1663 ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
1664 {
1665 PNegoHelper helper;
1666 int token_idx;
1667
1668 TRACE("%p %d %p %d\n", phContext, fQOP, pMessage, MessageSeqNo);
1669 if (!phContext)
1670 return SEC_E_INVALID_HANDLE;
1671
1672 if(fQOP)
1673 FIXME("Ignoring fQOP 0x%08x\n", fQOP);
1674
1675 if(MessageSeqNo)
1676 FIXME("Ignoring MessageSeqNo\n");
1677
1678 if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2)
1679 return SEC_E_INVALID_TOKEN;
1680
1681 /* If we didn't find a SECBUFFER_TOKEN type buffer */
1682 if((token_idx = ntlm_GetTokenBufferIndex(pMessage)) == -1)
1683 return SEC_E_INVALID_TOKEN;
1684
1685 if(pMessage->pBuffers[token_idx].cbBuffer < 16)
1686 return SEC_E_BUFFER_TOO_SMALL;
1687
1688 helper = (PNegoHelper)phContext->dwLower;
1689 TRACE("Negotiated flags are: 0x%08x\n", helper->neg_flags);
1690
1691 return ntlm_CreateSignature(helper, pMessage, token_idx, NTLM_SEND, TRUE);
1692 }
1693
1694 /***********************************************************************
1695 * VerifySignature
1696 */
ntlm_VerifySignature(PCtxtHandle phContext,PSecBufferDesc pMessage,ULONG MessageSeqNo,PULONG pfQOP)1697 SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle phContext,
1698 PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
1699 {
1700 PNegoHelper helper;
1701 UINT i;
1702 int token_idx;
1703 SECURITY_STATUS ret;
1704 SecBufferDesc local_desc;
1705 PSecBuffer local_buff;
1706 BYTE local_sig[16];
1707
1708 TRACE("%p %p %d %p\n", phContext, pMessage, MessageSeqNo, pfQOP);
1709 if(!phContext)
1710 return SEC_E_INVALID_HANDLE;
1711
1712 if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2)
1713 return SEC_E_INVALID_TOKEN;
1714
1715 if((token_idx = ntlm_GetTokenBufferIndex(pMessage)) == -1)
1716 return SEC_E_INVALID_TOKEN;
1717
1718 if(pMessage->pBuffers[token_idx].cbBuffer < 16)
1719 return SEC_E_BUFFER_TOO_SMALL;
1720
1721 if(MessageSeqNo)
1722 FIXME("Ignoring MessageSeqNo\n");
1723
1724 helper = (PNegoHelper)phContext->dwLower;
1725 TRACE("Negotiated flags: 0x%08x\n", helper->neg_flags);
1726
1727 local_buff = HeapAlloc(GetProcessHeap(), 0, pMessage->cBuffers * sizeof(SecBuffer));
1728
1729 local_desc.ulVersion = SECBUFFER_VERSION;
1730 local_desc.cBuffers = pMessage->cBuffers;
1731 local_desc.pBuffers = local_buff;
1732
1733 for(i=0; i < pMessage->cBuffers; ++i)
1734 {
1735 if(pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN)
1736 {
1737 local_buff[i].BufferType = SECBUFFER_TOKEN;
1738 local_buff[i].cbBuffer = 16;
1739 local_buff[i].pvBuffer = local_sig;
1740 }
1741 else
1742 {
1743 local_buff[i].BufferType = pMessage->pBuffers[i].BufferType;
1744 local_buff[i].cbBuffer = pMessage->pBuffers[i].cbBuffer;
1745 local_buff[i].pvBuffer = pMessage->pBuffers[i].pvBuffer;
1746 }
1747 }
1748
1749 if((ret = ntlm_CreateSignature(helper, &local_desc, token_idx, NTLM_RECV, TRUE)) != SEC_E_OK)
1750 return ret;
1751
1752 if(memcmp(((PBYTE)local_buff[token_idx].pvBuffer) + 8,
1753 ((PBYTE)pMessage->pBuffers[token_idx].pvBuffer) + 8, 8))
1754 ret = SEC_E_MESSAGE_ALTERED;
1755 else
1756 ret = SEC_E_OK;
1757
1758 HeapFree(GetProcessHeap(), 0, local_buff);
1759
1760 return ret;
1761
1762 }
1763
1764 /***********************************************************************
1765 * FreeCredentialsHandle
1766 */
ntlm_FreeCredentialsHandle(PCredHandle phCredential)1767 SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(PCredHandle phCredential)
1768 {
1769 SECURITY_STATUS ret;
1770
1771 if(phCredential){
1772 PNtlmCredentials ntlm_cred = (PNtlmCredentials) phCredential->dwLower;
1773 phCredential->dwUpper = 0;
1774 phCredential->dwLower = 0;
1775 if (ntlm_cred->password)
1776 memset(ntlm_cred->password, 0, ntlm_cred->pwlen);
1777 HeapFree(GetProcessHeap(), 0, ntlm_cred->password);
1778 HeapFree(GetProcessHeap(), 0, ntlm_cred->username_arg);
1779 HeapFree(GetProcessHeap(), 0, ntlm_cred->domain_arg);
1780 HeapFree(GetProcessHeap(), 0, ntlm_cred);
1781 ret = SEC_E_OK;
1782 }
1783 else
1784 ret = SEC_E_OK;
1785
1786 return ret;
1787 }
1788
1789 /***********************************************************************
1790 * EncryptMessage
1791 */
ntlm_EncryptMessage(PCtxtHandle phContext,ULONG fQOP,PSecBufferDesc pMessage,ULONG MessageSeqNo)1792 SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext,
1793 ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
1794 {
1795 PNegoHelper helper;
1796 int token_idx, data_idx;
1797
1798 TRACE("(%p %d %p %d)\n", phContext, fQOP, pMessage, MessageSeqNo);
1799
1800 if(!phContext)
1801 return SEC_E_INVALID_HANDLE;
1802
1803 if(fQOP)
1804 FIXME("Ignoring fQOP\n");
1805
1806 if(MessageSeqNo)
1807 FIXME("Ignoring MessageSeqNo\n");
1808
1809 if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2)
1810 return SEC_E_INVALID_TOKEN;
1811
1812 if((token_idx = ntlm_GetTokenBufferIndex(pMessage)) == -1)
1813 return SEC_E_INVALID_TOKEN;
1814
1815 if((data_idx = ntlm_GetDataBufferIndex(pMessage)) ==-1 )
1816 return SEC_E_INVALID_TOKEN;
1817
1818 if(pMessage->pBuffers[token_idx].cbBuffer < 16)
1819 return SEC_E_BUFFER_TOO_SMALL;
1820
1821 helper = (PNegoHelper) phContext->dwLower;
1822
1823 if(helper->neg_flags & NTLMSSP_NEGOTIATE_NTLM2 &&
1824 helper->neg_flags & NTLMSSP_NEGOTIATE_SEAL)
1825 {
1826 ntlm_CreateSignature(helper, pMessage, token_idx, NTLM_SEND, FALSE);
1827 SECUR32_arc4Process(helper->crypt.ntlm2.send_a4i,
1828 pMessage->pBuffers[data_idx].pvBuffer,
1829 pMessage->pBuffers[data_idx].cbBuffer);
1830
1831 if(helper->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCHANGE)
1832 SECUR32_arc4Process(helper->crypt.ntlm2.send_a4i,
1833 ((BYTE *)pMessage->pBuffers[token_idx].pvBuffer)+4, 8);
1834 }
1835 else
1836 {
1837 PBYTE sig;
1838 ULONG save_flags;
1839
1840 /* EncryptMessage always produces real signatures, so make sure
1841 * NTLMSSP_NEGOTIATE_SIGN is set*/
1842 save_flags = helper->neg_flags;
1843 helper->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
1844 ntlm_CreateSignature(helper, pMessage, token_idx, NTLM_SEND, FALSE);
1845 helper->neg_flags = save_flags;
1846
1847 sig = pMessage->pBuffers[token_idx].pvBuffer;
1848
1849 SECUR32_arc4Process(helper->crypt.ntlm.a4i,
1850 pMessage->pBuffers[data_idx].pvBuffer,
1851 pMessage->pBuffers[data_idx].cbBuffer);
1852 SECUR32_arc4Process(helper->crypt.ntlm.a4i, sig+4, 12);
1853
1854 if(helper->neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN || helper->neg_flags == 0)
1855 memset(sig+4, 0, 4);
1856 }
1857 return SEC_E_OK;
1858 }
1859
1860 /***********************************************************************
1861 * DecryptMessage
1862 */
ntlm_DecryptMessage(PCtxtHandle phContext,PSecBufferDesc pMessage,ULONG MessageSeqNo,PULONG pfQOP)1863 SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext,
1864 PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
1865 {
1866 SECURITY_STATUS ret;
1867 ULONG ntlmssp_flags_save;
1868 PNegoHelper helper;
1869 int token_idx, data_idx;
1870 TRACE("(%p %p %d %p)\n", phContext, pMessage, MessageSeqNo, pfQOP);
1871
1872 if(!phContext)
1873 return SEC_E_INVALID_HANDLE;
1874
1875 if(MessageSeqNo)
1876 FIXME("Ignoring MessageSeqNo\n");
1877
1878 if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2)
1879 return SEC_E_INVALID_TOKEN;
1880
1881 if((token_idx = ntlm_GetTokenBufferIndex(pMessage)) == -1)
1882 return SEC_E_INVALID_TOKEN;
1883
1884 if((data_idx = ntlm_GetDataBufferIndex(pMessage)) ==-1)
1885 return SEC_E_INVALID_TOKEN;
1886
1887 if(pMessage->pBuffers[token_idx].cbBuffer < 16)
1888 return SEC_E_BUFFER_TOO_SMALL;
1889
1890 helper = (PNegoHelper) phContext->dwLower;
1891
1892 if(helper->neg_flags & NTLMSSP_NEGOTIATE_NTLM2 && helper->neg_flags & NTLMSSP_NEGOTIATE_SEAL)
1893 {
1894 SECUR32_arc4Process(helper->crypt.ntlm2.recv_a4i,
1895 pMessage->pBuffers[data_idx].pvBuffer,
1896 pMessage->pBuffers[data_idx].cbBuffer);
1897 }
1898 else
1899 {
1900 SECUR32_arc4Process(helper->crypt.ntlm.a4i,
1901 pMessage->pBuffers[data_idx].pvBuffer,
1902 pMessage->pBuffers[data_idx].cbBuffer);
1903 }
1904
1905 /* Make sure we use a session key for the signature check, EncryptMessage
1906 * always does that, even in the dummy case */
1907 ntlmssp_flags_save = helper->neg_flags;
1908
1909 helper->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
1910 ret = ntlm_VerifySignature(phContext, pMessage, MessageSeqNo, pfQOP);
1911
1912 helper->neg_flags = ntlmssp_flags_save;
1913
1914 return ret;
1915 }
1916
1917 static const SecurityFunctionTableA ntlmTableA = {
1918 1,
1919 NULL, /* EnumerateSecurityPackagesA */
1920 ntlm_QueryCredentialsAttributesA, /* QueryCredentialsAttributesA */
1921 ntlm_AcquireCredentialsHandleA, /* AcquireCredentialsHandleA */
1922 ntlm_FreeCredentialsHandle, /* FreeCredentialsHandle */
1923 NULL, /* Reserved2 */
1924 ntlm_InitializeSecurityContextA, /* InitializeSecurityContextA */
1925 ntlm_AcceptSecurityContext, /* AcceptSecurityContext */
1926 ntlm_CompleteAuthToken, /* CompleteAuthToken */
1927 ntlm_DeleteSecurityContext, /* DeleteSecurityContext */
1928 NULL, /* ApplyControlToken */
1929 ntlm_QueryContextAttributesA, /* QueryContextAttributesA */
1930 ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
1931 ntlm_RevertSecurityContext, /* RevertSecurityContext */
1932 ntlm_MakeSignature, /* MakeSignature */
1933 ntlm_VerifySignature, /* VerifySignature */
1934 FreeContextBuffer, /* FreeContextBuffer */
1935 NULL, /* QuerySecurityPackageInfoA */
1936 NULL, /* Reserved3 */
1937 NULL, /* Reserved4 */
1938 NULL, /* ExportSecurityContext */
1939 NULL, /* ImportSecurityContextA */
1940 NULL, /* AddCredentialsA */
1941 NULL, /* Reserved8 */
1942 NULL, /* QuerySecurityContextToken */
1943 ntlm_EncryptMessage, /* EncryptMessage */
1944 ntlm_DecryptMessage, /* DecryptMessage */
1945 NULL, /* SetContextAttributesA */
1946 };
1947
1948 static const SecurityFunctionTableW ntlmTableW = {
1949 1,
1950 NULL, /* EnumerateSecurityPackagesW */
1951 ntlm_QueryCredentialsAttributesW, /* QueryCredentialsAttributesW */
1952 ntlm_AcquireCredentialsHandleW, /* AcquireCredentialsHandleW */
1953 ntlm_FreeCredentialsHandle, /* FreeCredentialsHandle */
1954 NULL, /* Reserved2 */
1955 ntlm_InitializeSecurityContextW, /* InitializeSecurityContextW */
1956 ntlm_AcceptSecurityContext, /* AcceptSecurityContext */
1957 ntlm_CompleteAuthToken, /* CompleteAuthToken */
1958 ntlm_DeleteSecurityContext, /* DeleteSecurityContext */
1959 NULL, /* ApplyControlToken */
1960 ntlm_QueryContextAttributesW, /* QueryContextAttributesW */
1961 ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
1962 ntlm_RevertSecurityContext, /* RevertSecurityContext */
1963 ntlm_MakeSignature, /* MakeSignature */
1964 ntlm_VerifySignature, /* VerifySignature */
1965 FreeContextBuffer, /* FreeContextBuffer */
1966 NULL, /* QuerySecurityPackageInfoW */
1967 NULL, /* Reserved3 */
1968 NULL, /* Reserved4 */
1969 NULL, /* ExportSecurityContext */
1970 NULL, /* ImportSecurityContextW */
1971 NULL, /* AddCredentialsW */
1972 NULL, /* Reserved8 */
1973 NULL, /* QuerySecurityContextToken */
1974 ntlm_EncryptMessage, /* EncryptMessage */
1975 ntlm_DecryptMessage, /* DecryptMessage */
1976 NULL, /* SetContextAttributesW */
1977 };
1978
1979 #define NTLM_COMMENT \
1980 { 'N', 'T', 'L', 'M', ' ', \
1981 'S', 'e', 'c', 'u', 'r', 'i', 't', 'y', ' ', \
1982 'P', 'a', 'c', 'k', 'a', 'g', 'e', 0}
1983
1984 static CHAR ntlm_comment_A[] = NTLM_COMMENT;
1985 static WCHAR ntlm_comment_W[] = NTLM_COMMENT;
1986
1987 #define NTLM_NAME {'N', 'T', 'L', 'M', 0}
1988
1989 static char ntlm_name_A[] = NTLM_NAME;
1990 static WCHAR ntlm_name_W[] = NTLM_NAME;
1991
1992 /* According to Windows, NTLM has the following capabilities. */
1993 #define CAPS ( \
1994 SECPKG_FLAG_INTEGRITY | \
1995 SECPKG_FLAG_PRIVACY | \
1996 SECPKG_FLAG_TOKEN_ONLY | \
1997 SECPKG_FLAG_CONNECTION | \
1998 SECPKG_FLAG_MULTI_REQUIRED | \
1999 SECPKG_FLAG_IMPERSONATION | \
2000 SECPKG_FLAG_ACCEPT_WIN32_NAME | \
2001 SECPKG_FLAG_NEGOTIABLE | \
2002 SECPKG_FLAG_LOGON | \
2003 SECPKG_FLAG_RESTRICTED_TOKENS )
2004
2005 static const SecPkgInfoW infoW = {
2006 CAPS,
2007 1,
2008 RPC_C_AUTHN_WINNT,
2009 NTLM_MAX_BUF,
2010 ntlm_name_W,
2011 ntlm_comment_W
2012 };
2013
2014 static const SecPkgInfoA infoA = {
2015 CAPS,
2016 1,
2017 RPC_C_AUTHN_WINNT,
2018 NTLM_MAX_BUF,
2019 ntlm_name_A,
2020 ntlm_comment_A
2021 };
2022
2023 SecPkgInfoA *ntlm_package_infoA = (SecPkgInfoA *)&infoA;
2024 SecPkgInfoW *ntlm_package_infoW = (SecPkgInfoW *)&infoW;
2025
SECUR32_initNTLMSP(void)2026 void SECUR32_initNTLMSP(void)
2027 {
2028 PNegoHelper helper;
2029 static CHAR version[] = "--version";
2030
2031 SEC_CHAR *args[] = {
2032 ntlm_auth,
2033 version,
2034 NULL };
2035
2036 if(fork_helper(&helper, ntlm_auth, args) != SEC_E_OK)
2037 helper = NULL;
2038 else
2039 check_version(helper);
2040
2041 if( helper &&
2042 ((helper->major > MIN_NTLM_AUTH_MAJOR_VERSION) ||
2043 (helper->major == MIN_NTLM_AUTH_MAJOR_VERSION &&
2044 helper->minor > MIN_NTLM_AUTH_MINOR_VERSION) ||
2045 (helper->major == MIN_NTLM_AUTH_MAJOR_VERSION &&
2046 helper->minor == MIN_NTLM_AUTH_MINOR_VERSION &&
2047 helper->micro >= MIN_NTLM_AUTH_MICRO_VERSION)) )
2048 {
2049 SecureProvider *provider = SECUR32_addProvider(&ntlmTableA, &ntlmTableW, NULL);
2050 SECUR32_addPackages(provider, 1L, ntlm_package_infoA, ntlm_package_infoW);
2051 }
2052 else
2053 {
2054 ERR_(winediag)("%s was not found or is outdated. "
2055 "Make sure that ntlm_auth >= %d.%d.%d is in your path. "
2056 "Usually, you can find it in the winbind package of your distribution.\n",
2057 ntlm_auth,
2058 MIN_NTLM_AUTH_MAJOR_VERSION,
2059 MIN_NTLM_AUTH_MINOR_VERSION,
2060 MIN_NTLM_AUTH_MICRO_VERSION);
2061
2062 }
2063 cleanup_helper(helper);
2064 }
2065