secur32: Implement a Negotiate provider that forwards to NTLM.
[wine] / dlls / secur32 / negotiate.c
1 /*
2  * Copyright 2005 Kai Blin
3  * Copyright 2012 Hans Leidekker for CodeWeavers
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  *
19  * This file implements a Negotiate provider that simply forwards to
20  * the NTLM provider.
21  */
22
23 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "sspi.h"
27 #include "rpc.h"
28 #include "wincred.h"
29 #include "secur32_priv.h"
30
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
35
36 /***********************************************************************
37  *              QueryCredentialsAttributesA
38  */
39 static SECURITY_STATUS SEC_ENTRY nego_QueryCredentialsAttributesA(
40     PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
41 {
42     FIXME("%p, %u, %p\n", phCredential, ulAttribute, pBuffer);
43     return SEC_E_UNSUPPORTED_FUNCTION;
44 }
45
46 /***********************************************************************
47  *              QueryCredentialsAttributesW
48  */
49 static SECURITY_STATUS SEC_ENTRY nego_QueryCredentialsAttributesW(
50     PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
51 {
52     FIXME("%p, %u, %p\n", phCredential, ulAttribute, pBuffer);
53     return SEC_E_UNSUPPORTED_FUNCTION;
54 }
55
56 /***********************************************************************
57  *              AcquireCredentialsHandleW
58  */
59 static SECURITY_STATUS SEC_ENTRY nego_AcquireCredentialsHandleW(
60     SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse,
61     PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
62     PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry )
63 {
64     static SEC_WCHAR ntlmW[] = {'N','T','L','M',0};
65     SECURITY_STATUS ret;
66
67     TRACE("%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p\n",
68           debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse,
69           pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
70
71     FIXME("forwarding to NTLM\n");
72     ret = ntlm_AcquireCredentialsHandleW( pszPrincipal, ntlmW, fCredentialUse,
73                                           pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument,
74                                           phCredential, ptsExpiry );
75     if (ret == SEC_E_OK)
76     {
77         NtlmCredentials *cred = (NtlmCredentials *)phCredential->dwLower;
78         cred->no_cached_credentials = (pAuthData == NULL);
79     }
80     return ret;
81 }
82
83 /***********************************************************************
84  *              AcquireCredentialsHandleA
85  */
86 static SECURITY_STATUS SEC_ENTRY nego_AcquireCredentialsHandleA(
87     SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse,
88     PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
89     PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry )
90 {
91     SECURITY_STATUS ret = SEC_E_INSUFFICIENT_MEMORY;
92     SEC_WCHAR *user = NULL, *domain = NULL, *passwd = NULL, *package = NULL;
93     SEC_WINNT_AUTH_IDENTITY_W *identityW = NULL;
94
95     TRACE("%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p\n",
96           debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse,
97           pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
98
99     if (pszPackage)
100     {
101         int package_len = MultiByteToWideChar( CP_ACP, 0, pszPackage, -1, NULL, 0 );
102         package = HeapAlloc( GetProcessHeap(), 0, package_len * sizeof(SEC_WCHAR) );
103         if (!package) return SEC_E_INSUFFICIENT_MEMORY;
104         MultiByteToWideChar( CP_ACP, 0, pszPackage, -1, package, package_len );
105     }
106     if (pAuthData)
107     {
108         SEC_WINNT_AUTH_IDENTITY_A *identity = pAuthData;
109         int user_len, domain_len, passwd_len;
110
111         if (identity->Flags == SEC_WINNT_AUTH_IDENTITY_ANSI)
112         {
113             identityW = HeapAlloc( GetProcessHeap(), 0, sizeof(*identityW) );
114             if (!identityW) goto done;
115
116             if (!identity->UserLength) user_len = 0;
117             else
118             {
119                 user_len = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)identity->User,
120                                                 identity->UserLength, NULL, 0 );
121                 user = HeapAlloc( GetProcessHeap(), 0, user_len * sizeof(SEC_WCHAR) );
122                 if (!user) goto done;
123                 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)identity->User, identity->UserLength,
124                                      user, user_len );
125             }
126             if (!identity->DomainLength) domain_len = 0;
127             else
128             {
129                 domain_len = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)identity->Domain,
130                                                   identity->DomainLength, NULL, 0 );
131                 domain = HeapAlloc( GetProcessHeap(), 0, domain_len * sizeof(SEC_WCHAR) );
132                 if (!domain) goto done;
133                 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)identity->Domain, identity->DomainLength,
134                                      domain, domain_len );
135             }
136             if (!identity->PasswordLength) passwd_len = 0;
137             else
138             {
139                 passwd_len = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)identity->Password,
140                                                   identity->PasswordLength, NULL, 0 );
141                 passwd = HeapAlloc( GetProcessHeap(), 0, passwd_len * sizeof(SEC_WCHAR) );
142                 if (!passwd) goto done;
143                 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)identity->Password, identity->PasswordLength,
144                                      passwd, passwd_len );
145             }
146             identityW->Flags          = SEC_WINNT_AUTH_IDENTITY_UNICODE;
147             identityW->User           = user;
148             identityW->UserLength     = user_len;
149             identityW->Domain         = domain;
150             identityW->DomainLength   = domain_len;
151             identityW->Password       = passwd;
152             identityW->PasswordLength = passwd_len;
153         }
154         else identityW = (SEC_WINNT_AUTH_IDENTITY_W *)identity;
155     }
156     ret = nego_AcquireCredentialsHandleW( NULL, package, fCredentialUse, pLogonID, identityW,
157                                           pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry );
158 done:
159     HeapFree( GetProcessHeap(), 0, package );
160     HeapFree( GetProcessHeap(), 0, user );
161     HeapFree( GetProcessHeap(), 0, domain );
162     HeapFree( GetProcessHeap(), 0, passwd );
163     HeapFree( GetProcessHeap(), 0, identityW );
164     return ret;
165 }
166
167 /***********************************************************************
168  *              InitializeSecurityContextW
169  */
170 static SECURITY_STATUS SEC_ENTRY nego_InitializeSecurityContextW(
171     PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName,
172     ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
173     PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
174     PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry )
175 {
176     TRACE("%p, %p, %s, 0x%08x, %u, %u, %p, %u, %p, %p, %p, %p\n",
177           phCredential, phContext, debugstr_w(pszTargetName), fContextReq,
178           Reserved1, TargetDataRep, pInput, Reserved1, phNewContext, pOutput,
179           pfContextAttr, ptsExpiry);
180
181     return ntlm_InitializeSecurityContextW( phCredential, phContext, pszTargetName,
182                                             fContextReq, Reserved1, TargetDataRep,
183                                             pInput, Reserved2, phNewContext,
184                                             pOutput, pfContextAttr, ptsExpiry );
185 }
186
187 /***********************************************************************
188  *              InitializeSecurityContextA
189  */
190 static SECURITY_STATUS SEC_ENTRY nego_InitializeSecurityContextA(
191     PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName,
192     ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
193     PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
194     PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry )
195 {
196     SECURITY_STATUS ret;
197     SEC_WCHAR *target = NULL;
198
199     TRACE("%p, %p, %s, 0x%08x, %u, %u, %p, %u, %p, %p, %p, %p\n",
200           phCredential, phContext, debugstr_a(pszTargetName), fContextReq,
201           Reserved1, TargetDataRep, pInput, Reserved1, phNewContext, pOutput,
202           pfContextAttr, ptsExpiry);
203
204     if (pszTargetName)
205     {
206         int target_len = MultiByteToWideChar( CP_ACP, 0, pszTargetName, -1, NULL, 0 );
207         target = HeapAlloc(GetProcessHeap(), 0, target_len * sizeof(SEC_WCHAR) );
208         if (!target) return SEC_E_INSUFFICIENT_MEMORY;
209         MultiByteToWideChar( CP_ACP, 0, pszTargetName, -1, target, target_len );
210     }
211     ret = nego_InitializeSecurityContextW( phCredential, phContext, target, fContextReq,
212                                            Reserved1, TargetDataRep, pInput, Reserved2,
213                                            phNewContext, pOutput, pfContextAttr, ptsExpiry );
214     HeapFree( GetProcessHeap(), 0, target );
215     return ret;
216 }
217
218 /***********************************************************************
219  *              AcceptSecurityContext
220  */
221 static SECURITY_STATUS SEC_ENTRY nego_AcceptSecurityContext(
222     PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput,
223     ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext,
224     PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
225 {
226     TRACE("%p, %p, %p, 0x%08x, %u, %p, %p, %p, %p\n", phCredential, phContext,
227           pInput, fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr,
228           ptsExpiry);
229
230     return ntlm_AcceptSecurityContext( phCredential, phContext, pInput,
231                                        fContextReq, TargetDataRep, phNewContext,
232                                        pOutput, pfContextAttr, ptsExpiry );
233 }
234
235 /***********************************************************************
236  *              CompleteAuthToken
237  */
238 static SECURITY_STATUS SEC_ENTRY nego_CompleteAuthToken(PCtxtHandle phContext,
239  PSecBufferDesc pToken)
240 {
241     SECURITY_STATUS ret;
242
243     TRACE("%p %p\n", phContext, pToken);
244     if (phContext)
245     {
246         ret = SEC_E_UNSUPPORTED_FUNCTION;
247     }
248     else
249     {
250         ret = SEC_E_INVALID_HANDLE;
251     }
252     return ret;
253 }
254
255 /***********************************************************************
256  *              DeleteSecurityContext
257  */
258 static SECURITY_STATUS SEC_ENTRY nego_DeleteSecurityContext(PCtxtHandle phContext)
259 {
260     TRACE("%p\n", phContext);
261
262     return ntlm_DeleteSecurityContext( phContext );
263 }
264
265 /***********************************************************************
266  *              ApplyControlToken
267  */
268 static SECURITY_STATUS SEC_ENTRY nego_ApplyControlToken(PCtxtHandle phContext,
269  PSecBufferDesc pInput)
270 {
271     SECURITY_STATUS ret;
272
273     TRACE("%p %p\n", phContext, pInput);
274     if (phContext)
275     {
276         ret = SEC_E_UNSUPPORTED_FUNCTION;
277     }
278     else
279     {
280         ret = SEC_E_INVALID_HANDLE;
281     }
282     return ret;
283 }
284
285 /***********************************************************************
286  *              QueryContextAttributesW
287  */
288 static SECURITY_STATUS SEC_ENTRY nego_QueryContextAttributesW(
289     PCtxtHandle phContext, ULONG ulAttribute, void *pBuffer)
290 {
291     TRACE("%p, %u, %p\n", phContext, ulAttribute, pBuffer);
292
293     switch (ulAttribute)
294     {
295     case SECPKG_ATTR_SIZES:
296     {
297         SecPkgContext_Sizes *sizes = (SecPkgContext_Sizes *)pBuffer;
298         sizes->cbMaxToken        = 2888;
299         sizes->cbMaxSignature    = 16;
300         sizes->cbSecurityTrailer = 16;
301         sizes->cbBlockSize       = 0;
302         return SEC_E_OK;
303     }
304     case SECPKG_ATTR_NEGOTIATION_INFO:
305     {
306         SecPkgContext_NegotiationInfoW *info = (SecPkgContext_NegotiationInfoW *)pBuffer;
307         info->PackageInfo      = ntlm_package_infoW;
308         info->NegotiationState = SECPKG_NEGOTIATION_COMPLETE;
309         return SEC_E_OK;
310     }
311     default:
312         return ntlm_QueryContextAttributesW( phContext, ulAttribute, pBuffer );
313     }
314 }
315
316 /***********************************************************************
317  *              QueryContextAttributesA
318  */
319 static SECURITY_STATUS SEC_ENTRY nego_QueryContextAttributesA(PCtxtHandle phContext,
320  ULONG ulAttribute, void *pBuffer)
321 {
322     TRACE("%p, %u, %p\n", phContext, ulAttribute, pBuffer);
323
324     switch (ulAttribute)
325     {
326     case SECPKG_ATTR_SIZES:
327     {
328         SecPkgContext_Sizes *sizes = (SecPkgContext_Sizes *)pBuffer;
329         sizes->cbMaxToken        = 2888;
330         sizes->cbMaxSignature    = 16;
331         sizes->cbSecurityTrailer = 16;
332         sizes->cbBlockSize       = 0;
333         return SEC_E_OK;
334     }
335     case SECPKG_ATTR_NEGOTIATION_INFO:
336     {
337         SecPkgContext_NegotiationInfoA *info = (SecPkgContext_NegotiationInfoA *)pBuffer;
338         info->PackageInfo      = ntlm_package_infoA;
339         info->NegotiationState = SECPKG_NEGOTIATION_COMPLETE;
340         return SEC_E_OK;
341     }
342     default:
343         return ntlm_QueryContextAttributesA( phContext, ulAttribute, pBuffer );
344     }
345 }
346
347 /***********************************************************************
348  *              ImpersonateSecurityContext
349  */
350 static SECURITY_STATUS SEC_ENTRY nego_ImpersonateSecurityContext(PCtxtHandle phContext)
351 {
352     SECURITY_STATUS ret;
353
354     TRACE("%p\n", phContext);
355     if (phContext)
356     {
357         ret = SEC_E_UNSUPPORTED_FUNCTION;
358     }
359     else
360     {
361         ret = SEC_E_INVALID_HANDLE;
362     }
363     return ret;
364 }
365
366 /***********************************************************************
367  *              RevertSecurityContext
368  */
369 static SECURITY_STATUS SEC_ENTRY nego_RevertSecurityContext(PCtxtHandle phContext)
370 {
371     SECURITY_STATUS ret;
372
373     TRACE("%p\n", phContext);
374     if (phContext)
375     {
376         ret = SEC_E_UNSUPPORTED_FUNCTION;
377     }
378     else
379     {
380         ret = SEC_E_INVALID_HANDLE;
381     }
382     return ret;
383 }
384
385 /***********************************************************************
386  *              MakeSignature
387  */
388 static SECURITY_STATUS SEC_ENTRY nego_MakeSignature(PCtxtHandle phContext,
389     ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
390 {
391     TRACE("%p, 0x%08x, %p, %u\n", phContext, fQOP, pMessage, MessageSeqNo);
392
393     return ntlm_MakeSignature( phContext, fQOP, pMessage, MessageSeqNo );
394 }
395
396 /***********************************************************************
397  *              VerifySignature
398  */
399 static SECURITY_STATUS SEC_ENTRY nego_VerifySignature(PCtxtHandle phContext,
400     PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
401 {
402     TRACE("%p, %p, %u, %p\n", phContext, pMessage, MessageSeqNo, pfQOP);
403
404     return ntlm_VerifySignature( phContext, pMessage, MessageSeqNo, pfQOP );
405 }
406
407 /***********************************************************************
408  *             FreeCredentialsHandle
409  */
410 SECURITY_STATUS SEC_ENTRY nego_FreeCredentialsHandle(PCredHandle phCredential)
411 {
412     TRACE("%p\n", phCredential);
413
414     return ntlm_FreeCredentialsHandle( phCredential );
415 }
416
417 /***********************************************************************
418  *             EncryptMessage
419  */
420 SECURITY_STATUS SEC_ENTRY nego_EncryptMessage(PCtxtHandle phContext,
421     ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
422 {
423     TRACE("%p, 0x%08x, %p, %u\n", phContext, fQOP, pMessage, MessageSeqNo);
424
425     return ntlm_EncryptMessage( phContext, fQOP, pMessage, MessageSeqNo );
426 }
427
428 /***********************************************************************
429  *             DecryptMessage
430  */
431 SECURITY_STATUS SEC_ENTRY nego_DecryptMessage(PCtxtHandle phContext,
432     PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
433 {
434     TRACE("%p, %p, %u, %p\n", phContext, pMessage, MessageSeqNo, pfQOP);
435
436     return ntlm_DecryptMessage( phContext, pMessage, MessageSeqNo, pfQOP );
437 }
438
439 static const SecurityFunctionTableA negoTableA = {
440     1,
441     NULL,                               /* EnumerateSecurityPackagesA */
442     nego_QueryCredentialsAttributesA,   /* QueryCredentialsAttributesA */
443     nego_AcquireCredentialsHandleA,     /* AcquireCredentialsHandleA */
444     nego_FreeCredentialsHandle,         /* FreeCredentialsHandle */
445     NULL,                               /* Reserved2 */
446     nego_InitializeSecurityContextA,    /* InitializeSecurityContextA */
447     nego_AcceptSecurityContext,         /* AcceptSecurityContext */
448     nego_CompleteAuthToken,             /* CompleteAuthToken */
449     nego_DeleteSecurityContext,         /* DeleteSecurityContext */
450     nego_ApplyControlToken,             /* ApplyControlToken */
451     nego_QueryContextAttributesA,       /* QueryContextAttributesA */
452     nego_ImpersonateSecurityContext,    /* ImpersonateSecurityContext */
453     nego_RevertSecurityContext,         /* RevertSecurityContext */
454     nego_MakeSignature,                 /* MakeSignature */
455     nego_VerifySignature,               /* VerifySignature */
456     FreeContextBuffer,                  /* FreeContextBuffer */
457     NULL,   /* QuerySecurityPackageInfoA */
458     NULL,   /* Reserved3 */
459     NULL,   /* Reserved4 */
460     NULL,   /* ExportSecurityContext */
461     NULL,   /* ImportSecurityContextA */
462     NULL,   /* AddCredentialsA */
463     NULL,   /* Reserved8 */
464     NULL,   /* QuerySecurityContextToken */
465     nego_EncryptMessage,                /* EncryptMessage */
466     nego_DecryptMessage,                /* DecryptMessage */
467     NULL,   /* SetContextAttributesA */
468 };
469
470 static const SecurityFunctionTableW negoTableW = {
471     1,
472     NULL,                               /* EnumerateSecurityPackagesW */
473     nego_QueryCredentialsAttributesW,   /* QueryCredentialsAttributesW */
474     nego_AcquireCredentialsHandleW,     /* AcquireCredentialsHandleW */
475     nego_FreeCredentialsHandle,         /* FreeCredentialsHandle */
476     NULL,                               /* Reserved2 */
477     nego_InitializeSecurityContextW,    /* InitializeSecurityContextW */
478     nego_AcceptSecurityContext,         /* AcceptSecurityContext */
479     nego_CompleteAuthToken,             /* CompleteAuthToken */
480     nego_DeleteSecurityContext,         /* DeleteSecurityContext */
481     nego_ApplyControlToken,             /* ApplyControlToken */
482     nego_QueryContextAttributesW,       /* QueryContextAttributesW */
483     nego_ImpersonateSecurityContext,    /* ImpersonateSecurityContext */
484     nego_RevertSecurityContext,         /* RevertSecurityContext */
485     nego_MakeSignature,                 /* MakeSignature */
486     nego_VerifySignature,               /* VerifySignature */
487     FreeContextBuffer,                  /* FreeContextBuffer */
488     NULL,   /* QuerySecurityPackageInfoW */
489     NULL,   /* Reserved3 */
490     NULL,   /* Reserved4 */
491     NULL,   /* ExportSecurityContext */
492     NULL,   /* ImportSecurityContextW */
493     NULL,   /* AddCredentialsW */
494     NULL,   /* Reserved8 */
495     NULL,   /* QuerySecurityContextToken */
496     nego_EncryptMessage,                /* EncryptMessage */
497     nego_DecryptMessage,                /* DecryptMessage */
498     NULL,   /* SetContextAttributesW */
499 };
500
501 #define NEGO_MAX_TOKEN 12000
502
503 static WCHAR nego_name_W[] = {'N','e','g','o','t','i','a','t','e',0};
504 static char nego_name_A[] = "Negotiate";
505
506 static WCHAR negotiate_comment_W[] =
507     {'M','i','c','r','o','s','o','f','t',' ','P','a','c','k','a','g','e',' ',
508      'N','e','g','o','t','i','a','t','o','r',0};
509 static CHAR negotiate_comment_A[] = "Microsoft Package Negotiator";
510
511 #define CAPS ( \
512     SECPKG_FLAG_INTEGRITY  | \
513     SECPKG_FLAG_PRIVACY    | \
514     SECPKG_FLAG_CONNECTION | \
515     SECPKG_FLAG_MULTI_REQUIRED | \
516     SECPKG_FLAG_EXTENDED_ERROR | \
517     SECPKG_FLAG_IMPERSONATION  | \
518     SECPKG_FLAG_ACCEPT_WIN32_NAME | \
519     SECPKG_FLAG_NEGOTIABLE        | \
520     SECPKG_FLAG_GSS_COMPATIBLE    | \
521     SECPKG_FLAG_LOGON             | \
522     SECPKG_FLAG_RESTRICTED_TOKENS )
523
524 void SECUR32_initNegotiateSP(void)
525 {
526     SecureProvider *provider = SECUR32_addProvider(&negoTableA, &negoTableW, NULL);
527
528     const SecPkgInfoW infoW = {CAPS, 1, RPC_C_AUTHN_GSS_NEGOTIATE, NEGO_MAX_TOKEN,
529                                nego_name_W, negotiate_comment_W};
530     const SecPkgInfoA infoA = {CAPS, 1, RPC_C_AUTHN_GSS_NEGOTIATE, NEGO_MAX_TOKEN,
531                                nego_name_A, negotiate_comment_A};
532     SECUR32_addPackages(provider, 1L, &infoA, &infoW);
533 }