reg/tests: Test import with non-standard registry file headers.
[wine.git] / dlls / secur32 / ntlm.c
blob94b94f48cee8abb566768768c0d374fbde86830c
1 /*
2 * Copyright 2005, 2006 Kai Blin
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.
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.
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
18 * This file implements the NTLM security provider.
21 #include <assert.h>
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winnls.h"
27 #include "wincred.h"
28 #include "rpc.h"
29 #include "sspi.h"
30 #include "lm.h"
31 #include "secur32_priv.h"
32 #include "hmac_md5.h"
33 #include "wine/unicode.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(ntlm);
37 WINE_DECLARE_DEBUG_CHANNEL(winediag);
39 #define NTLM_MAX_BUF 1904
40 #define MIN_NTLM_AUTH_MAJOR_VERSION 3
41 #define MIN_NTLM_AUTH_MINOR_VERSION 0
42 #define MIN_NTLM_AUTH_MICRO_VERSION 25
44 static CHAR ntlm_auth[] = "ntlm_auth";
46 /***********************************************************************
47 * QueryCredentialsAttributesA
49 static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesA(
50 PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
52 SECURITY_STATUS ret;
54 TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer);
56 if(ulAttribute == SECPKG_ATTR_NAMES)
58 FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
59 ret = SEC_E_UNSUPPORTED_FUNCTION;
61 else
62 ret = SEC_E_UNSUPPORTED_FUNCTION;
64 return ret;
67 /***********************************************************************
68 * QueryCredentialsAttributesW
70 static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesW(
71 PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
73 SECURITY_STATUS ret;
75 TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer);
77 if(ulAttribute == SECPKG_ATTR_NAMES)
79 FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
80 ret = SEC_E_UNSUPPORTED_FUNCTION;
82 else
83 ret = SEC_E_UNSUPPORTED_FUNCTION;
85 return ret;
88 static char *ntlm_GetUsernameArg(LPCWSTR userW, INT userW_length)
90 static const char username_arg[] = "--username=";
91 char *user;
92 int unixcp_size;
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;
106 static char *ntlm_GetDomainArg(LPCWSTR domainW, INT domainW_length)
108 static const char domain_arg[] = "--domain=";
109 char *domain;
110 int unixcp_size;
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;
124 /***********************************************************************
125 * AcquireCredentialsHandleW
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)
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;
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);
141 switch(fCredentialUse)
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
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;
156 phCredential->dwUpper = fCredentialUse;
157 phCredential->dwLower = (ULONG_PTR)ntlm_cred;
158 ret = SEC_E_OK;
160 break;
161 case SECPKG_CRED_OUTBOUND:
163 auth_data = pAuthData;
164 ntlm_cred = HeapAlloc(GetProcessHeap(), 0, sizeof(*ntlm_cred));
165 if (!ntlm_cred)
167 ret = SEC_E_INSUFFICIENT_MEMORY;
168 break;
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;
177 if(pAuthData != NULL)
179 int domain_len = 0, user_len = 0, password_len = 0;
181 if (auth_data->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI)
183 if (auth_data->DomainLength)
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)
190 ret = SEC_E_INSUFFICIENT_MEMORY;
191 break;
193 MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->Domain, auth_data->DomainLength,
194 domain, domain_len);
197 if (auth_data->UserLength)
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)
204 ret = SEC_E_INSUFFICIENT_MEMORY;
205 break;
207 MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->User, auth_data->UserLength,
208 user, user_len);
211 if (auth_data->PasswordLength)
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)
218 ret = SEC_E_INSUFFICIENT_MEMORY;
219 break;
221 MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->Password, auth_data->PasswordLength,
222 password, password_len);
225 else
227 domain = auth_data->Domain;
228 domain_len = auth_data->DomainLength;
230 user = auth_data->User;
231 user_len = auth_data->UserLength;
233 password = auth_data->Password;
234 password_len = auth_data->PasswordLength;
237 TRACE("Username is %s\n", debugstr_wn(user, user_len));
238 TRACE("Domain name is %s\n", debugstr_wn(domain, domain_len));
240 ntlm_cred->username_arg = ntlm_GetUsernameArg(user, user_len);
241 ntlm_cred->domain_arg = ntlm_GetDomainArg(domain, domain_len);
243 if(password_len != 0)
245 ntlm_cred->pwlen = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, password,
246 password_len, NULL, 0, NULL, NULL);
248 ntlm_cred->password = HeapAlloc(GetProcessHeap(), 0,
249 ntlm_cred->pwlen);
250 if(!ntlm_cred->password)
252 ret = SEC_E_INSUFFICIENT_MEMORY;
253 break;
256 WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, password, password_len,
257 ntlm_cred->password, ntlm_cred->pwlen, NULL, NULL);
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;
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;
278 if (auth_data && auth_data->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI)
280 HeapFree(GetProcessHeap(), 0, domain);
281 HeapFree(GetProcessHeap(), 0, user);
282 HeapFree(GetProcessHeap(), 0, password);
284 return ret;
287 /***********************************************************************
288 * AcquireCredentialsHandleA
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)
295 SECURITY_STATUS ret;
296 int user_sizeW, domain_sizeW, passwd_sizeW;
298 SEC_WCHAR *user = NULL, *domain = NULL, *passwd = NULL, *package = NULL;
300 PSEC_WINNT_AUTH_IDENTITY_W pAuthDataW = NULL;
301 PSEC_WINNT_AUTH_IDENTITY_A identity = NULL;
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);
307 if(pszPackage != NULL)
309 int package_sizeW = MultiByteToWideChar(CP_ACP, 0, pszPackage, -1,
310 NULL, 0);
312 package = HeapAlloc(GetProcessHeap(), 0, package_sizeW *
313 sizeof(SEC_WCHAR));
314 MultiByteToWideChar(CP_ACP, 0, pszPackage, -1, package, package_sizeW);
318 if(pAuthData != NULL)
320 identity = pAuthData;
322 if(identity->Flags == SEC_WINNT_AUTH_IDENTITY_ANSI)
324 pAuthDataW = HeapAlloc(GetProcessHeap(), 0,
325 sizeof(SEC_WINNT_AUTH_IDENTITY_W));
327 if(identity->UserLength != 0)
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);
336 else
338 user_sizeW = 0;
341 if(identity->DomainLength != 0)
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);
350 else
352 domain_sizeW = 0;
355 if(identity->PasswordLength != 0)
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);
365 else
367 passwd_sizeW = 0;
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;
378 else
380 pAuthDataW = (PSEC_WINNT_AUTH_IDENTITY_W)identity;
384 ret = ntlm_AcquireCredentialsHandleW(NULL, package, fCredentialUse,
385 pLogonID, pAuthDataW, pGetKeyFn, pGetKeyArgument, phCredential,
386 ptsExpiry);
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);
395 return ret;
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.
403 static int ntlm_GetTokenBufferIndex(PSecBufferDesc pMessage)
405 UINT i;
407 TRACE("%p\n", pMessage);
409 for( i = 0; i < pMessage->cBuffers; ++i )
411 if(pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN)
412 return i;
415 return -1;
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.
423 static int ntlm_GetDataBufferIndex(PSecBufferDesc pMessage)
425 UINT i;
427 TRACE("%p\n", pMessage);
429 for( i = 0; i < pMessage->cBuffers; ++i )
431 if(pMessage->pBuffers[i].BufferType == SECBUFFER_DATA)
432 return i;
435 return -1;
438 static BOOL ntlm_GetCachedCredential(const SEC_WCHAR *pszTargetName, PCREDENTIALW *cred)
440 LPCWSTR p;
441 LPCWSTR pszHost;
442 LPWSTR pszHostOnly;
443 BOOL ret;
445 if (!pszTargetName)
446 return FALSE;
448 /* try to get the start of the hostname from service principal name (SPN) */
449 pszHost = strchrW(pszTargetName, '/');
450 if (pszHost)
452 /* skip slash character */
453 pszHost++;
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);
462 else /* otherwise not an SPN, just a host */
464 pszHost = pszTargetName;
465 p = pszHost + strlenW(pszHost);
468 pszHostOnly = HeapAlloc(GetProcessHeap(), 0, (p - pszHost + 1) * sizeof(WCHAR));
469 if (!pszHostOnly)
470 return FALSE;
472 memcpy(pszHostOnly, pszHost, (p - pszHost) * sizeof(WCHAR));
473 pszHostOnly[p - pszHost] = '\0';
475 ret = CredReadW(pszHostOnly, CRED_TYPE_DOMAIN_PASSWORD, 0, cred);
477 HeapFree(GetProcessHeap(), 0, pszHostOnly);
478 return ret;
481 /***********************************************************************
482 * InitializeSecurityContextW
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)
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;
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);
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
518 /* The squid cache size is 2010 chars, and that's what ntlm_auth uses */
520 if(TargetDataRep == SECURITY_NETWORK_DREP){
521 TRACE("Setting SECURITY_NETWORK_DREP\n");
524 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(char) * NTLM_MAX_BUF);
525 bin = HeapAlloc(GetProcessHeap(), 0, sizeof(BYTE) * NTLM_MAX_BUF);
527 if((phContext == NULL) && (pInput == NULL))
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;
534 TRACE("First time in ISC()\n");
536 if(!phCredential)
538 ret = SEC_E_INVALID_HANDLE;
539 goto isc_end;
542 /* As the server side of sspi never calls this, make sure that
543 * the handler is a client handler.
545 ntlm_cred = (PNtlmCredentials)phCredential->dwLower;
546 if(ntlm_cred->mode != NTLM_CLIENT)
548 TRACE("Cred mode = %d\n", ntlm_cred->mode);
549 ret = SEC_E_INVALID_HANDLE;
550 goto isc_end;
553 client_argv[0] = ntlm_auth;
554 client_argv[1] = helper_protocol;
555 if (!ntlm_cred->username_arg && !ntlm_cred->domain_arg)
557 LPWKSTA_USER_INFO_1 ui = NULL;
558 NET_API_STATUS status;
559 PCREDENTIALW cred;
561 if (ntlm_GetCachedCredential(pszTargetName, &cred))
563 LPWSTR p;
564 p = strchrW(cred->UserName, '\\');
565 if (p)
567 domain = ntlm_GetDomainArg(cred->UserName, p - cred->UserName);
568 p++;
570 else
572 domain = ntlm_GetDomainArg(NULL, 0);
573 p = cred->UserName;
576 username = ntlm_GetUsernameArg(p, -1);
578 if(cred->CredentialBlobSize != 0)
580 pwlen = WideCharToMultiByte(CP_UNIXCP,
581 WC_NO_BEST_FIT_CHARS, (LPWSTR)cred->CredentialBlob,
582 cred->CredentialBlobSize / sizeof(WCHAR), NULL, 0,
583 NULL, NULL);
585 password = HeapAlloc(GetProcessHeap(), 0, pwlen);
587 WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
588 (LPWSTR)cred->CredentialBlob,
589 cred->CredentialBlobSize / sizeof(WCHAR),
590 password, pwlen, NULL, NULL);
593 CredFree(cred);
595 client_argv[2] = username;
596 client_argv[3] = domain;
597 client_argv[4] = NULL;
599 else
601 status = NetWkstaUserGetInfo(NULL, 1, (LPBYTE *)&ui);
602 if (status != NERR_Success || ui == NULL || ntlm_cred->no_cached_credentials)
604 ret = SEC_E_NO_CREDENTIALS;
605 goto isc_end;
607 username = ntlm_GetUsernameArg(ui->wkui1_username, -1);
608 NetApiBufferFree(ui);
610 TRACE("using cached credentials\n");
612 client_argv[2] = username;
613 client_argv[3] = credentials_argv;
614 client_argv[4] = NULL;
617 else
619 client_argv[2] = ntlm_cred->username_arg;
620 client_argv[3] = ntlm_cred->domain_arg;
621 client_argv[4] = NULL;
624 if((ret = fork_helper(&helper, ntlm_auth, client_argv)) != SEC_E_OK)
625 goto isc_end;
627 helper->mode = NTLM_CLIENT;
628 helper->session_key = HeapAlloc(GetProcessHeap(), 0, 16);
629 if (!helper->session_key)
631 cleanup_helper(helper);
632 ret = SEC_E_INSUFFICIENT_MEMORY;
633 goto isc_end;
636 /* Generate the dummy session key = MD4(MD4(password))*/
637 if(password || ntlm_cred->password)
639 SEC_WCHAR *unicode_password;
640 int passwd_lenW;
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);
652 SECUR32_CreateNTLM1SessionKey((PBYTE)unicode_password,
653 passwd_lenW * sizeof(SEC_WCHAR), helper->session_key);
655 HeapFree(GetProcessHeap(), 0, unicode_password);
657 else
658 memset(helper->session_key, 0, 16);
660 /* Allocate space for a maximal string of
661 * "SF NTLMSSP_FEATURE_SIGN NTLMSSP_FEATURE_SEAL
662 * NTLMSSP_FEATURE_SESSION_KEY"
664 want_flags = HeapAlloc(GetProcessHeap(), 0, 73);
665 if(want_flags == NULL)
667 cleanup_helper(helper);
668 ret = SEC_E_INSUFFICIENT_MEMORY;
669 goto isc_end;
671 lstrcpyA(want_flags, "SF");
672 if(fContextReq & ISC_REQ_CONFIDENTIALITY)
674 if(strstr(want_flags, "NTLMSSP_FEATURE_SEAL") == NULL)
675 lstrcatA(want_flags, " NTLMSSP_FEATURE_SEAL");
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)
683 if(strstr(want_flags, "NTLMSSP_FEATURE_SIGN") == NULL)
684 lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN");
686 if(fContextReq & ISC_REQ_MUTUAL_AUTH)
687 ctxt_attr |= ISC_RET_MUTUAL_AUTH;
688 if(fContextReq & ISC_REQ_REPLAY_DETECT)
690 if(strstr(want_flags, "NTLMSSP_FEATURE_SIGN") == NULL)
691 lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN");
693 if(fContextReq & ISC_REQ_SEQUENCE_DETECT)
695 if(strstr(want_flags, "NTLMSSP_FEATURE_SIGN") == NULL)
696 lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN");
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;
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)
709 lstrcpynA(buffer, "OK", max_len-1);
710 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
712 cleanup_helper(helper);
713 goto isc_end;
715 /* If the helper replied with "PW", using cached credentials failed */
716 if(!strncmp(buffer, "PW", 2))
718 TRACE("Using cached credentials failed.\n");
719 lstrcpynA(buffer, "PW AA==", max_len-1);
721 else /* Just do a noop on the next run */
722 lstrcpynA(buffer, "OK", max_len-1);
724 else
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)
731 cleanup_helper(helper);
732 goto isc_end;
737 TRACE("Sending to helper: %s\n", debugstr_a(buffer));
738 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
740 cleanup_helper(helper);
741 goto isc_end;
744 TRACE("Helper returned %s\n", debugstr_a(buffer));
746 if(lstrlenA(want_flags) > 2)
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)
753 cleanup_helper(helper);
754 goto isc_end;
756 if(!strncmp(buffer, "BH", 2))
757 ERR("Helper doesn't understand new command set. Expect more things to fail.\n");
760 lstrcpynA(buffer, "YR", max_len-1);
762 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
764 cleanup_helper(helper);
765 goto isc_end;
768 TRACE("%s\n", buffer);
770 if(strncmp(buffer, "YR ", 3) != 0)
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;
778 if((ret = decodeBase64(buffer+3, buffer_len-3, bin,
779 max_len-1, &bin_len)) != SEC_E_OK)
781 cleanup_helper(helper);
782 goto isc_end;
785 /* put the decoded client blob into the out buffer */
787 phNewContext->dwUpper = ctxt_attr;
788 phNewContext->dwLower = (ULONG_PTR)helper;
790 ret = SEC_I_CONTINUE_NEEDED;
792 else
794 int input_token_idx;
796 /* handle second call here */
797 /* encode server data to base64 */
798 if (!pInput || ((input_token_idx = ntlm_GetTokenBufferIndex(pInput)) == -1))
800 ret = SEC_E_INVALID_TOKEN;
801 goto isc_end;
804 if(!phContext)
806 ret = SEC_E_INVALID_HANDLE;
807 goto isc_end;
810 /* As the server side of sspi never calls this, make sure that
811 * the handler is a client handler.
813 helper = (PNegoHelper)phContext->dwLower;
814 if(helper->mode != NTLM_CLIENT)
816 TRACE("Helper mode = %d\n", helper->mode);
817 ret = SEC_E_INVALID_HANDLE;
818 goto isc_end;
821 if (!pInput->pBuffers[input_token_idx].pvBuffer)
823 ret = SEC_E_INTERNAL_ERROR;
824 goto isc_end;
827 if(pInput->pBuffers[input_token_idx].cbBuffer > max_len)
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;
835 else
836 bin_len = pInput->pBuffers[input_token_idx].cbBuffer;
838 memcpy(bin, pInput->pBuffers[input_token_idx].pvBuffer, bin_len);
840 lstrcpynA(buffer, "TT ", max_len-1);
842 if((ret = encodeBase64(bin, bin_len, buffer+3,
843 max_len-3, &buffer_len)) != SEC_E_OK)
844 goto isc_end;
846 TRACE("Server sent: %s\n", debugstr_a(buffer));
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;
852 TRACE("Helper replied: %s\n", debugstr_a(buffer));
854 if( (strncmp(buffer, "KK ", 3) != 0) &&
855 (strncmp(buffer, "AF ", 3) !=0))
857 TRACE("Helper returned %c%c\n", buffer[0], buffer[1]);
858 ret = SEC_E_INVALID_TOKEN;
859 goto isc_end;
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)
866 goto isc_end;
869 phNewContext->dwUpper = ctxt_attr;
870 phNewContext->dwLower = (ULONG_PTR)helper;
872 ret = SEC_E_OK;
875 /* put the decoded client blob into the out buffer */
877 if (!pOutput || ((token_idx = ntlm_GetTokenBufferIndex(pOutput)) == -1))
879 TRACE("no SECBUFFER_TOKEN buffer could be found\n");
880 ret = SEC_E_BUFFER_TOO_SMALL;
881 if ((phContext == NULL) && (pInput == NULL))
883 cleanup_helper(helper);
884 phNewContext->dwUpper = 0;
885 phNewContext->dwLower = 0;
887 goto isc_end;
890 if (fContextReq & ISC_REQ_ALLOCATE_MEMORY)
892 pOutput->pBuffers[token_idx].pvBuffer = HeapAlloc(GetProcessHeap(), 0, bin_len);
893 pOutput->pBuffers[token_idx].cbBuffer = bin_len;
895 else if (pOutput->pBuffers[token_idx].cbBuffer < bin_len)
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))
901 cleanup_helper(helper);
902 phNewContext->dwUpper = 0;
903 phNewContext->dwLower = 0;
905 goto isc_end;
908 if (!pOutput->pBuffers[token_idx].pvBuffer)
910 TRACE("out buffer is NULL\n");
911 ret = SEC_E_INTERNAL_ERROR;
912 if ((phContext == NULL) && (pInput == NULL))
914 cleanup_helper(helper);
915 phNewContext->dwUpper = 0;
916 phNewContext->dwLower = 0;
918 goto isc_end;
921 pOutput->pBuffers[token_idx].cbBuffer = bin_len;
922 memcpy(pOutput->pBuffers[token_idx].pvBuffer, bin, bin_len);
924 if(ret == SEC_E_OK)
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;
931 if(buffer_len < 3)
933 TRACE("No flags negotiated.\n");
934 helper->neg_flags = 0l;
936 else
938 TRACE("Negotiated %s\n", debugstr_a(buffer));
939 sscanf(buffer + 3, "%x", &(helper->neg_flags));
940 TRACE("Stored 0x%08x as flags\n", helper->neg_flags);
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;
948 if(strncmp(buffer, "BH", 2) == 0)
949 TRACE("No key negotiated.\n");
950 else if(strncmp(buffer, "GK ", 3) == 0)
952 if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len,
953 &bin_len)) != SEC_E_OK)
955 TRACE("Failed to decode session key\n");
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)
962 ret = SEC_E_INSUFFICIENT_MEMORY;
963 goto isc_end;
965 memcpy(helper->session_key, bin, bin_len);
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;
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;
992 /***********************************************************************
993 * InitializeSecurityContextA
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)
1001 SECURITY_STATUS ret;
1002 SEC_WCHAR *target = NULL;
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);
1008 if(pszTargetName != NULL)
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);
1018 ret = ntlm_InitializeSecurityContextW(phCredential, phContext, target,
1019 fContextReq, Reserved1, TargetDataRep, pInput, Reserved2,
1020 phNewContext, pOutput, pfContextAttr, ptsExpiry);
1022 HeapFree(GetProcessHeap(), 0, target);
1023 return ret;
1026 /***********************************************************************
1027 * AcceptSecurityContext
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)
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;
1042 TRACE("%p %p %p %d %d %p %p %p %p\n", phCredential, phContext, pInput,
1043 fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr,
1044 ptsExpiry);
1046 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(char) * NTLM_MAX_BUF);
1047 bin = HeapAlloc(GetProcessHeap(),0, sizeof(BYTE) * NTLM_MAX_BUF);
1049 if(TargetDataRep == SECURITY_NETWORK_DREP){
1050 TRACE("Using SECURITY_NETWORK_DREP\n");
1053 if(phContext == NULL)
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 };
1060 if (!phCredential)
1062 ret = SEC_E_INVALID_HANDLE;
1063 goto asc_end;
1066 ntlm_cred = (PNtlmCredentials)phCredential->dwLower;
1068 if(ntlm_cred->mode != NTLM_SERVER)
1070 ret = SEC_E_INVALID_HANDLE;
1071 goto asc_end;
1074 /* This is the first call to AcceptSecurityHandle */
1075 if(pInput == NULL)
1077 ret = SEC_E_INCOMPLETE_MESSAGE;
1078 goto asc_end;
1081 if(pInput->cBuffers < 1)
1083 ret = SEC_E_INCOMPLETE_MESSAGE;
1084 goto asc_end;
1087 if(pInput->pBuffers[0].cbBuffer > max_len)
1089 ret = SEC_E_INVALID_TOKEN;
1090 goto asc_end;
1092 else
1093 bin_len = pInput->pBuffers[0].cbBuffer;
1095 if( (ret = fork_helper(&helper, ntlm_auth, server_argv)) !=
1096 SEC_E_OK)
1098 ret = SEC_E_INTERNAL_ERROR;
1099 goto asc_end;
1101 helper->mode = NTLM_SERVER;
1103 /* Handle all the flags */
1104 want_flags = HeapAlloc(GetProcessHeap(), 0, 73);
1105 if(want_flags == NULL)
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;
1112 lstrcpyA(want_flags, "SF");
1113 if(fContextReq & ASC_REQ_ALLOCATE_MEMORY)
1115 FIXME("ASC_REQ_ALLOCATE_MEMORY stub\n");
1117 if(fContextReq & ASC_REQ_CONFIDENTIALITY)
1119 lstrcatA(want_flags, " NTLMSSP_FEATURE_SEAL");
1121 if(fContextReq & ASC_REQ_CONNECTION)
1123 /* This is default, so we'll enable it */
1124 lstrcatA(want_flags, " NTLMSSP_FEATURE_SESSION_KEY");
1125 ctxt_attr |= ASC_RET_CONNECTION;
1127 if(fContextReq & ASC_REQ_EXTENDED_ERROR)
1129 FIXME("ASC_REQ_EXTENDED_ERROR stub\n");
1131 if(fContextReq & ASC_REQ_INTEGRITY)
1133 lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN");
1135 if(fContextReq & ASC_REQ_MUTUAL_AUTH)
1137 FIXME("ASC_REQ_MUTUAL_AUTH stub\n");
1139 if(fContextReq & ASC_REQ_REPLAY_DETECT)
1141 FIXME("ASC_REQ_REPLAY_DETECT stub\n");
1143 if(fContextReq & ISC_REQ_SEQUENCE_DETECT)
1145 FIXME("ASC_REQ_SEQUENCE_DETECT stub\n");
1147 if(fContextReq & ISC_REQ_STREAM)
1149 FIXME("ASC_REQ_STREAM stub\n");
1151 /* Done with the flags */
1153 if(lstrlenA(want_flags) > 3)
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)
1160 cleanup_helper(helper);
1161 goto asc_end;
1163 if(!strncmp(buffer, "BH", 2))
1164 TRACE("Helper doesn't understand new command set\n");
1167 /* This is the YR request from the client, encode to base64 */
1169 memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len);
1171 lstrcpynA(buffer, "YR ", max_len-1);
1173 if((ret = encodeBase64(bin, bin_len, buffer+3, max_len-3,
1174 &buffer_len)) != SEC_E_OK)
1176 cleanup_helper(helper);
1177 goto asc_end;
1180 TRACE("Client sent: %s\n", debugstr_a(buffer));
1182 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) !=
1183 SEC_E_OK)
1185 cleanup_helper(helper);
1186 goto asc_end;
1189 TRACE("Reply from ntlm_auth: %s\n", debugstr_a(buffer));
1190 /* The expected answer is TT <base64 blob> */
1192 if(strncmp(buffer, "TT ", 3) != 0)
1194 ret = SEC_E_INTERNAL_ERROR;
1195 cleanup_helper(helper);
1196 goto asc_end;
1199 if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len,
1200 &bin_len)) != SEC_E_OK)
1202 cleanup_helper(helper);
1203 goto asc_end;
1206 /* send this to the client */
1207 if(pOutput == NULL)
1209 ret = SEC_E_INSUFFICIENT_MEMORY;
1210 cleanup_helper(helper);
1211 goto asc_end;
1214 if(pOutput->cBuffers < 1)
1216 ret = SEC_E_INSUFFICIENT_MEMORY;
1217 cleanup_helper(helper);
1218 goto asc_end;
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;
1227 else
1229 /* we expect a KK request from client */
1230 if(pInput == NULL)
1232 ret = SEC_E_INCOMPLETE_MESSAGE;
1233 goto asc_end;
1236 if(pInput->cBuffers < 1)
1238 ret = SEC_E_INCOMPLETE_MESSAGE;
1239 goto asc_end;
1242 helper = (PNegoHelper)phContext->dwLower;
1244 if(helper->mode != NTLM_SERVER)
1246 ret = SEC_E_INVALID_HANDLE;
1247 goto asc_end;
1250 if(pInput->pBuffers[0].cbBuffer > max_len)
1252 ret = SEC_E_INVALID_TOKEN;
1253 goto asc_end;
1255 else
1256 bin_len = pInput->pBuffers[0].cbBuffer;
1258 memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len);
1260 lstrcpynA(buffer, "KK ", max_len-1);
1262 if((ret = encodeBase64(bin, bin_len, buffer+3, max_len-3,
1263 &buffer_len)) != SEC_E_OK)
1265 goto asc_end;
1268 TRACE("Client sent: %s\n", debugstr_a(buffer));
1270 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) !=
1271 SEC_E_OK)
1273 goto asc_end;
1276 TRACE("Reply from ntlm_auth: %s\n", debugstr_a(buffer));
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)
1284 if(strncmp(buffer, "NA ", 3) == 0)
1286 ret = SEC_E_LOGON_DENIED;
1287 goto asc_end;
1289 else
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");
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) )
1299 TRACE("Connection to winbindd failed\n");
1300 ret = SEC_E_LOGON_DENIED;
1302 else
1303 ret = SEC_E_INTERNAL_ERROR;
1305 goto asc_end;
1308 pOutput->pBuffers[0].cbBuffer = 0;
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;
1315 if(buffer_len < 3)
1317 TRACE("No flags negotiated, or helper does not support GF command\n");
1319 else
1321 TRACE("Negotiated %s\n", debugstr_a(buffer));
1322 sscanf(buffer + 3, "%x", &(helper->neg_flags));
1323 TRACE("Stored 0x%08x as flags\n", helper->neg_flags);
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;
1331 if(buffer_len < 3)
1332 TRACE("Helper does not support GK command\n");
1333 else
1335 if(strncmp(buffer, "BH ", 3) == 0)
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)
1342 ret = SEC_E_INSUFFICIENT_MEMORY;
1343 goto asc_end;
1345 /*FIXME: Generate the dummy session key = MD4(MD4(password))*/
1346 memset(helper->session_key, 0 , 16);
1348 else if(strncmp(buffer, "GK ", 3) == 0)
1350 if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len,
1351 &bin_len)) != SEC_E_OK)
1353 TRACE("Failed to decode session key\n");
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)
1360 ret = SEC_E_INSUFFICIENT_MEMORY;
1361 goto asc_end;
1363 memcpy(helper->session_key, bin, 16);
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;
1371 phNewContext->dwUpper = ctxt_attr;
1372 phNewContext->dwLower = (ULONG_PTR)helper;
1374 asc_end:
1375 HeapFree(GetProcessHeap(), 0, want_flags);
1376 HeapFree(GetProcessHeap(), 0, buffer);
1377 HeapFree(GetProcessHeap(), 0, bin);
1378 return ret;
1381 /***********************************************************************
1382 * CompleteAuthToken
1384 static SECURITY_STATUS SEC_ENTRY ntlm_CompleteAuthToken(PCtxtHandle phContext,
1385 PSecBufferDesc pToken)
1387 /* We never need to call CompleteAuthToken anyway */
1388 TRACE("%p %p\n", phContext, pToken);
1389 if (!phContext)
1390 return SEC_E_INVALID_HANDLE;
1392 return SEC_E_OK;
1395 /***********************************************************************
1396 * DeleteSecurityContext
1398 SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext)
1400 PNegoHelper helper;
1402 TRACE("%p\n", phContext);
1403 if (!phContext)
1404 return SEC_E_INVALID_HANDLE;
1406 helper = (PNegoHelper)phContext->dwLower;
1408 phContext->dwUpper = 0;
1409 phContext->dwLower = 0;
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);
1419 cleanup_helper(helper);
1421 return SEC_E_OK;
1424 /***********************************************************************
1425 * QueryContextAttributesW
1427 SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext,
1428 ULONG ulAttribute, void *pBuffer)
1430 TRACE("%p %d %p\n", phContext, ulAttribute, pBuffer);
1431 if (!phContext)
1432 return SEC_E_INVALID_HANDLE;
1434 switch(ulAttribute)
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:
1442 PSecPkgContext_Flags spcf = (PSecPkgContext_Flags)pBuffer;
1443 PNegoHelper helper = (PNegoHelper)phContext->dwLower;
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;
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:
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;
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);
1476 return SEC_E_UNSUPPORTED_FUNCTION;
1479 /***********************************************************************
1480 * QueryContextAttributesA
1482 SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(PCtxtHandle phContext,
1483 ULONG ulAttribute, void *pBuffer)
1485 return ntlm_QueryContextAttributesW(phContext, ulAttribute, pBuffer);
1488 /***********************************************************************
1489 * ImpersonateSecurityContext
1491 static SECURITY_STATUS SEC_ENTRY ntlm_ImpersonateSecurityContext(PCtxtHandle phContext)
1493 SECURITY_STATUS ret;
1495 TRACE("%p\n", phContext);
1496 if (phContext)
1498 ret = SEC_E_UNSUPPORTED_FUNCTION;
1500 else
1502 ret = SEC_E_INVALID_HANDLE;
1504 return ret;
1507 /***********************************************************************
1508 * RevertSecurityContext
1510 static SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(PCtxtHandle phContext)
1512 SECURITY_STATUS ret;
1514 TRACE("%p\n", phContext);
1515 if (phContext)
1517 ret = SEC_E_UNSUPPORTED_FUNCTION;
1519 else
1521 ret = SEC_E_INVALID_HANDLE;
1523 return ret;
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.
1536 static SECURITY_STATUS ntlm_CreateSignature(PNegoHelper helper, PSecBufferDesc pMessage,
1537 int token_idx, SignDirection direction, BOOL encrypt_sig)
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);
1545 sig = pMessage->pBuffers[token_idx].pvBuffer;
1547 if(helper->neg_flags & NTLMSSP_NEGOTIATE_NTLM2 &&
1548 helper->neg_flags & NTLMSSP_NEGOTIATE_SIGN)
1550 BYTE digest[16];
1551 BYTE seq_no[4];
1552 HMAC_MD5_CTX hmac_md5_ctx;
1554 TRACE("Signing NTLM2 style\n");
1556 if(direction == NTLM_SEND)
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;
1563 ++(helper->crypt.ntlm2.send_seq_no);
1565 HMACMD5Init(&hmac_md5_ctx, helper->crypt.ntlm2.send_sign_key, 16);
1567 else
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;
1574 ++(helper->crypt.ntlm2.recv_seq_no);
1576 HMACMD5Init(&hmac_md5_ctx, helper->crypt.ntlm2.recv_sign_key, 16);
1579 HMACMD5Update(&hmac_md5_ctx, seq_no, 4);
1580 for( i = 0; i < pMessage->cBuffers; ++i )
1582 if(pMessage->pBuffers[i].BufferType & SECBUFFER_DATA)
1583 HMACMD5Update(&hmac_md5_ctx, pMessage->pBuffers[i].pvBuffer,
1584 pMessage->pBuffers[i].cbBuffer);
1587 HMACMD5Final(&hmac_md5_ctx, digest);
1589 if(encrypt_sig && helper->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCHANGE)
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);
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);
1607 pMessage->pBuffers[token_idx].cbBuffer = 16;
1609 return SEC_E_OK;
1611 if(helper->neg_flags & NTLMSSP_NEGOTIATE_SIGN)
1613 ULONG crc = 0U;
1614 TRACE("Signing NTLM1 style\n");
1616 for(i=0; i < pMessage->cBuffers; ++i)
1618 if(pMessage->pBuffers[i].BufferType & SECBUFFER_DATA)
1620 crc = ComputeCrc32(pMessage->pBuffers[i].pvBuffer,
1621 pMessage->pBuffers[i].cbBuffer, crc);
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;
1639 ++(helper->crypt.ntlm.seq_num);
1641 if(encrypt_sig)
1642 SECUR32_arc4Process(helper->crypt.ntlm.a4i, sig+4, 12);
1643 return SEC_E_OK;
1646 if(helper->neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN || helper->neg_flags == 0)
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;
1656 return SEC_E_UNSUPPORTED_FUNCTION;
1659 /***********************************************************************
1660 * MakeSignature
1662 SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext,
1663 ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
1665 PNegoHelper helper;
1666 int token_idx;
1668 TRACE("%p %d %p %d\n", phContext, fQOP, pMessage, MessageSeqNo);
1669 if (!phContext)
1670 return SEC_E_INVALID_HANDLE;
1672 if(fQOP)
1673 FIXME("Ignoring fQOP 0x%08x\n", fQOP);
1675 if(MessageSeqNo)
1676 FIXME("Ignoring MessageSeqNo\n");
1678 if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2)
1679 return SEC_E_INVALID_TOKEN;
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;
1685 if(pMessage->pBuffers[token_idx].cbBuffer < 16)
1686 return SEC_E_BUFFER_TOO_SMALL;
1688 helper = (PNegoHelper)phContext->dwLower;
1689 TRACE("Negotiated flags are: 0x%08x\n", helper->neg_flags);
1691 return ntlm_CreateSignature(helper, pMessage, token_idx, NTLM_SEND, TRUE);
1694 /***********************************************************************
1695 * VerifySignature
1697 SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle phContext,
1698 PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
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];
1708 TRACE("%p %p %d %p\n", phContext, pMessage, MessageSeqNo, pfQOP);
1709 if(!phContext)
1710 return SEC_E_INVALID_HANDLE;
1712 if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2)
1713 return SEC_E_INVALID_TOKEN;
1715 if((token_idx = ntlm_GetTokenBufferIndex(pMessage)) == -1)
1716 return SEC_E_INVALID_TOKEN;
1718 if(pMessage->pBuffers[token_idx].cbBuffer < 16)
1719 return SEC_E_BUFFER_TOO_SMALL;
1721 if(MessageSeqNo)
1722 FIXME("Ignoring MessageSeqNo\n");
1724 helper = (PNegoHelper)phContext->dwLower;
1725 TRACE("Negotiated flags: 0x%08x\n", helper->neg_flags);
1727 local_buff = HeapAlloc(GetProcessHeap(), 0, pMessage->cBuffers * sizeof(SecBuffer));
1729 local_desc.ulVersion = SECBUFFER_VERSION;
1730 local_desc.cBuffers = pMessage->cBuffers;
1731 local_desc.pBuffers = local_buff;
1733 for(i=0; i < pMessage->cBuffers; ++i)
1735 if(pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN)
1737 local_buff[i].BufferType = SECBUFFER_TOKEN;
1738 local_buff[i].cbBuffer = 16;
1739 local_buff[i].pvBuffer = local_sig;
1741 else
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;
1749 if((ret = ntlm_CreateSignature(helper, &local_desc, token_idx, NTLM_RECV, TRUE)) != SEC_E_OK)
1750 return ret;
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;
1758 HeapFree(GetProcessHeap(), 0, local_buff);
1760 return ret;
1764 /***********************************************************************
1765 * FreeCredentialsHandle
1767 SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(PCredHandle phCredential)
1769 SECURITY_STATUS ret;
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;
1783 else
1784 ret = SEC_E_OK;
1786 return ret;
1789 /***********************************************************************
1790 * EncryptMessage
1792 SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext,
1793 ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
1795 PNegoHelper helper;
1796 int token_idx, data_idx;
1798 TRACE("(%p %d %p %d)\n", phContext, fQOP, pMessage, MessageSeqNo);
1800 if(!phContext)
1801 return SEC_E_INVALID_HANDLE;
1803 if(fQOP)
1804 FIXME("Ignoring fQOP\n");
1806 if(MessageSeqNo)
1807 FIXME("Ignoring MessageSeqNo\n");
1809 if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2)
1810 return SEC_E_INVALID_TOKEN;
1812 if((token_idx = ntlm_GetTokenBufferIndex(pMessage)) == -1)
1813 return SEC_E_INVALID_TOKEN;
1815 if((data_idx = ntlm_GetDataBufferIndex(pMessage)) ==-1 )
1816 return SEC_E_INVALID_TOKEN;
1818 if(pMessage->pBuffers[token_idx].cbBuffer < 16)
1819 return SEC_E_BUFFER_TOO_SMALL;
1821 helper = (PNegoHelper) phContext->dwLower;
1823 if(helper->neg_flags & NTLMSSP_NEGOTIATE_NTLM2 &&
1824 helper->neg_flags & NTLMSSP_NEGOTIATE_SEAL)
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);
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);
1835 else
1837 PBYTE sig;
1838 ULONG save_flags;
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;
1847 sig = pMessage->pBuffers[token_idx].pvBuffer;
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);
1854 if(helper->neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN || helper->neg_flags == 0)
1855 memset(sig+4, 0, 4);
1857 return SEC_E_OK;
1860 /***********************************************************************
1861 * DecryptMessage
1863 SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext,
1864 PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
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);
1872 if(!phContext)
1873 return SEC_E_INVALID_HANDLE;
1875 if(MessageSeqNo)
1876 FIXME("Ignoring MessageSeqNo\n");
1878 if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2)
1879 return SEC_E_INVALID_TOKEN;
1881 if((token_idx = ntlm_GetTokenBufferIndex(pMessage)) == -1)
1882 return SEC_E_INVALID_TOKEN;
1884 if((data_idx = ntlm_GetDataBufferIndex(pMessage)) ==-1)
1885 return SEC_E_INVALID_TOKEN;
1887 if(pMessage->pBuffers[token_idx].cbBuffer < 16)
1888 return SEC_E_BUFFER_TOO_SMALL;
1890 helper = (PNegoHelper) phContext->dwLower;
1892 if(helper->neg_flags & NTLMSSP_NEGOTIATE_NTLM2 && helper->neg_flags & NTLMSSP_NEGOTIATE_SEAL)
1894 SECUR32_arc4Process(helper->crypt.ntlm2.recv_a4i,
1895 pMessage->pBuffers[data_idx].pvBuffer,
1896 pMessage->pBuffers[data_idx].cbBuffer);
1898 else
1900 SECUR32_arc4Process(helper->crypt.ntlm.a4i,
1901 pMessage->pBuffers[data_idx].pvBuffer,
1902 pMessage->pBuffers[data_idx].cbBuffer);
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;
1909 helper->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
1910 ret = ntlm_VerifySignature(phContext, pMessage, MessageSeqNo, pfQOP);
1912 helper->neg_flags = ntlmssp_flags_save;
1914 return ret;
1917 static const SecurityFunctionTableA ntlmTableA = {
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 */
1948 static const SecurityFunctionTableW ntlmTableW = {
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 */
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}
1984 static CHAR ntlm_comment_A[] = NTLM_COMMENT;
1985 static WCHAR ntlm_comment_W[] = NTLM_COMMENT;
1987 #define NTLM_NAME {'N', 'T', 'L', 'M', 0}
1989 static char ntlm_name_A[] = NTLM_NAME;
1990 static WCHAR ntlm_name_W[] = NTLM_NAME;
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 )
2005 static const SecPkgInfoW infoW = {
2006 CAPS,
2008 RPC_C_AUTHN_WINNT,
2009 NTLM_MAX_BUF,
2010 ntlm_name_W,
2011 ntlm_comment_W
2014 static const SecPkgInfoA infoA = {
2015 CAPS,
2017 RPC_C_AUTHN_WINNT,
2018 NTLM_MAX_BUF,
2019 ntlm_name_A,
2020 ntlm_comment_A
2023 SecPkgInfoA *ntlm_package_infoA = (SecPkgInfoA *)&infoA;
2024 SecPkgInfoW *ntlm_package_infoW = (SecPkgInfoW *)&infoW;
2026 void SECUR32_initNTLMSP(void)
2028 PNegoHelper helper;
2029 static CHAR version[] = "--version";
2031 SEC_CHAR *args[] = {
2032 ntlm_auth,
2033 version,
2034 NULL };
2036 if(fork_helper(&helper, ntlm_auth, args) != SEC_E_OK)
2037 helper = NULL;
2038 else
2039 check_version(helper);
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)) )
2049 SecureProvider *provider = SECUR32_addProvider(&ntlmTableA, &ntlmTableW, NULL);
2050 SECUR32_addPackages(provider, 1L, ntlm_package_infoA, ntlm_package_infoW);
2052 else
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);
2063 cleanup_helper(helper);