secur32: Don't fail on SECURITY_NETWORK_DREP, ntlm_auth handles this just fine.
[wine.git] / dlls / secur32 / ntlm.c
blob3554f672794ac88cf1f2e115dd3c9dc151b1ea2e
1 /*
2 * Copyright 2005 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 "windef.h"
24 #include "winbase.h"
25 #include "winnls.h"
26 #include "rpc.h"
27 #include "sspi.h"
28 #include "lm.h"
29 #include "secur32_priv.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
34 #define NTLM_MAX_BUF 2010
37 /***********************************************************************
38 * QueryCredentialsAttributesA
40 static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesA(
41 PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
43 SECURITY_STATUS ret;
45 TRACE("(%p, %ld, %p)\n", phCredential, ulAttribute, pBuffer);
47 if(ulAttribute == SECPKG_ATTR_NAMES)
49 FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
50 ret = SEC_E_UNSUPPORTED_FUNCTION;
52 else
53 ret = SEC_E_UNSUPPORTED_FUNCTION;
55 return ret;
58 /***********************************************************************
59 * QueryCredentialsAttributesW
61 static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesW(
62 PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
64 SECURITY_STATUS ret;
66 TRACE("(%p, %ld, %p)\n", phCredential, ulAttribute, pBuffer);
68 if(ulAttribute == SECPKG_ATTR_NAMES)
70 FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
71 ret = SEC_E_UNSUPPORTED_FUNCTION;
73 else
74 ret = SEC_E_UNSUPPORTED_FUNCTION;
76 return ret;
79 /***********************************************************************
80 * AcquireCredentialsHandleW
82 static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(
83 SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse,
84 PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
85 PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
87 SECURITY_STATUS ret;
88 PNegoHelper helper = NULL;
90 SEC_CHAR *client_user_arg = NULL;
91 SEC_CHAR *client_domain_arg = NULL;
92 SEC_WCHAR *username = NULL, *domain = NULL;
94 SEC_CHAR *client_argv[5];
95 SEC_CHAR *server_argv[] = { "ntlm_auth",
96 "--helper-protocol=squid-2.5-ntlmssp",
97 NULL };
99 TRACE("(%s, %s, 0x%08lx, %p, %p, %p, %p, %p, %p)\n",
100 debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse,
101 pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
104 switch(fCredentialUse)
106 case SECPKG_CRED_INBOUND:
107 if( (ret = fork_helper(&helper, "ntlm_auth", server_argv)) !=
108 SEC_E_OK)
110 phCredential = NULL;
111 break;
113 else
115 helper->mode = NTLM_SERVER;
116 phCredential->dwUpper = fCredentialUse;
117 phCredential->dwLower = (DWORD)helper;
119 ret = SEC_E_OK;
120 break;
121 case SECPKG_CRED_OUTBOUND:
123 static const char username_arg[] = "--username=";
124 static const char domain_arg[] = "--domain=";
125 int unixcp_size;
127 if(pAuthData == NULL)
129 LPWKSTA_USER_INFO_1 ui = NULL;
130 NET_API_STATUS status;
132 status = NetWkstaUserGetInfo(NULL, 1, (LPBYTE *)&ui);
133 if (status != NERR_Success || ui == NULL)
135 ret = SEC_E_NO_CREDENTIALS;
136 phCredential = NULL;
137 break;
140 username = HeapAlloc(GetProcessHeap(), 0,
141 (lstrlenW(ui->wkui1_username)+1) *
142 sizeof(SEC_WCHAR));
143 lstrcpyW(username, ui->wkui1_username);
145 /* same for the domain */
146 domain = HeapAlloc(GetProcessHeap(), 0,
147 (lstrlenW(ui->wkui1_logon_domain)+1) *
148 sizeof(SEC_WCHAR));
149 lstrcpyW(domain, ui->wkui1_logon_domain);
150 NetApiBufferFree(ui);
152 else
154 PSEC_WINNT_AUTH_IDENTITY_W auth_data =
155 (PSEC_WINNT_AUTH_IDENTITY_W)pAuthData;
157 if (!auth_data->UserLength || !auth_data->DomainLength)
159 ret = SEC_E_NO_CREDENTIALS;
160 phCredential = NULL;
161 break;
163 /* Get username and domain from pAuthData */
164 username = HeapAlloc(GetProcessHeap(), 0,
165 (auth_data->UserLength + 1) * sizeof(SEC_WCHAR));
166 lstrcpyW(username, auth_data->User);
168 domain = HeapAlloc(GetProcessHeap(), 0,
169 (auth_data->DomainLength + 1) * sizeof(SEC_WCHAR));
170 lstrcpyW(domain, auth_data->Domain);
172 TRACE("Username is %s\n", debugstr_w(username));
173 unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
174 username, -1, NULL, 0, NULL, NULL) + sizeof(username_arg);
175 client_user_arg = HeapAlloc(GetProcessHeap(), 0, unixcp_size);
176 lstrcpyA(client_user_arg, username_arg);
177 WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, username, -1,
178 client_user_arg + sizeof(username_arg) - 1,
179 unixcp_size - sizeof(username_arg) + 1, NULL, NULL);
181 TRACE("Domain name is %s\n", debugstr_w(domain));
182 unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
183 domain, -1, NULL, 0, NULL, NULL) + sizeof(domain_arg);
184 client_domain_arg = HeapAlloc(GetProcessHeap(), 0, unixcp_size);
185 lstrcpyA(client_domain_arg, domain_arg);
186 WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, domain,
187 -1, client_domain_arg + sizeof(domain_arg) - 1,
188 unixcp_size - sizeof(domain) + 1, NULL, NULL);
190 client_argv[0] = "ntlm_auth";
191 client_argv[1] = "--helper-protocol=ntlmssp-client-1";
192 client_argv[2] = client_user_arg;
193 client_argv[3] = client_domain_arg;
194 client_argv[4] = NULL;
196 if((ret = fork_helper(&helper, "ntlm_auth", client_argv)) !=
197 SEC_E_OK)
199 phCredential = NULL;
200 break;
202 else
204 helper->mode = NTLM_CLIENT;
206 if(pAuthData != NULL)
208 PSEC_WINNT_AUTH_IDENTITY_W auth_data =
209 (PSEC_WINNT_AUTH_IDENTITY_W)pAuthData;
211 if(auth_data->PasswordLength != 0)
213 helper->pwlen = WideCharToMultiByte(CP_UNIXCP,
214 WC_NO_BEST_FIT_CHARS, auth_data->Password,
215 auth_data->PasswordLength+1, NULL, 0, NULL, NULL);
217 helper->password = HeapAlloc(GetProcessHeap(), 0,
218 helper->pwlen);
220 WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
221 auth_data->Password, auth_data->PasswordLength+1,
222 helper->password, helper->pwlen, NULL, NULL);
226 phCredential->dwUpper = fCredentialUse;
227 phCredential->dwLower = (DWORD)helper;
228 TRACE("ACH phCredential->dwUpper: 0x%08lx, dwLower: 0x%08lx\n",
229 phCredential->dwUpper, phCredential->dwLower);
231 ret = SEC_E_OK;
232 break;
234 case SECPKG_CRED_BOTH:
235 FIXME("AcquireCredentialsHandle: SECPKG_CRED_BOTH stub\n");
236 ret = SEC_E_UNSUPPORTED_FUNCTION;
237 phCredential = NULL;
238 break;
239 default:
240 phCredential = NULL;
241 ret = SEC_E_UNKNOWN_CREDENTIALS;
245 HeapFree(GetProcessHeap(), 0, client_user_arg);
246 HeapFree(GetProcessHeap(), 0, client_domain_arg);
247 HeapFree(GetProcessHeap(), 0, username);
248 HeapFree(GetProcessHeap(), 0, domain);
250 return ret;
253 /***********************************************************************
254 * AcquireCredentialsHandleA
256 static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA(
257 SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse,
258 PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
259 PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
261 SECURITY_STATUS ret;
262 int user_sizeW, domain_sizeW, passwd_sizeW;
264 SEC_WCHAR *user = NULL, *domain = NULL, *passwd = NULL, *package = NULL;
266 PSEC_WINNT_AUTH_IDENTITY_W pAuthDataW = NULL;
267 PSEC_WINNT_AUTH_IDENTITY_A identity = NULL;
269 TRACE("(%s, %s, 0x%08lx, %p, %p, %p, %p, %p, %p)\n",
270 debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse,
271 pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
273 if(pszPackage != NULL)
275 int package_sizeW = MultiByteToWideChar(CP_ACP, 0, pszPackage, -1,
276 NULL, 0);
278 package = HeapAlloc(GetProcessHeap(), 0, package_sizeW *
279 sizeof(SEC_WCHAR));
280 MultiByteToWideChar(CP_ACP, 0, pszPackage, -1, package, package_sizeW);
284 if(pAuthData != NULL)
286 identity = (PSEC_WINNT_AUTH_IDENTITY_A)pAuthData;
288 if(identity->Flags == SEC_WINNT_AUTH_IDENTITY_ANSI)
290 pAuthDataW = HeapAlloc(GetProcessHeap(), 0,
291 sizeof(SEC_WINNT_AUTH_IDENTITY_W));
293 if(identity->UserLength != 0)
295 user_sizeW = MultiByteToWideChar(CP_ACP, 0,
296 (LPCSTR)identity->User, identity->UserLength+1, NULL, 0);
297 user = HeapAlloc(GetProcessHeap(), 0, user_sizeW *
298 sizeof(SEC_WCHAR));
299 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->User,
300 identity->UserLength+1, user, user_sizeW);
302 else
304 user_sizeW = 0;
307 if(identity->DomainLength != 0)
309 domain_sizeW = MultiByteToWideChar(CP_ACP, 0,
310 (LPCSTR)identity->Domain, identity->DomainLength+1, NULL, 0);
311 domain = HeapAlloc(GetProcessHeap(), 0, domain_sizeW
312 * sizeof(SEC_WCHAR));
313 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->Domain,
314 identity->DomainLength+1, domain, domain_sizeW);
316 else
318 domain_sizeW = 0;
321 if(identity->PasswordLength != 0)
323 passwd_sizeW = MultiByteToWideChar(CP_ACP, 0,
324 (LPCSTR)identity->Password, identity->PasswordLength+1,
325 NULL, 0);
326 passwd = HeapAlloc(GetProcessHeap(), 0, passwd_sizeW
327 * sizeof(SEC_WCHAR));
328 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->Password,
329 identity->PasswordLength+1, passwd, passwd_sizeW);
331 else
333 passwd_sizeW = 0;
336 pAuthDataW->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
337 pAuthDataW->User = user;
338 pAuthDataW->UserLength = user_sizeW;
339 pAuthDataW->Domain = domain;
340 pAuthDataW->DomainLength = domain_sizeW;
341 pAuthDataW->Password = passwd;
342 pAuthDataW->PasswordLength = passwd_sizeW;
344 else
346 pAuthDataW = (PSEC_WINNT_AUTH_IDENTITY_W)identity;
350 ret = ntlm_AcquireCredentialsHandleW(NULL, package, fCredentialUse,
351 pLogonID, pAuthDataW, pGetKeyFn, pGetKeyArgument, phCredential,
352 ptsExpiry);
354 HeapFree(GetProcessHeap(), 0, package);
355 HeapFree(GetProcessHeap(), 0, user);
356 HeapFree(GetProcessHeap(), 0, domain);
357 HeapFree(GetProcessHeap(), 0, passwd);
358 if(pAuthDataW != (PSEC_WINNT_AUTH_IDENTITY_W)identity)
359 HeapFree(GetProcessHeap(), 0, pAuthDataW);
361 return ret;
364 /***********************************************************************
365 * InitializeSecurityContextW
367 static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
368 PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName,
369 ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
370 PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
371 PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
373 SECURITY_STATUS ret;
374 PNegoHelper helper;
375 ULONG ctxt_attr = 0;
376 char* buffer;
377 PBYTE bin;
378 int buffer_len, bin_len, max_len = NTLM_MAX_BUF;
380 TRACE("%p %p %s %ld %ld %ld %p %ld %p %p %p %p\n", phCredential, phContext,
381 debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
382 Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
384 if(!phCredential)
385 return SEC_E_INVALID_HANDLE;
387 /* As the server side of sspi never calls this, make sure that
388 * the handler is a client handler.
390 helper = (PNegoHelper)phCredential->dwLower;
391 if(helper->mode != NTLM_CLIENT)
393 TRACE("Helper mode = %d\n", helper->mode);
394 return SEC_E_INVALID_HANDLE;
397 /****************************************
398 * When communicating with the client, there can be the
399 * following reply packets:
400 * YR <base64 blob> should be sent to the server
401 * PW should be sent back to helper with
402 * base64 encoded password
403 * AF <base64 blob> client is done, blob should be
404 * sent to server with KK prefixed
405 * BH <char reason> something broke
407 /* The squid cache size is 2010 chars, and that's what ntlm_auth uses */
409 if (pszTargetName)
411 TRACE("According to a MS whitepaper pszTargetName is ignored.\n");
413 /* Handle all the flags */
414 if(fContextReq & ISC_REQ_CONFIDENTIALITY)
416 FIXME("InitializeSecurityContext(): ISC_REQ_CONFIDENTIALITY stub\n");
418 if(fContextReq & ISC_REQ_CONNECTION)
420 /* This is default, so we'll enable it */
421 ctxt_attr |= ISC_RET_CONNECTION;
423 if(fContextReq & ISC_REQ_EXTENDED_ERROR)
424 FIXME("ISC_REQ_EXTENDED_ERROR\n");
425 if(fContextReq & ISC_REQ_INTEGRITY)
426 FIXME("ISC_REQ_INTEGRITY\n");
427 if(fContextReq & ISC_REQ_MUTUAL_AUTH)
428 FIXME("ISC_REQ_MUTUAL_AUTH\n");
429 if(fContextReq & ISC_REQ_REPLAY_DETECT)
430 FIXME("ISC_REQ_REPLAY_DETECT\n");
431 if(fContextReq & ISC_REQ_SEQUENCE_DETECT)
432 FIXME("ISC_REQ_SEQUENCE_DETECT\n");
433 if(fContextReq & ISC_REQ_STREAM)
434 FIXME("ISC_REQ_STREAM\n");
436 /* Done with the flags */
437 if(TargetDataRep == SECURITY_NETWORK_DREP){
438 TRACE("Setting SECURITY_NETWORK_DREP\n");
441 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(char) * NTLM_MAX_BUF);
442 bin = HeapAlloc(GetProcessHeap(), 0, sizeof(BYTE) * NTLM_MAX_BUF);
444 if((phContext == NULL) && (pInput == NULL))
446 TRACE("First time in ISC()\n");
447 /* Request a challenge request from ntlm_auth */
448 if(helper->password == NULL)
450 FIXME("Using empty password for now.\n");
451 lstrcpynA(buffer, "PW AA==", max_len-1);
453 else
455 lstrcpynA(buffer, "PW ", max_len-1);
456 if((ret = encodeBase64((unsigned char*)helper->password,
457 helper->pwlen-2, buffer+3,
458 max_len-3, &buffer_len)) != SEC_E_OK)
460 TRACE("Deleting password!\n");
461 memset(helper->password, 0, helper->pwlen-2);
462 HeapFree(GetProcessHeap(), 0, helper->password);
463 goto end;
468 TRACE("Sending to helper: %s\n", debugstr_a(buffer));
469 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
470 goto end;
472 TRACE("Helper returned %s\n", debugstr_a(buffer));
473 lstrcpynA(buffer, "YR", max_len-1);
475 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
476 goto end;
478 TRACE("%s\n", buffer);
480 if(strncmp(buffer, "YR ", 3) != 0)
482 /* Something borked */
483 TRACE("Helper returned %c%c\n", buffer[0], buffer[1]);
484 ret = SEC_E_INTERNAL_ERROR;
485 goto end;
487 if((ret = decodeBase64(buffer+3, buffer_len-3, bin,
488 max_len-1, &bin_len)) != SEC_E_OK)
489 goto end;
491 /* put the decoded client blob into the out buffer */
493 ret = SEC_I_CONTINUE_NEEDED;
495 else
497 /* handle second call here */
498 /* encode server data to base64 */
499 if (!pInput || !pInput->cBuffers)
501 ret = SEC_E_INCOMPLETE_MESSAGE;
502 goto end;
505 if (!pInput->pBuffers[0].pvBuffer)
507 ret = SEC_E_INTERNAL_ERROR;
508 goto end;
511 if(pInput->pBuffers[0].cbBuffer > max_len)
513 TRACE("pInput->pBuffers[0].cbBuffer is: %ld\n",
514 pInput->pBuffers[0].cbBuffer);
515 ret = SEC_E_INVALID_TOKEN;
516 goto end;
518 else
519 bin_len = pInput->pBuffers[0].cbBuffer;
521 memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len);
523 lstrcpynA(buffer, "TT ", max_len-1);
525 if((ret = encodeBase64(bin, bin_len, buffer+3,
526 max_len-3, &buffer_len)) != SEC_E_OK)
527 goto end;
529 TRACE("Server sent: %s\n", debugstr_a(buffer));
531 /* send TT base64 blob to ntlm_auth */
532 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
533 goto end;
535 TRACE("Helper replied: %s\n", debugstr_a(buffer));
537 if( (strncmp(buffer, "KK ", 3) != 0) &&
538 (strncmp(buffer, "AF ", 3) !=0))
540 TRACE("Helper returned %c%c\n", buffer[0], buffer[1]);
541 HeapFree(GetProcessHeap(), 0, buffer);
542 HeapFree(GetProcessHeap(), 0, bin);
543 return SEC_E_INVALID_TOKEN;
546 /* decode the blob and send it to server */
547 if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len,
548 &bin_len)) != SEC_E_OK)
550 HeapFree(GetProcessHeap(), 0, buffer);
551 HeapFree(GetProcessHeap(), 0, bin);
552 return ret;
555 phNewContext->dwUpper = ctxt_attr;
556 phNewContext->dwLower = ret;
558 ret = SEC_E_OK;
561 /* put the decoded client blob into the out buffer */
563 if (fContextReq & ISC_REQ_ALLOCATE_MEMORY)
565 if (pOutput)
567 pOutput->cBuffers = 1;
568 pOutput->pBuffers[0].pvBuffer = SECUR32_ALLOC(bin_len);
569 pOutput->pBuffers[0].cbBuffer = bin_len;
573 if (!pOutput || !pOutput->cBuffers || pOutput->pBuffers[0].cbBuffer < bin_len)
575 TRACE("out buffer is NULL or has not enough space\n");
576 ret = SEC_E_BUFFER_TOO_SMALL;
577 goto end;
580 if (!pOutput->pBuffers[0].pvBuffer)
582 TRACE("out buffer is NULL\n");
583 ret = SEC_E_INTERNAL_ERROR;
584 goto end;
587 pOutput->pBuffers[0].cbBuffer = bin_len;
588 pOutput->pBuffers[0].BufferType = SECBUFFER_DATA;
589 memcpy(pOutput->pBuffers[0].pvBuffer, bin, bin_len);
591 if(ret != SEC_I_CONTINUE_NEEDED)
593 TRACE("Deleting password!\n");
594 if(helper->password)
595 memset(helper->password, 0, helper->pwlen-2);
596 HeapFree(GetProcessHeap(), 0, helper->password);
598 end:
599 HeapFree(GetProcessHeap(), 0, buffer);
600 HeapFree(GetProcessHeap(), 0, bin);
601 return ret;
604 /***********************************************************************
605 * InitializeSecurityContextA
607 static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA(
608 PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName,
609 ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
610 PSecBufferDesc pInput,ULONG Reserved2, PCtxtHandle phNewContext,
611 PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
613 SECURITY_STATUS ret;
615 TRACE("%p %p %s %ld %ld %ld %p %ld %p %p %p %p\n", phCredential, phContext,
616 debugstr_a(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
617 Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
619 if (phCredential)
621 SEC_WCHAR *target = NULL;
622 if(pszTargetName != NULL)
624 int target_size = MultiByteToWideChar(CP_ACP, 0, pszTargetName,
625 strlen(pszTargetName)+1, NULL, 0);
626 target = HeapAlloc(GetProcessHeap(), 0, target_size *
627 sizeof(SEC_WCHAR));
628 MultiByteToWideChar(CP_ACP, 0, pszTargetName, strlen(pszTargetName)+1,
629 target, target_size);
632 ret = ntlm_InitializeSecurityContextW(phCredential, phContext, target,
633 fContextReq, Reserved1, TargetDataRep, pInput, Reserved2,
634 phNewContext, pOutput, pfContextAttr, ptsExpiry);
636 HeapFree(GetProcessHeap(), 0, target);
638 else
640 ret = SEC_E_INVALID_HANDLE;
642 return ret;
645 /***********************************************************************
646 * AcceptSecurityContext
648 static SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(
649 PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput,
650 ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext,
651 PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
653 SECURITY_STATUS ret;
655 TRACE("%p %p %p %ld %ld %p %p %p %p\n", phCredential, phContext, pInput,
656 fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr,
657 ptsExpiry);
658 if (phCredential)
660 PNegoHelper helper = (PNegoHelper)phCredential->dwLower;
661 /* Max size of input data is 2010 byte, as that's the maximum size
662 * ntlm_auth will handle*/
663 char *buffer = HeapAlloc(GetProcessHeap(), 0,
664 sizeof(char) * NTLM_MAX_BUF);
665 PBYTE bin = HeapAlloc(GetProcessHeap(),0, sizeof(BYTE) * NTLM_MAX_BUF);
666 int buffer_len, bin_len, max_len = NTLM_MAX_BUF;
667 ULONG ctxt_attr = 0;
669 if(helper->mode != NTLM_SERVER)
671 HeapFree(GetProcessHeap(), 0, buffer);
672 HeapFree(GetProcessHeap(), 0, bin);
673 return SEC_E_INVALID_HANDLE;
676 /* Handle all the flags */
677 if(fContextReq & ISC_REQ_ALLOCATE_MEMORY)
679 FIXME("AcceptSecurityContext(): ISC_REQ_ALLOCATE_MEMORY stub\n");
681 if(fContextReq & ISC_REQ_CONFIDENTIALITY)
683 FIXME("AcceptSecurityContext(): ISC_REQ_CONFIDENTIALITY stub\n");
685 if(fContextReq & ISC_REQ_CONNECTION)
687 /* This is default, so we'll enable it */
688 ctxt_attr |= ISC_RET_CONNECTION;
690 if(fContextReq & ISC_REQ_EXTENDED_ERROR)
692 FIXME("AcceptSecurityContext(): ISC_REQ_EXTENDED_ERROR stub\n");
694 if(fContextReq & ISC_REQ_INTEGRITY)
696 FIXME("AcceptSecurityContext(): ISC_REQ_INTEGRITY stub\n");
698 if(fContextReq & ISC_REQ_MUTUAL_AUTH)
700 FIXME("AcceptSecurityContext(): ISC_REQ_MUTUAL_AUTH stub\n");
702 if(fContextReq & ISC_REQ_REPLAY_DETECT)
704 FIXME("AcceptSecurityContext(): ISC_REQ_REPLAY_DETECT stub\n");
706 if(fContextReq & ISC_REQ_SEQUENCE_DETECT)
708 FIXME("AcceptSecurityContext(): ISC_REQ_SEQUENCE_DETECT stub\n");
710 if(fContextReq & ISC_REQ_STREAM)
712 FIXME("AcceptSecurityContext(): ISC_REQ_STREAM stub\n");
714 /* Done with the flags */
715 if(TargetDataRep == SECURITY_NETWORK_DREP){
716 TRACE("Using SECURITY_NETWORK_DREP\n");
720 if(phContext == NULL)
722 /* This is the first call to AcceptSecurityHandle */
723 if(pInput == NULL)
725 HeapFree(GetProcessHeap(), 0, buffer);
726 HeapFree(GetProcessHeap(), 0, bin);
727 return SEC_E_INCOMPLETE_MESSAGE;
730 if(pInput->cBuffers < 1)
732 HeapFree(GetProcessHeap(), 0, buffer);
733 HeapFree(GetProcessHeap(), 0, bin);
734 return SEC_E_INCOMPLETE_MESSAGE;
737 if(pInput->pBuffers[0].cbBuffer > max_len)
739 HeapFree(GetProcessHeap(), 0, buffer);
740 HeapFree(GetProcessHeap(), 0, bin);
741 return SEC_E_INVALID_TOKEN;
743 else
744 bin_len = pInput->pBuffers[0].cbBuffer;
746 /* This is the YR request from the client, encode to base64 */
748 memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len);
750 lstrcpynA(buffer, "YR ", max_len-1);
752 if((ret = encodeBase64(bin, bin_len, buffer+3, max_len-3,
753 &buffer_len)) != SEC_E_OK)
755 HeapFree(GetProcessHeap(), 0, buffer);
756 HeapFree(GetProcessHeap(), 0, bin);
757 return ret;
760 TRACE("Client sent: %s\n", debugstr_a(buffer));
762 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) !=
763 SEC_E_OK)
765 HeapFree(GetProcessHeap(), 0, buffer);
766 HeapFree(GetProcessHeap(), 0, bin);
767 return ret;
770 TRACE("Reply from ntlm_auth: %s\n", debugstr_a(buffer));
771 /* The expected answer is TT <base64 blob> */
773 if(strncmp(buffer, "TT ", 3) != 0)
775 HeapFree(GetProcessHeap(), 0, buffer);
776 HeapFree(GetProcessHeap(), 0, bin);
777 return SEC_E_INVALID_TOKEN;
780 if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len,
781 &bin_len)) != SEC_E_OK)
783 HeapFree(GetProcessHeap(), 0, buffer);
784 HeapFree(GetProcessHeap(), 0, bin);
785 return ret;
788 /* send this to the client */
789 if(pOutput == NULL)
791 HeapFree(GetProcessHeap(), 0, buffer);
792 HeapFree(GetProcessHeap(), 0, bin);
793 return SEC_E_INSUFFICIENT_MEMORY;
796 if(pOutput->cBuffers < 1)
798 HeapFree(GetProcessHeap(), 0, buffer);
799 HeapFree(GetProcessHeap(), 0, bin);
800 return SEC_E_INSUFFICIENT_MEMORY;
803 pOutput->pBuffers[0].cbBuffer = bin_len;
804 pOutput->pBuffers[0].BufferType = SECBUFFER_DATA;
805 memcpy(pOutput->pBuffers[0].pvBuffer, bin, bin_len);
806 ret = SEC_I_CONTINUE_NEEDED;
809 else
811 /* we expect a KK request from client */
812 if(pInput == NULL)
814 HeapFree(GetProcessHeap(), 0, buffer);
815 HeapFree(GetProcessHeap(), 0, bin);
816 return SEC_E_INCOMPLETE_MESSAGE;
819 if(pInput->cBuffers < 1)
821 HeapFree(GetProcessHeap(), 0, buffer);
822 HeapFree(GetProcessHeap(), 0, bin);
823 return SEC_E_INCOMPLETE_MESSAGE;
826 if(pInput->pBuffers[0].cbBuffer > max_len)
828 HeapFree(GetProcessHeap(), 0, buffer);
829 HeapFree(GetProcessHeap(), 0, bin);
830 return SEC_E_INVALID_TOKEN;
832 else
833 bin_len = pInput->pBuffers[0].cbBuffer;
835 memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len);
837 lstrcpynA(buffer, "KK ", max_len-1);
839 if((ret = encodeBase64(bin, bin_len, buffer+3, max_len-3,
840 &buffer_len)) != SEC_E_OK)
842 HeapFree(GetProcessHeap(), 0, buffer);
843 HeapFree(GetProcessHeap(), 0, bin);
844 return ret;
847 TRACE("Client sent: %s\n", debugstr_a(buffer));
849 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) !=
850 SEC_E_OK)
852 HeapFree(GetProcessHeap(), 0, buffer);
853 HeapFree(GetProcessHeap(), 0, bin);
854 return ret;
857 TRACE("Reply from ntlm_auth: %s\n", debugstr_a(buffer));
859 if(strncmp(buffer, "AF ", 3) != 0)
861 if(strncmp(buffer, "NA ", 3) == 0)
863 HeapFree(GetProcessHeap(), 0, buffer);
864 HeapFree(GetProcessHeap(), 0, bin);
865 return SEC_E_LOGON_DENIED;
867 else
869 HeapFree(GetProcessHeap(), 0, buffer);
870 HeapFree(GetProcessHeap(), 0, bin);
871 return SEC_E_INVALID_TOKEN;
875 ret = SEC_E_OK;
878 phNewContext->dwUpper = ctxt_attr;
879 phNewContext->dwLower = ret;
880 HeapFree(GetProcessHeap(), 0, buffer);
881 HeapFree(GetProcessHeap(), 0, bin);
884 else
886 ret = SEC_E_INVALID_HANDLE;
888 return ret;
891 /***********************************************************************
892 * CompleteAuthToken
894 static SECURITY_STATUS SEC_ENTRY ntlm_CompleteAuthToken(PCtxtHandle phContext,
895 PSecBufferDesc pToken)
897 SECURITY_STATUS ret;
899 TRACE("%p %p\n", phContext, pToken);
900 if (phContext)
902 ret = SEC_E_UNSUPPORTED_FUNCTION;
904 else
906 ret = SEC_E_INVALID_HANDLE;
908 return ret;
911 /***********************************************************************
912 * DeleteSecurityContext
914 static SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext)
916 SECURITY_STATUS ret;
918 TRACE("%p\n", phContext);
919 if (phContext)
921 phContext->dwUpper = 0;
922 phContext->dwLower = 0;
923 ret = SEC_E_OK;
925 else
927 ret = SEC_E_INVALID_HANDLE;
929 return ret;
932 /***********************************************************************
933 * QueryContextAttributesW
935 static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext,
936 unsigned long ulAttribute, void *pBuffer)
938 SECURITY_STATUS ret;
940 /* FIXME: From reading wrapper.h, I think the dwUpper part of a context is
941 * the SecurePackage part and the dwLower part is the actual context
942 * handle. It should be easy to extract the context attributes from that.
944 TRACE("%p %ld %p\n", phContext, ulAttribute, pBuffer);
945 if (phContext)
947 ret = SEC_E_UNSUPPORTED_FUNCTION;
949 else
951 ret = SEC_E_INVALID_HANDLE;
953 return ret;
956 /***********************************************************************
957 * QueryContextAttributesA
959 static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(PCtxtHandle phContext,
960 unsigned long ulAttribute, void *pBuffer)
962 return ntlm_QueryContextAttributesW(phContext, ulAttribute, pBuffer);
965 /***********************************************************************
966 * ImpersonateSecurityContext
968 static SECURITY_STATUS SEC_ENTRY ntlm_ImpersonateSecurityContext(PCtxtHandle phContext)
970 SECURITY_STATUS ret;
972 TRACE("%p\n", phContext);
973 if (phContext)
975 ret = SEC_E_UNSUPPORTED_FUNCTION;
977 else
979 ret = SEC_E_INVALID_HANDLE;
981 return ret;
984 /***********************************************************************
985 * RevertSecurityContext
987 static SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(PCtxtHandle phContext)
989 SECURITY_STATUS ret;
991 TRACE("%p\n", phContext);
992 if (phContext)
994 ret = SEC_E_UNSUPPORTED_FUNCTION;
996 else
998 ret = SEC_E_INVALID_HANDLE;
1000 return ret;
1003 /***********************************************************************
1004 * MakeSignature
1006 static SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext, ULONG fQOP,
1007 PSecBufferDesc pMessage, ULONG MessageSeqNo)
1009 SECURITY_STATUS ret;
1011 TRACE("%p %ld %p %ld\n", phContext, fQOP, pMessage, MessageSeqNo);
1012 if (phContext)
1014 ret = SEC_E_UNSUPPORTED_FUNCTION;
1016 else
1018 ret = SEC_E_INVALID_HANDLE;
1020 return ret;
1023 /***********************************************************************
1024 * VerifySignature
1026 static SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle phContext,
1027 PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
1029 SECURITY_STATUS ret;
1031 TRACE("%p %p %ld %p\n", phContext, pMessage, MessageSeqNo, pfQOP);
1032 if (phContext)
1034 ret = SEC_E_UNSUPPORTED_FUNCTION;
1036 else
1038 ret = SEC_E_INVALID_HANDLE;
1040 return ret;
1043 /***********************************************************************
1044 * FreeCredentialsHandle
1046 static SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(
1047 PCredHandle phCredential)
1049 SECURITY_STATUS ret;
1051 if(phCredential){
1052 PNegoHelper helper = (PNegoHelper) phCredential->dwLower;
1053 phCredential->dwUpper = 0;
1054 phCredential->dwLower = 0;
1055 cleanup_helper(helper);
1056 ret = SEC_E_OK;
1058 else
1059 ret = SEC_E_OK;
1061 return ret;
1064 /***********************************************************************
1065 * EncryptMessage
1067 static SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext,
1068 ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
1070 TRACE("%p %ld %p %ld stub\n", phContext, fQOP, pMessage, MessageSeqNo);
1072 if(!phContext)
1073 return SEC_E_INVALID_HANDLE;
1075 return SEC_E_UNSUPPORTED_FUNCTION;
1078 /***********************************************************************
1079 * DecryptMessage
1081 static SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext,
1082 PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
1084 TRACE("%p %p %ld %p stub\n", phContext, pMessage, MessageSeqNo, pfQOP);
1086 if(!phContext)
1087 return SEC_E_INVALID_HANDLE;
1089 return SEC_E_UNSUPPORTED_FUNCTION;
1092 static SecurityFunctionTableA ntlmTableA = {
1094 NULL, /* EnumerateSecurityPackagesA */
1095 ntlm_QueryCredentialsAttributesA, /* QueryCredentialsAttributesA */
1096 ntlm_AcquireCredentialsHandleA, /* AcquireCredentialsHandleA */
1097 ntlm_FreeCredentialsHandle, /* FreeCredentialsHandle */
1098 NULL, /* Reserved2 */
1099 ntlm_InitializeSecurityContextA, /* InitializeSecurityContextA */
1100 ntlm_AcceptSecurityContext, /* AcceptSecurityContext */
1101 ntlm_CompleteAuthToken, /* CompleteAuthToken */
1102 ntlm_DeleteSecurityContext, /* DeleteSecurityContext */
1103 NULL, /* ApplyControlToken */
1104 ntlm_QueryContextAttributesA, /* QueryContextAttributesA */
1105 ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
1106 ntlm_RevertSecurityContext, /* RevertSecurityContext */
1107 ntlm_MakeSignature, /* MakeSignature */
1108 ntlm_VerifySignature, /* VerifySignature */
1109 FreeContextBuffer, /* FreeContextBuffer */
1110 NULL, /* QuerySecurityPackageInfoA */
1111 NULL, /* Reserved3 */
1112 NULL, /* Reserved4 */
1113 NULL, /* ExportSecurityContext */
1114 NULL, /* ImportSecurityContextA */
1115 NULL, /* AddCredentialsA */
1116 NULL, /* Reserved8 */
1117 NULL, /* QuerySecurityContextToken */
1118 ntlm_EncryptMessage, /* EncryptMessage */
1119 ntlm_DecryptMessage, /* DecryptMessage */
1120 NULL, /* SetContextAttributesA */
1123 static SecurityFunctionTableW ntlmTableW = {
1125 NULL, /* EnumerateSecurityPackagesW */
1126 ntlm_QueryCredentialsAttributesW, /* QueryCredentialsAttributesW */
1127 ntlm_AcquireCredentialsHandleW, /* AcquireCredentialsHandleW */
1128 ntlm_FreeCredentialsHandle, /* FreeCredentialsHandle */
1129 NULL, /* Reserved2 */
1130 ntlm_InitializeSecurityContextW, /* InitializeSecurityContextW */
1131 ntlm_AcceptSecurityContext, /* AcceptSecurityContext */
1132 ntlm_CompleteAuthToken, /* CompleteAuthToken */
1133 ntlm_DeleteSecurityContext, /* DeleteSecurityContext */
1134 NULL, /* ApplyControlToken */
1135 ntlm_QueryContextAttributesW, /* QueryContextAttributesW */
1136 ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
1137 ntlm_RevertSecurityContext, /* RevertSecurityContext */
1138 ntlm_MakeSignature, /* MakeSignature */
1139 ntlm_VerifySignature, /* VerifySignature */
1140 FreeContextBuffer, /* FreeContextBuffer */
1141 NULL, /* QuerySecurityPackageInfoW */
1142 NULL, /* Reserved3 */
1143 NULL, /* Reserved4 */
1144 NULL, /* ExportSecurityContext */
1145 NULL, /* ImportSecurityContextW */
1146 NULL, /* AddCredentialsW */
1147 NULL, /* Reserved8 */
1148 NULL, /* QuerySecurityContextToken */
1149 ntlm_EncryptMessage, /* EncryptMessage */
1150 ntlm_DecryptMessage, /* DecryptMessage */
1151 NULL, /* SetContextAttributesW */
1154 #define NTLM_COMMENT \
1155 { 'N', 'T', 'L', 'M', ' ', \
1156 'S', 'e', 'c', 'u', 'r', 'i', 't', 'y', ' ', \
1157 'P', 'a', 'c', 'k', 'a', 'g', 'e', 0}
1159 static CHAR ntlm_comment_A[] = NTLM_COMMENT;
1160 static WCHAR ntlm_comment_W[] = NTLM_COMMENT;
1162 #define NTLM_NAME {'N', 'T', 'L', 'M', 0}
1164 static char ntlm_name_A[] = NTLM_NAME;
1165 static WCHAR ntlm_name_W[] = NTLM_NAME;
1167 /* According to Windows, NTLM has the following capabilities. */
1168 #define CAPS ( \
1169 SECPKG_FLAG_INTEGRITY | \
1170 SECPKG_FLAG_PRIVACY | \
1171 SECPKG_FLAG_TOKEN_ONLY | \
1172 SECPKG_FLAG_CONNECTION | \
1173 SECPKG_FLAG_MULTI_REQUIRED | \
1174 SECPKG_FLAG_IMPERSONATION | \
1175 SECPKG_FLAG_ACCEPT_WIN32_NAME | \
1176 SECPKG_FLAG_READONLY_WITH_CHECKSUM)
1178 static const SecPkgInfoW infoW = {
1179 CAPS,
1181 RPC_C_AUTHN_WINNT,
1182 NTLM_MAX_BUF,
1183 ntlm_name_W,
1184 ntlm_comment_W
1187 static const SecPkgInfoA infoA = {
1188 CAPS,
1190 RPC_C_AUTHN_WINNT,
1191 NTLM_MAX_BUF,
1192 ntlm_name_A,
1193 ntlm_comment_A
1196 void SECUR32_initNTLMSP(void)
1198 SECURITY_STATUS ret;
1199 PNegoHelper helper;
1201 SEC_CHAR *args[] = {
1202 "ntlm_auth",
1203 "--version",
1204 NULL };
1206 if((ret = fork_helper(&helper, "ntlm_auth", args)) != SEC_E_OK)
1208 /* Cheat and allocate a helper anyway, so cleanup later will work. */
1209 helper = HeapAlloc(GetProcessHeap,0, sizeof(PNegoHelper));
1210 helper->version = -1;
1212 else
1213 check_version(helper);
1215 if(helper->version > 2)
1217 SecureProvider *provider = SECUR32_addProvider(&ntlmTableA, &ntlmTableW, NULL);
1218 SECUR32_addPackages(provider, 1L, &infoA, &infoW);
1220 cleanup_helper(helper);