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