ole32: Try to retrieve messages that are COM calls first.
[wine] / dlls / secur32 / ntlm.c
1 /*
2  * Copyright 2005 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * This file implements the NTLM security provider.
19  */
20
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"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
33
34 #define NTLM_MAX_BUF 2010
35
36 static char ntlm_name_A[] = "NTLM";
37 static WCHAR ntlm_name_W[] = {'N', 'T', 'L', 'M', 0};
38
39
40 /***********************************************************************
41  *              QueryCredentialsAttributesA
42  */
43 static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesA(
44         PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
45 {
46     SECURITY_STATUS ret;
47
48     TRACE("(%p, %ld, %p)\n", phCredential, ulAttribute, pBuffer);
49
50     if(ulAttribute == SECPKG_ATTR_NAMES)
51     {
52         FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
53         ret = SEC_E_UNSUPPORTED_FUNCTION;
54     }
55     else
56         ret = SEC_E_UNSUPPORTED_FUNCTION;
57     
58     return ret;
59 }
60
61 /***********************************************************************
62  *              QueryCredentialsAttributesW
63  */
64 static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesW(
65         PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
66 {
67     SECURITY_STATUS ret;
68
69     TRACE("(%p, %ld, %p)\n", phCredential, ulAttribute, pBuffer);
70
71     if(ulAttribute == SECPKG_ATTR_NAMES)
72     {
73         FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
74         ret = SEC_E_UNSUPPORTED_FUNCTION;
75     }
76     else
77         ret = SEC_E_UNSUPPORTED_FUNCTION;
78     
79     return ret;
80 }
81
82 /***********************************************************************
83  *              AcquireCredentialsHandleW
84  */
85 static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(
86  SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse,
87  PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
88  PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
89 {
90     SECURITY_STATUS ret;
91     PNegoHelper helper = NULL;
92     
93     SEC_CHAR *client_user_arg = NULL;
94     SEC_CHAR *client_domain_arg = NULL;
95     SEC_WCHAR *username = NULL, *domain = NULL;
96     
97     SEC_CHAR *client_argv[5];
98     SEC_CHAR *server_argv[] = { "ntlm_auth",
99         "--helper-protocol=squid-2.5-ntlmssp",
100         NULL };
101
102     TRACE("(%s, %s, 0x%08lx, %p, %p, %p, %p, %p, %p)\n",
103      debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse,
104      pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
105
106
107     switch(fCredentialUse)
108     {
109         case SECPKG_CRED_INBOUND:
110             if( (ret = fork_helper(&helper, "ntlm_auth", server_argv)) !=
111                     SEC_E_OK)
112             {
113                 phCredential = NULL;
114                 break;
115             }
116             else
117             {
118                 helper->mode = NTLM_SERVER;
119                 phCredential->dwUpper = fCredentialUse;
120                 phCredential->dwLower = (DWORD)helper;
121             }
122             ret = SEC_E_OK;
123             break;
124         case SECPKG_CRED_OUTBOUND:
125             {
126                 static const char username_arg[] = "--username=";
127                 static const char domain_arg[] = "--domain=";
128                 int unixcp_size;
129
130                 if(pAuthData == NULL)
131                 {
132                     LPWKSTA_USER_INFO_1 ui = NULL;
133                     NET_API_STATUS status;
134
135                     if((status = NetWkstaUserGetInfo(NULL, 1, (LPBYTE *)&ui)) !=
136                             NERR_Success)
137                     {
138                         ret = SEC_E_NO_CREDENTIALS;
139                         phCredential = NULL;
140                         break;
141                     }
142                     
143                     if(ui != NULL)
144                     {
145                         username = HeapAlloc(GetProcessHeap(), 0, 
146                                 (lstrlenW(ui->wkui1_username)+1) * 
147                                 sizeof(SEC_WCHAR));
148                         lstrcpyW(username, ui->wkui1_username);
149                         
150                         /* same for the domain */
151                         domain = HeapAlloc(GetProcessHeap(), 0, 
152                                 (lstrlenW(ui->wkui1_logon_domain)+1) * 
153                                 sizeof(SEC_WCHAR));
154                         lstrcpyW(domain, ui->wkui1_logon_domain);
155                         NetApiBufferFree(ui);
156                     }
157                     else
158                     {
159                         ret = SEC_E_NO_CREDENTIALS;
160                         phCredential = NULL;
161                         break;
162                     }
163                     
164                                     
165                 }
166                 else
167                 {
168                     PSEC_WINNT_AUTH_IDENTITY_W auth_data = 
169                         (PSEC_WINNT_AUTH_IDENTITY_W)pAuthData;
170
171                     if(auth_data->UserLength != 0)
172                     {
173                         /* Get username and domain from pAuthData */
174                         username = HeapAlloc(GetProcessHeap(), 0, 
175                                 (auth_data->UserLength + 1) * sizeof(SEC_WCHAR));
176                         lstrcpyW(username, auth_data->User);
177                     }
178                     else
179                     {
180                         ret = SEC_E_NO_CREDENTIALS;
181                         phCredential = NULL;
182                         break;
183                     }
184                     if(auth_data->DomainLength != 0)
185                     {
186                         domain = HeapAlloc(GetProcessHeap(), 0,
187                                 (auth_data->DomainLength + 1) * sizeof(SEC_WCHAR));
188                         lstrcpyW(domain, auth_data->Domain);
189
190                     }
191                     else
192                     {
193                         ret = SEC_E_NO_CREDENTIALS;
194                         phCredential = NULL;
195                         break;
196                     }
197
198                 }
199                 TRACE("Username is %s\n", debugstr_w(username));
200                 unixcp_size =  WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
201                         username, -1, NULL, 0, NULL, NULL) + sizeof(username_arg);
202                 client_user_arg = HeapAlloc(GetProcessHeap(), 0, unixcp_size);
203                 lstrcpyA(client_user_arg, username_arg);
204                 WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, username, -1,
205                         client_user_arg + sizeof(username_arg) - 1, 
206                         unixcp_size - sizeof(username_arg) + 1, NULL, NULL);
207
208                 TRACE("Domain name is %s\n", debugstr_w(domain));
209                 unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
210                         domain, -1, NULL, 0,  NULL, NULL) + sizeof(domain_arg);
211                 client_domain_arg = HeapAlloc(GetProcessHeap(), 0, unixcp_size);
212                 lstrcpyA(client_domain_arg, domain_arg);
213                 WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, domain,
214                         -1, client_domain_arg + sizeof(domain_arg) - 1, 
215                         unixcp_size - sizeof(domain) + 1, NULL, NULL);
216
217                 client_argv[0] = "ntlm_auth";
218                 client_argv[1] = "--helper-protocol=ntlmssp-client-1";
219                 client_argv[2] = client_user_arg;
220                 client_argv[3] = client_domain_arg;
221                 client_argv[4] = NULL;
222
223                 if((ret = fork_helper(&helper, "ntlm_auth", client_argv)) != 
224                         SEC_E_OK)
225                 {
226                     phCredential = NULL;
227                     break;
228                 }
229                 else
230                 {
231                     helper->mode = NTLM_CLIENT;
232
233                     if(pAuthData != NULL)
234                     {
235                         PSEC_WINNT_AUTH_IDENTITY_W auth_data = 
236                            (PSEC_WINNT_AUTH_IDENTITY_W)pAuthData;
237
238                         if(auth_data->PasswordLength != 0)
239                         {
240                             helper->pwlen = WideCharToMultiByte(CP_UNIXCP, 
241                                 WC_NO_BEST_FIT_CHARS, auth_data->Password, 
242                                 auth_data->PasswordLength+1, NULL, 0, NULL, NULL);
243                         
244                             helper->password = HeapAlloc(GetProcessHeap(), 0, 
245                                     helper->pwlen);
246
247                             WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
248                                 auth_data->Password, auth_data->PasswordLength+1,
249                                 helper->password, helper->pwlen, NULL, NULL);
250                         }
251                     }
252            
253                     phCredential->dwUpper = fCredentialUse;
254                     phCredential->dwLower = (DWORD)helper;
255                     TRACE("ACH phCredential->dwUpper: 0x%08lx, dwLower: 0x%08lx\n",
256                             phCredential->dwUpper, phCredential->dwLower);
257                 }
258                 ret = SEC_E_OK;
259                 break;
260             }
261         case SECPKG_CRED_BOTH:
262             FIXME("AcquireCredentialsHandle: SECPKG_CRED_BOTH stub\n");
263             ret = SEC_E_UNSUPPORTED_FUNCTION;
264             phCredential = NULL;
265             break;
266         default:
267             phCredential = NULL;
268             ret = SEC_E_UNKNOWN_CREDENTIALS;
269     }
270     
271
272     HeapFree(GetProcessHeap(), 0, client_user_arg);
273     HeapFree(GetProcessHeap(), 0, client_domain_arg);
274     HeapFree(GetProcessHeap(), 0, username);
275     HeapFree(GetProcessHeap(), 0, domain);
276
277     return ret;
278 }
279
280 /***********************************************************************
281  *              AcquireCredentialsHandleA
282  */
283 static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA(
284  SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse,
285  PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
286  PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
287 {
288     SECURITY_STATUS ret;
289     int user_sizeW, domain_sizeW, passwd_sizeW;
290     
291     SEC_WCHAR *user = NULL, *domain = NULL, *passwd = NULL, *package = NULL;
292     
293     PSEC_WINNT_AUTH_IDENTITY_W pAuthDataW = NULL;
294     PSEC_WINNT_AUTH_IDENTITY_A identity  = NULL;
295
296     TRACE("(%s, %s, 0x%08lx, %p, %p, %p, %p, %p, %p)\n",
297      debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse,
298      pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
299     
300     if(pszPackage != NULL)
301     {
302         int package_sizeW = MultiByteToWideChar(CP_ACP, 0, pszPackage, -1,
303                 NULL, 0);
304
305         package = HeapAlloc(GetProcessHeap(), 0, package_sizeW * 
306                 sizeof(SEC_WCHAR));
307         MultiByteToWideChar(CP_ACP, 0, pszPackage, -1, package, package_sizeW);
308     }
309
310     
311     if(pAuthData != NULL)
312     {
313         identity = (PSEC_WINNT_AUTH_IDENTITY_A)pAuthData;
314         
315         if(identity->Flags == SEC_WINNT_AUTH_IDENTITY_ANSI)
316         {
317             pAuthDataW = HeapAlloc(GetProcessHeap(), 0, 
318                     sizeof(SEC_WINNT_AUTH_IDENTITY_W));
319
320             if(identity->UserLength != 0)
321             {
322                 user_sizeW = MultiByteToWideChar(CP_ACP, 0, 
323                     (LPCSTR)identity->User, identity->UserLength+1, NULL, 0);
324                 user = HeapAlloc(GetProcessHeap(), 0, user_sizeW * 
325                         sizeof(SEC_WCHAR));
326                 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->User, 
327                     identity->UserLength+1, user, user_sizeW);
328             }
329             else
330             {
331                 user_sizeW = 0;
332             }
333              
334             if(identity->DomainLength != 0)
335             {
336                 domain_sizeW = MultiByteToWideChar(CP_ACP, 0, 
337                     (LPCSTR)identity->Domain, identity->DomainLength+1, NULL, 0);
338                 domain = HeapAlloc(GetProcessHeap(), 0, domain_sizeW 
339                     * sizeof(SEC_WCHAR));
340                 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->Domain, 
341                     identity->DomainLength+1, domain, domain_sizeW);
342             }
343             else
344             {
345                 domain_sizeW = 0;
346             }
347
348             if(identity->PasswordLength != 0)
349             {
350                 passwd_sizeW = MultiByteToWideChar(CP_ACP, 0, 
351                     (LPCSTR)identity->Password, identity->PasswordLength+1, 
352                     NULL, 0);
353                 passwd = HeapAlloc(GetProcessHeap(), 0, passwd_sizeW
354                     * sizeof(SEC_WCHAR));
355                 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->Password,
356                     identity->PasswordLength+1, passwd, passwd_sizeW);
357             }
358             else
359             {
360                 passwd_sizeW = 0;
361             }
362             
363             pAuthDataW->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
364             pAuthDataW->User = user;
365             pAuthDataW->UserLength = user_sizeW;
366             pAuthDataW->Domain = domain;
367             pAuthDataW->DomainLength = domain_sizeW;
368             pAuthDataW->Password = passwd;
369             pAuthDataW->PasswordLength = passwd_sizeW;
370         }
371         else
372         {
373             pAuthDataW = (PSEC_WINNT_AUTH_IDENTITY_W)identity;
374         }
375     }       
376     
377     ret = ntlm_AcquireCredentialsHandleW(NULL, package, fCredentialUse, 
378             pLogonID, pAuthDataW, pGetKeyFn, pGetKeyArgument, phCredential,
379             ptsExpiry);
380     
381     HeapFree(GetProcessHeap(), 0, package);
382     HeapFree(GetProcessHeap(), 0, user);
383     HeapFree(GetProcessHeap(), 0, domain);
384     HeapFree(GetProcessHeap(), 0, passwd);
385     if(pAuthDataW != (PSEC_WINNT_AUTH_IDENTITY_W)identity)
386         HeapFree(GetProcessHeap(), 0, pAuthDataW);
387     
388     return ret;
389 }
390
391 /***********************************************************************
392  *              InitializeSecurityContextW
393  */
394 static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
395  PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName, 
396  ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, 
397  PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext, 
398  PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
399 {
400     SECURITY_STATUS ret;
401
402     TRACE("%p %p %s %ld %ld %ld %p %ld %p %p %p %p\n", phCredential, phContext,
403      debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
404      Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
405
406     if(phCredential){
407         /* As the server side of sspi never calls this, make sure that 
408          * the handler is a client handler.
409          */
410         PNegoHelper helper = (PNegoHelper)phCredential->dwLower;
411         ULONG ctxt_attr = 0;
412         if(helper->mode == NTLM_CLIENT)
413         {
414             /****************************************
415              * When communicating with the client, there can be the 
416              * following reply packets:
417              * YR <base64 blob>         should be sent to the server
418              * PW                       should be sent back to helper with
419              *                          base64 encoded password
420              * AF <base64 blob>         client is done, blob should be 
421              *                          sent to server with KK prefixed
422              * BH <char reason>         something broke
423              */
424             BOOL first = FALSE;
425             /* The squid cache size is 2010 chars, and that's what ntlm_auth uses */
426             char* buffer = HeapAlloc(GetProcessHeap(), 0, 
427                     sizeof(char) * NTLM_MAX_BUF);
428             PBYTE bin = HeapAlloc(GetProcessHeap(), 0, sizeof(BYTE) * 
429                     NTLM_MAX_BUF);
430             int buffer_len, bin_len, max_len = NTLM_MAX_BUF;
431             
432             if((phContext == NULL) && (pInput == NULL))
433                 first = TRUE;
434             if (pszTargetName)
435             {
436                 TRACE("According to a MS whitepaper pszTargetName is ignored.\n");
437             }
438             /* Handle all the flags */
439             if(fContextReq & ISC_REQ_ALLOCATE_MEMORY)
440             {
441                 FIXME("InitializeSecurityContext(): ISC_REQ_ALLOCATE_MEMORY stub\n");
442             }
443             if(fContextReq & ISC_REQ_CONFIDENTIALITY)
444             {
445                 FIXME("InitializeSecurityContext(): ISC_REQ_CONFIDENTIALITY stub\n");
446             }
447             if(fContextReq & ISC_REQ_CONNECTION)
448             {
449                 /* This is default, so we'll enable it */
450                 ctxt_attr |= ISC_RET_CONNECTION;
451             }
452             if(fContextReq & ISC_REQ_EXTENDED_ERROR)
453             {
454                 FIXME("InitializeSecurityContext(): ISC_REQ_EXTENDED_ERROR stub\n");
455             }
456             if(fContextReq & ISC_REQ_INTEGRITY)
457             {
458                 FIXME("InitializeSecurityContext(): ISC_REQ_INTEGRITY stub\n");
459             }
460             if(fContextReq & ISC_REQ_MUTUAL_AUTH)
461             {
462                 FIXME("InitializeSecurityContext(): ISC_REQ_MUTUAL_AUTH stub\n");
463             }
464             if(fContextReq & ISC_REQ_REPLAY_DETECT)
465             {
466                 FIXME("InitializeSecurityContext(): ISC_REQ_REPLAY_DETECT stub\n");
467             }
468             if(fContextReq & ISC_REQ_SEQUENCE_DETECT)
469             {
470                 FIXME("InitializeSecurityContext(): ISC_REQ_SEQUENCE_DETECT stub\n");
471             }
472             if(fContextReq & ISC_REQ_STREAM)
473             {
474                 FIXME("InitializeSecurityContext(): ISC_REQ_STREAM stub\n");
475             }
476             /* Done with the flags */
477             if(TargetDataRep == SECURITY_NETWORK_DREP){
478                 FIXME("Don't know how to do SECURITY_NETWORK_DREP\n");
479                 HeapFree(GetProcessHeap(), 0, buffer);
480                 HeapFree(GetProcessHeap(), 0, bin);
481                 return SEC_E_UNSUPPORTED_FUNCTION;
482             }
483
484             if(first)
485             {
486                 TRACE("First time in ISC()\n");
487                 /* Request a challenge request from ntlm_auth */
488                 if(helper->password == NULL)
489                 {
490                     FIXME("Using empty password for now.\n");
491                     lstrcpynA(buffer, "PW AA==", max_len-1);
492                 }
493                 else
494                 {
495                     lstrcpynA(buffer, "PW ", max_len-1);
496                     if((ret = encodeBase64((unsigned char*)helper->password, 
497                                 helper->pwlen-2, buffer+3,
498                                 max_len-3, &buffer_len)) != SEC_E_OK)
499                     {
500                         TRACE("Deleting password!\n");
501                         memset(helper->password, 0, helper->pwlen-2);
502                         HeapFree(GetProcessHeap(), 0, helper->password);
503                         HeapFree(GetProcessHeap(), 0, buffer);
504                         HeapFree(GetProcessHeap(), 0, bin);
505                         return ret;
506                     }
507                                     
508                 }
509
510                 TRACE("Sending to helper: %s\n", debugstr_a(buffer));
511                 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != 
512                     SEC_E_OK)
513                 {
514                     HeapFree(GetProcessHeap(), 0, buffer);
515                     HeapFree(GetProcessHeap(), 0, bin);
516                     return ret;
517                 }
518                 TRACE("Helper returned %s\n", debugstr_a(buffer));
519                 lstrcpynA(buffer, "YR", max_len-1);
520
521                 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) !=
522                         SEC_E_OK)
523                 {
524                     HeapFree(GetProcessHeap(), 0, buffer);
525                     HeapFree(GetProcessHeap(), 0, bin);
526                     return ret;
527                 }
528
529                 TRACE("%s\n", buffer);
530                  
531                 if(strncmp(buffer, "YR ", 3) != 0)
532                 {
533                     
534                     /* Something borked */
535                     TRACE("Helper returned %c%c\n", buffer[0], buffer[1]);
536                     HeapFree(GetProcessHeap(), 0, buffer);
537                     HeapFree(GetProcessHeap(), 0, bin);
538                     return SEC_E_INTERNAL_ERROR;
539                 }
540                 if((ret = decodeBase64(buffer+3, buffer_len-3, bin, 
541                                 max_len-1, &bin_len)) != SEC_E_OK)
542                 {
543                     HeapFree(GetProcessHeap(), 0, buffer);
544                     HeapFree(GetProcessHeap(), 0, bin);
545                     return ret;
546                 }
547                 
548                 /* put the decoded client blob into the out buffer */
549                 if(pOutput == NULL){
550                     TRACE("pOutput is NULL\n");
551                     HeapFree(GetProcessHeap(), 0, buffer);
552                     HeapFree(GetProcessHeap(), 0, bin);
553                     return SEC_E_INSUFFICIENT_MEMORY;
554                 }
555
556                 if(pOutput->cBuffers < 1)
557                 {
558                     TRACE("pOutput->cBuffers is %ld\n", pOutput->cBuffers);
559                     HeapFree(GetProcessHeap(), 0, buffer);
560                     HeapFree(GetProcessHeap(), 0, bin);
561                     return SEC_E_INSUFFICIENT_MEMORY;
562                 }
563                 pOutput->pBuffers[0].cbBuffer = bin_len;
564                 pOutput->pBuffers[0].BufferType = SECBUFFER_DATA;
565                 memcpy(pOutput->pBuffers[0].pvBuffer, bin, bin_len);
566                 
567                 ret = SEC_I_CONTINUE_NEEDED;
568             }
569             else
570             {
571                 /* handle second call here */
572                 /* encode server data to base64 */
573                 if(pInput == NULL)
574                 {
575                     HeapFree(GetProcessHeap(), 0, buffer);
576                     HeapFree(GetProcessHeap(), 0, bin);
577                     return SEC_E_INCOMPLETE_MESSAGE;
578                 }
579                 
580                 if(pInput->cBuffers < 1)
581                 {
582                     HeapFree(GetProcessHeap(), 0, buffer);
583                     HeapFree(GetProcessHeap(), 0, bin);
584                     return SEC_E_INCOMPLETE_MESSAGE;
585                 }
586
587                 if(pInput->pBuffers[0].cbBuffer > max_len)
588                 {
589                     TRACE("pInput->pBuffers[0].cbBuffer is: %ld\n", 
590                             pInput->pBuffers[0].cbBuffer);
591                     HeapFree(GetProcessHeap(), 0, buffer);
592                     HeapFree(GetProcessHeap(), 0, bin);
593                     return SEC_E_INVALID_TOKEN;
594                 }
595                 else
596                     bin_len = pInput->pBuffers[0].cbBuffer;
597
598                 memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len);
599
600                 lstrcpynA(buffer, "TT ", max_len-1);
601
602                 if((ret = encodeBase64(bin, bin_len, buffer+3,
603                                 max_len-3, &buffer_len)) != SEC_E_OK)
604                 {
605                     HeapFree(GetProcessHeap(), 0, buffer);
606                     HeapFree(GetProcessHeap(), 0, bin);
607                     return ret;
608                 }
609
610                 TRACE("Server sent: %s\n", debugstr_a(buffer));
611
612                 /* send TT base64 blob to ntlm_auth */
613                 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) !=
614                         SEC_E_OK)
615                 {
616                     HeapFree(GetProcessHeap(), 0, buffer);
617                     HeapFree(GetProcessHeap(), 0, bin);
618                     return ret;
619                 }
620                 
621                 TRACE("Helper replied: %s\n", debugstr_a(buffer));
622                                 
623                 if( (strncmp(buffer, "KK ", 3) != 0) && 
624                         (strncmp(buffer, "AF ", 3) !=0))
625                 {
626                     TRACE("Helper returned %c%c\n", buffer[0], buffer[1]);
627                     HeapFree(GetProcessHeap(), 0, buffer);
628                     HeapFree(GetProcessHeap(), 0, bin);
629                     return SEC_E_INVALID_TOKEN;
630                 }
631
632                 /* decode the blob and send it to server */
633                 if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len, 
634                                 &bin_len)) != SEC_E_OK)
635                 {
636                     HeapFree(GetProcessHeap(), 0, buffer);
637                     HeapFree(GetProcessHeap(), 0, bin);
638                     return ret;
639                 }
640
641                 if(pOutput == NULL)
642                 {
643                     HeapFree(GetProcessHeap(), 0, buffer);
644                     HeapFree(GetProcessHeap(), 0, bin);
645                     return SEC_E_INSUFFICIENT_MEMORY;
646                 }
647
648                 if(pOutput->cBuffers < 1)
649                 {
650                     HeapFree(GetProcessHeap(), 0, buffer);
651                     HeapFree(GetProcessHeap(), 0, bin);
652                     return SEC_E_INSUFFICIENT_MEMORY;
653                 }
654
655                 pOutput->pBuffers[0].cbBuffer = bin_len;
656                 pOutput->pBuffers[0].BufferType = SECBUFFER_DATA;
657                 memcpy(pOutput->pBuffers[0].pvBuffer, bin, bin_len);
658                 
659                 ret = SEC_E_OK;
660                 phNewContext->dwUpper = ctxt_attr;
661                 phNewContext->dwLower = ret;
662
663             }
664             HeapFree(GetProcessHeap(), 0, buffer);
665             HeapFree(GetProcessHeap(), 0, bin);
666             if(ret != SEC_I_CONTINUE_NEEDED)
667             {
668                 TRACE("Deleting password!\n");
669                 if(helper->password)
670                     memset(helper->password, 0, helper->pwlen-2);
671                 HeapFree(GetProcessHeap(), 0, helper->password);
672             }
673
674         }
675         else
676         {
677             ret = SEC_E_INVALID_HANDLE;
678             TRACE("Helper mode = %d\n", helper->mode);
679         }
680     }
681     else
682     {
683         ret = SEC_E_INVALID_HANDLE;
684     }
685     return ret;
686 }
687
688 /***********************************************************************
689  *              InitializeSecurityContextA
690  */
691 static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA(
692  PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName,
693  ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, 
694  PSecBufferDesc pInput,ULONG Reserved2, PCtxtHandle phNewContext, 
695  PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
696 {
697     SECURITY_STATUS ret;
698
699     TRACE("%p %p %s %ld %ld %ld %p %ld %p %p %p %p\n", phCredential, phContext,
700      debugstr_a(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
701      Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
702     
703     if (phCredential)
704     {
705         SEC_WCHAR *target = NULL;
706         if(pszTargetName != NULL)
707         {
708             int target_size = MultiByteToWideChar(CP_ACP, 0, pszTargetName, 
709                 strlen(pszTargetName)+1, NULL, 0);
710             target = HeapAlloc(GetProcessHeap(), 0, target_size * 
711                     sizeof(SEC_WCHAR));
712             MultiByteToWideChar(CP_ACP, 0, pszTargetName, strlen(pszTargetName)+1,
713                 target, target_size);
714         }
715         
716         ret = ntlm_InitializeSecurityContextW(phCredential, phContext, target, 
717                 fContextReq, Reserved1, TargetDataRep, pInput, Reserved2,
718                 phNewContext, pOutput, pfContextAttr, ptsExpiry);
719         
720         HeapFree(GetProcessHeap(), 0, target);
721     }
722     else
723     {
724         ret = SEC_E_INVALID_HANDLE;
725     }
726     return ret;
727 }
728
729 /***********************************************************************
730  *              AcceptSecurityContext
731  */
732 static SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(
733  PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput,
734  ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext, 
735  PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
736 {
737     SECURITY_STATUS ret;
738
739     TRACE("%p %p %p %ld %ld %p %p %p %p\n", phCredential, phContext, pInput,
740      fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr,
741      ptsExpiry);
742     if (phCredential)
743     {
744         PNegoHelper helper = (PNegoHelper)phCredential->dwLower;
745         /* Max size of input data is 2010 byte, as that's the maximum size 
746          * ntlm_auth will handle*/
747         char *buffer = HeapAlloc(GetProcessHeap(), 0, 
748                 sizeof(char) * NTLM_MAX_BUF);
749         PBYTE bin = HeapAlloc(GetProcessHeap(),0, sizeof(BYTE) * NTLM_MAX_BUF);
750         int buffer_len, bin_len, max_len = NTLM_MAX_BUF;
751         ULONG ctxt_attr = 0;
752
753         if(helper->mode != NTLM_SERVER)
754         {
755             HeapFree(GetProcessHeap(), 0, buffer);
756             HeapFree(GetProcessHeap(), 0, bin);
757             return SEC_E_INVALID_HANDLE;
758         }
759
760         /* Handle all the flags */
761         if(fContextReq & ISC_REQ_ALLOCATE_MEMORY)
762         {
763             FIXME("AcceptSecurityContext(): ISC_REQ_ALLOCATE_MEMORY stub\n");
764         }
765         if(fContextReq & ISC_REQ_CONFIDENTIALITY)
766         {
767             FIXME("AcceptSecurityContext(): ISC_REQ_CONFIDENTIALITY stub\n");
768         }
769         if(fContextReq & ISC_REQ_CONNECTION)
770         {
771             /* This is default, so we'll enable it */
772             ctxt_attr |= ISC_RET_CONNECTION;
773         }
774         if(fContextReq & ISC_REQ_EXTENDED_ERROR)
775         {
776             FIXME("AcceptSecurityContext(): ISC_REQ_EXTENDED_ERROR stub\n");
777         }
778         if(fContextReq & ISC_REQ_INTEGRITY)
779         {
780             FIXME("AcceptSecurityContext(): ISC_REQ_INTEGRITY stub\n");
781         }
782         if(fContextReq & ISC_REQ_MUTUAL_AUTH)
783         {
784             FIXME("AcceptSecurityContext(): ISC_REQ_MUTUAL_AUTH stub\n");
785         }
786         if(fContextReq & ISC_REQ_REPLAY_DETECT)
787         {
788             FIXME("AcceptSecurityContext(): ISC_REQ_REPLAY_DETECT stub\n");
789         }
790         if(fContextReq & ISC_REQ_SEQUENCE_DETECT)
791         {
792             FIXME("AcceptSecurityContext(): ISC_REQ_SEQUENCE_DETECT stub\n");
793         }
794         if(fContextReq & ISC_REQ_STREAM)
795         {
796             FIXME("AcceptSecurityContext(): ISC_REQ_STREAM stub\n");
797         }
798         /* Done with the flags */
799         if(TargetDataRep == SECURITY_NETWORK_DREP){
800             FIXME("Don't know how to do SECURITY_NETWORK_DREP\n");
801             HeapFree(GetProcessHeap(), 0, buffer);
802             HeapFree(GetProcessHeap(), 0, bin);
803             return SEC_E_UNSUPPORTED_FUNCTION;
804         }
805
806         
807         if(phContext == NULL)
808         {
809             /* This is the first call to AcceptSecurityHandle */
810             if(pInput == NULL)
811             {
812                 HeapFree(GetProcessHeap(), 0, buffer);
813                 HeapFree(GetProcessHeap(), 0, bin);
814                 return SEC_E_INCOMPLETE_MESSAGE;
815             }
816             
817             if(pInput->cBuffers < 1)
818             {
819                 HeapFree(GetProcessHeap(), 0, buffer);
820                 HeapFree(GetProcessHeap(), 0, bin);
821                 return SEC_E_INCOMPLETE_MESSAGE;
822             }
823
824             if(pInput->pBuffers[0].cbBuffer > max_len)
825             {
826                 HeapFree(GetProcessHeap(), 0, buffer);
827                 HeapFree(GetProcessHeap(), 0, bin);
828                 return SEC_E_INVALID_TOKEN;
829             }
830             else
831                 bin_len = pInput->pBuffers[0].cbBuffer;
832
833             /* This is the YR request from the client, encode to base64 */
834             
835             memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len);
836
837             lstrcpynA(buffer, "YR ", max_len-1);
838
839             if((ret = encodeBase64(bin, bin_len, buffer+3, max_len-3,
840                         &buffer_len)) != SEC_E_OK)
841             {
842                 HeapFree(GetProcessHeap(), 0, buffer);
843                 HeapFree(GetProcessHeap(), 0, bin);
844                 return ret;
845             }
846             
847             TRACE("Client sent: %s\n", debugstr_a(buffer));
848             
849             if((ret = run_helper(helper, buffer, max_len, &buffer_len)) !=
850                         SEC_E_OK)
851             {
852                 HeapFree(GetProcessHeap(), 0, buffer);
853                 HeapFree(GetProcessHeap(), 0, bin);
854                 return ret;
855             }
856
857             TRACE("Reply from ntlm_auth: %s\n", debugstr_a(buffer));
858             /* The expected answer is TT <base64 blob> */
859
860             if(strncmp(buffer, "TT ", 3) != 0)
861             {
862                 HeapFree(GetProcessHeap(), 0, buffer);
863                 HeapFree(GetProcessHeap(), 0, bin);
864                 return SEC_E_INVALID_TOKEN;
865             }
866
867             if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len,
868                             &bin_len)) != SEC_E_OK)
869             {
870                 HeapFree(GetProcessHeap(), 0, buffer);
871                 HeapFree(GetProcessHeap(), 0, bin);
872                 return ret;
873             }
874             
875             /* send this to the client */
876             if(pOutput == NULL)
877             {
878                 HeapFree(GetProcessHeap(), 0, buffer);
879                 HeapFree(GetProcessHeap(), 0, bin);
880                 return SEC_E_INSUFFICIENT_MEMORY;
881             }
882
883             if(pOutput->cBuffers < 1)
884             {
885                 HeapFree(GetProcessHeap(), 0, buffer);
886                 HeapFree(GetProcessHeap(), 0, bin);
887                 return SEC_E_INSUFFICIENT_MEMORY;
888             }
889
890             pOutput->pBuffers[0].cbBuffer = bin_len;
891             pOutput->pBuffers[0].BufferType = SECBUFFER_DATA;
892             memcpy(pOutput->pBuffers[0].pvBuffer, bin, bin_len);
893             ret = SEC_I_CONTINUE_NEEDED;
894             
895         }
896         else
897         {
898             /* we expect a KK request from client */
899             if(pInput == NULL)
900             {
901                 HeapFree(GetProcessHeap(), 0, buffer);
902                 HeapFree(GetProcessHeap(), 0, bin);
903                 return SEC_E_INCOMPLETE_MESSAGE;
904             }
905             
906             if(pInput->cBuffers < 1)
907             {
908                 HeapFree(GetProcessHeap(), 0, buffer);
909                 HeapFree(GetProcessHeap(), 0, bin);
910                 return SEC_E_INCOMPLETE_MESSAGE;
911             }
912
913             if(pInput->pBuffers[0].cbBuffer > max_len)
914             {
915                 HeapFree(GetProcessHeap(), 0, buffer);
916                 HeapFree(GetProcessHeap(), 0, bin);
917                 return SEC_E_INVALID_TOKEN;
918             }
919             else
920                 bin_len = pInput->pBuffers[0].cbBuffer;
921
922             memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len);
923
924             lstrcpynA(buffer, "KK ", max_len-1);
925
926             if((ret = encodeBase64(bin, bin_len, buffer+3, max_len-3,
927                         &buffer_len)) != SEC_E_OK)
928             {
929                 HeapFree(GetProcessHeap(), 0, buffer);
930                 HeapFree(GetProcessHeap(), 0, bin);
931                 return ret;
932             }
933             
934             TRACE("Client sent: %s\n", debugstr_a(buffer));
935             
936             if((ret = run_helper(helper, buffer, max_len, &buffer_len)) !=
937                         SEC_E_OK)
938             {
939                 HeapFree(GetProcessHeap(), 0, buffer);
940                 HeapFree(GetProcessHeap(), 0, bin);
941                 return ret;
942             }
943
944             TRACE("Reply from ntlm_auth: %s\n", debugstr_a(buffer));
945             
946             if(strncmp(buffer, "AF ", 3) != 0)
947             {
948                 if(strncmp(buffer, "NA ", 3) == 0)
949                 {
950                     HeapFree(GetProcessHeap(), 0, buffer);
951                     HeapFree(GetProcessHeap(), 0, bin);
952                     return SEC_E_LOGON_DENIED;
953                 }
954                 else
955                 {
956                     HeapFree(GetProcessHeap(), 0, buffer);
957                     HeapFree(GetProcessHeap(), 0, bin);
958                     return SEC_E_INVALID_TOKEN;
959                 }
960             }
961             
962             ret = SEC_E_OK;
963         }
964         
965         phNewContext->dwUpper = ctxt_attr;
966         phNewContext->dwLower = ret;
967         HeapFree(GetProcessHeap(), 0, buffer);
968         HeapFree(GetProcessHeap(), 0, bin);
969
970     }
971     else
972     {
973         ret = SEC_E_INVALID_HANDLE;
974     }
975     return ret;
976 }
977
978 /***********************************************************************
979  *              CompleteAuthToken
980  */
981 static SECURITY_STATUS SEC_ENTRY ntlm_CompleteAuthToken(PCtxtHandle phContext,
982  PSecBufferDesc pToken)
983 {
984     SECURITY_STATUS ret;
985
986     TRACE("%p %p\n", phContext, pToken);
987     if (phContext)
988     {
989         ret = SEC_E_UNSUPPORTED_FUNCTION;
990     }
991     else
992     {
993         ret = SEC_E_INVALID_HANDLE;
994     }
995     return ret;
996 }
997
998 /***********************************************************************
999  *              DeleteSecurityContext
1000  */
1001 static SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext)
1002 {
1003     SECURITY_STATUS ret;
1004
1005     TRACE("%p\n", phContext);
1006     if (phContext)
1007     {
1008         phContext->dwUpper = 0;
1009         phContext->dwLower = 0;
1010         ret = SEC_E_OK;
1011     }
1012     else
1013     {
1014         ret = SEC_E_INVALID_HANDLE;
1015     }
1016     return ret;
1017 }
1018
1019 /***********************************************************************
1020  *              QueryContextAttributesW
1021  */
1022 static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext,
1023  unsigned long ulAttribute, void *pBuffer)
1024 {
1025     SECURITY_STATUS ret;
1026
1027     /* FIXME: From reading wrapper.h, I think the dwUpper part of a context is
1028      * the SecurePackage part and the dwLower part is the actual context 
1029      * handle. It should be easy to extract the context attributes from that.
1030      */
1031     TRACE("%p %ld %p\n", phContext, ulAttribute, pBuffer);
1032     if (phContext)
1033     {
1034         ret = SEC_E_UNSUPPORTED_FUNCTION;
1035     }
1036     else
1037     {
1038         ret = SEC_E_INVALID_HANDLE;
1039     }
1040     return ret;
1041 }
1042
1043 /***********************************************************************
1044  *              QueryContextAttributesA
1045  */
1046 static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(PCtxtHandle phContext,
1047  unsigned long ulAttribute, void *pBuffer)
1048 {
1049     return ntlm_QueryContextAttributesW(phContext, ulAttribute, pBuffer);
1050 }
1051
1052 /***********************************************************************
1053  *              ImpersonateSecurityContext
1054  */
1055 static SECURITY_STATUS SEC_ENTRY ntlm_ImpersonateSecurityContext(PCtxtHandle phContext)
1056 {
1057     SECURITY_STATUS ret;
1058
1059     TRACE("%p\n", phContext);
1060     if (phContext)
1061     {
1062         ret = SEC_E_UNSUPPORTED_FUNCTION;
1063     }
1064     else
1065     {
1066         ret = SEC_E_INVALID_HANDLE;
1067     }
1068     return ret;
1069 }
1070
1071 /***********************************************************************
1072  *              RevertSecurityContext
1073  */
1074 static SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(PCtxtHandle phContext)
1075 {
1076     SECURITY_STATUS ret;
1077
1078     TRACE("%p\n", phContext);
1079     if (phContext)
1080     {
1081         ret = SEC_E_UNSUPPORTED_FUNCTION;
1082     }
1083     else
1084     {
1085         ret = SEC_E_INVALID_HANDLE;
1086     }
1087     return ret;
1088 }
1089
1090 /***********************************************************************
1091  *              MakeSignature
1092  */
1093 static SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext, ULONG fQOP,
1094  PSecBufferDesc pMessage, ULONG MessageSeqNo)
1095 {
1096     SECURITY_STATUS ret;
1097
1098     TRACE("%p %ld %p %ld\n", phContext, fQOP, pMessage, MessageSeqNo);
1099     if (phContext)
1100     {
1101         ret = SEC_E_UNSUPPORTED_FUNCTION;
1102     }
1103     else
1104     {
1105         ret = SEC_E_INVALID_HANDLE;
1106     }
1107     return ret;
1108 }
1109
1110 /***********************************************************************
1111  *              VerifySignature
1112  */
1113 static SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle phContext,
1114  PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
1115 {
1116     SECURITY_STATUS ret;
1117
1118     TRACE("%p %p %ld %p\n", phContext, pMessage, MessageSeqNo, pfQOP);
1119     if (phContext)
1120     {
1121         ret = SEC_E_UNSUPPORTED_FUNCTION;
1122     }
1123     else
1124     {
1125         ret = SEC_E_INVALID_HANDLE;
1126     }
1127     return ret;
1128 }
1129
1130 /***********************************************************************
1131  *             FreeCredentialsHandle
1132  */
1133 static SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(
1134         PCredHandle phCredential)
1135 {
1136     SECURITY_STATUS ret;
1137
1138     if(phCredential){
1139         PNegoHelper helper = (PNegoHelper) phCredential->dwLower;
1140         phCredential->dwUpper = 0;
1141         phCredential->dwLower = 0;
1142         cleanup_helper(helper);
1143         ret = SEC_E_OK;
1144     }
1145     else
1146         ret = SEC_E_OK;
1147     
1148     return ret;
1149 }
1150
1151 static SecurityFunctionTableA ntlmTableA = {
1152     1,
1153     NULL,   /* EnumerateSecurityPackagesA */
1154     ntlm_QueryCredentialsAttributesA,   /* QueryCredentialsAttributesA */
1155     ntlm_AcquireCredentialsHandleA,     /* AcquireCredentialsHandleA */
1156     ntlm_FreeCredentialsHandle,         /* FreeCredentialsHandle */
1157     NULL,   /* Reserved2 */
1158     ntlm_InitializeSecurityContextA,    /* InitializeSecurityContextA */
1159     ntlm_AcceptSecurityContext,         /* AcceptSecurityContext */
1160     ntlm_CompleteAuthToken,             /* CompleteAuthToken */
1161     ntlm_DeleteSecurityContext,         /* DeleteSecurityContext */
1162     NULL,  /* ApplyControlToken */
1163     ntlm_QueryContextAttributesA,       /* QueryContextAttributesA */
1164     ntlm_ImpersonateSecurityContext,    /* ImpersonateSecurityContext */
1165     ntlm_RevertSecurityContext,         /* RevertSecurityContext */
1166     ntlm_MakeSignature,                 /* MakeSignature */
1167     ntlm_VerifySignature,               /* VerifySignature */
1168     FreeContextBuffer,                  /* FreeContextBuffer */
1169     NULL,   /* QuerySecurityPackageInfoA */
1170     NULL,   /* Reserved3 */
1171     NULL,   /* Reserved4 */
1172     NULL,   /* ExportSecurityContext */
1173     NULL,   /* ImportSecurityContextA */
1174     NULL,   /* AddCredentialsA */
1175     NULL,   /* Reserved8 */
1176     NULL,   /* QuerySecurityContextToken */
1177     NULL,   /* EncryptMessage */
1178     NULL,   /* DecryptMessage */
1179     NULL,   /* SetContextAttributesA */
1180 };
1181
1182 static SecurityFunctionTableW ntlmTableW = {
1183     1,
1184     NULL,   /* EnumerateSecurityPackagesW */
1185     ntlm_QueryCredentialsAttributesW,   /* QueryCredentialsAttributesW */
1186     ntlm_AcquireCredentialsHandleW,     /* AcquireCredentialsHandleW */
1187     ntlm_FreeCredentialsHandle,         /* FreeCredentialsHandle */
1188     NULL,   /* Reserved2 */
1189     ntlm_InitializeSecurityContextW,    /* InitializeSecurityContextW */
1190     ntlm_AcceptSecurityContext,         /* AcceptSecurityContext */
1191     ntlm_CompleteAuthToken,             /* CompleteAuthToken */
1192     ntlm_DeleteSecurityContext,         /* DeleteSecurityContext */
1193     NULL,  /* ApplyControlToken */
1194     ntlm_QueryContextAttributesW,       /* QueryContextAttributesW */
1195     ntlm_ImpersonateSecurityContext,    /* ImpersonateSecurityContext */
1196     ntlm_RevertSecurityContext,         /* RevertSecurityContext */
1197     ntlm_MakeSignature,                 /* MakeSignature */
1198     ntlm_VerifySignature,               /* VerifySignature */
1199     FreeContextBuffer,                  /* FreeContextBuffer */
1200     NULL,   /* QuerySecurityPackageInfoW */
1201     NULL,   /* Reserved3 */
1202     NULL,   /* Reserved4 */
1203     NULL,   /* ExportSecurityContext */
1204     NULL,   /* ImportSecurityContextW */
1205     NULL,   /* AddCredentialsW */
1206     NULL,   /* Reserved8 */
1207     NULL,   /* QuerySecurityContextToken */
1208     NULL,   /* EncryptMessage */
1209     NULL,   /* DecryptMessage */
1210     NULL,   /* SetContextAttributesW */
1211 };
1212
1213 static WCHAR ntlm_comment_W[] = { 'N', 'T', 'L', 'M', ' ', 'S', 'e',
1214     'c', 'u', 'r', 'i', 't', 'y', ' ', 'P', 'a', 'c', 'k', 'a', 'g', 'e',0};
1215
1216 static CHAR ntlm_comment_A[] = "NTLM Security Package";
1217
1218 void SECUR32_initNTLMSP(void)
1219 {   
1220     SECURITY_STATUS ret;
1221     PNegoHelper helper;
1222
1223     SEC_CHAR *args[] = {
1224         "ntlm_auth",
1225         "--version",
1226         NULL };
1227
1228     if((ret = fork_helper(&helper, "ntlm_auth", args)) != SEC_E_OK)
1229     {
1230         /* Cheat and allocate a helper anyway, so cleanup later will work. */
1231         helper = HeapAlloc(GetProcessHeap,0, sizeof(PNegoHelper));
1232         helper->version = -1;
1233     }
1234     else
1235     {
1236         check_version(helper);
1237     }
1238
1239     if(helper->version > 2)
1240     {
1241
1242         SecureProvider *provider = SECUR32_addProvider(&ntlmTableA, &ntlmTableW,
1243             NULL);
1244         /* According to Windows, NTLM has the following capabilities. 
1245          */
1246     
1247         static const LONG caps =
1248             SECPKG_FLAG_INTEGRITY |
1249             SECPKG_FLAG_PRIVACY |
1250             SECPKG_FLAG_TOKEN_ONLY |
1251             SECPKG_FLAG_CONNECTION |
1252             SECPKG_FLAG_MULTI_REQUIRED |
1253             SECPKG_FLAG_IMPERSONATION |
1254             SECPKG_FLAG_ACCEPT_WIN32_NAME |
1255             SECPKG_FLAG_READONLY_WITH_CHECKSUM;
1256
1257         static const USHORT version = 1;
1258         static const USHORT rpcid = 10;
1259         /* In Windows, this is 12000, but ntlm_auth won't take more than 2010 
1260          * characters, so there is no use reporting a bigger size */
1261         static const ULONG  max_token = NTLM_MAX_BUF;
1262         const SecPkgInfoW infoW = { caps, version, rpcid, max_token, ntlm_name_W,
1263             ntlm_comment_W};
1264         const SecPkgInfoA infoA = { caps, version, rpcid, max_token, ntlm_name_A,
1265             ntlm_comment_A};
1266
1267         SECUR32_addPackages(provider, 1L, &infoA, &infoW);
1268     }
1269     cleanup_helper(helper);
1270     
1271 }