secur32: Allow loading external schannel.dll.
[wine] / dlls / secur32 / schannel.c
1 /* Copyright (C) 2005 Juan Lang
2  *
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 2.1 of the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16  *
17  * This file implements the schannel provider, or, the SSL/TLS implementations.
18  * FIXME: It should be rather obvious that this file is empty of any
19  * implementation.
20  */
21 #include <stdarg.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "sspi.h"
25 #include "schannel.h"
26 #include "secur32_priv.h"
27 #include "wine/debug.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
30
31 static SECURITY_STATUS schan_QueryCredentialsAttributes(
32  PCredHandle phCredential, ULONG ulAttribute, const VOID *pBuffer)
33 {
34     SECURITY_STATUS ret;
35
36     switch (ulAttribute)
37     {
38     case SECPKG_ATTR_SUPPORTED_ALGS:
39         if (pBuffer)
40         {
41             /* FIXME: get from CryptoAPI */
42             FIXME("SECPKG_ATTR_SUPPORTED_ALGS: stub\n");
43             ret = SEC_E_UNSUPPORTED_FUNCTION;
44         }
45         else
46             ret = SEC_E_INTERNAL_ERROR;
47         break;
48     case SECPKG_ATTR_CIPHER_STRENGTHS:
49         if (pBuffer)
50         {
51             SecPkgCred_CipherStrengths *r = (SecPkgCred_CipherStrengths*)pBuffer;
52
53             /* FIXME: get from CryptoAPI */
54             FIXME("SECPKG_ATTR_CIPHER_STRENGTHS: semi-stub\n");
55             r->dwMinimumCipherStrength = 40;
56             r->dwMaximumCipherStrength = 168;
57             ret = SEC_E_OK;
58         }
59         else
60             ret = SEC_E_INTERNAL_ERROR;
61         break;
62     case SECPKG_ATTR_SUPPORTED_PROTOCOLS:
63         if (pBuffer)
64         {
65             /* FIXME: get from OpenSSL? */
66             FIXME("SECPKG_ATTR_SUPPORTED_PROTOCOLS: stub\n");
67             ret = SEC_E_UNSUPPORTED_FUNCTION;
68         }
69         else
70             ret = SEC_E_INTERNAL_ERROR;
71         break;
72     default:
73         ret = SEC_E_UNSUPPORTED_FUNCTION;
74     }
75     return ret;
76 }
77
78 static SECURITY_STATUS SEC_ENTRY schan_QueryCredentialsAttributesA(
79  PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
80 {
81     SECURITY_STATUS ret;
82
83     TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer);
84
85     switch (ulAttribute)
86     {
87     case SECPKG_CRED_ATTR_NAMES:
88         FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
89         ret = SEC_E_UNSUPPORTED_FUNCTION;
90         break;
91     default:
92         ret = schan_QueryCredentialsAttributes(phCredential, ulAttribute,
93          pBuffer);
94     }
95     return ret;
96 }
97
98 static SECURITY_STATUS SEC_ENTRY schan_QueryCredentialsAttributesW(
99  PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
100 {
101     SECURITY_STATUS ret;
102
103     TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer);
104
105     switch (ulAttribute)
106     {
107     case SECPKG_CRED_ATTR_NAMES:
108         FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
109         ret = SEC_E_UNSUPPORTED_FUNCTION;
110         break;
111     default:
112         ret = schan_QueryCredentialsAttributes(phCredential, ulAttribute,
113          pBuffer);
114     }
115     return ret;
116 }
117
118 static SECURITY_STATUS schan_CheckCreds(const SCHANNEL_CRED *schanCred)
119 {
120     SECURITY_STATUS st;
121
122     switch (schanCred->dwVersion)
123     {
124     case SCH_CRED_V3:
125     case SCHANNEL_CRED_VERSION:
126         break;
127     default:
128         return SEC_E_INTERNAL_ERROR;
129     }
130
131     if (schanCred->cCreds == 0)
132         st = SEC_E_NO_CREDENTIALS;
133     else if (schanCred->cCreds > 1)
134         st = SEC_E_UNKNOWN_CREDENTIALS;
135     else
136     {
137         DWORD keySpec;
138         HCRYPTPROV csp;
139         BOOL ret, freeCSP;
140
141         ret = CryptAcquireCertificatePrivateKey(schanCred->paCred[0],
142          0, /* FIXME: what flags to use? */ NULL,
143          &csp, &keySpec, &freeCSP);
144         if (ret)
145         {
146             st = SEC_E_OK;
147             if (freeCSP)
148                 CryptReleaseContext(csp, 0);
149         }
150         else
151             st = SEC_E_UNKNOWN_CREDENTIALS;
152     }
153     return st;
154 }
155
156 static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schanCred,
157  PCredHandle phCredential, PTimeStamp ptsExpiry)
158 {
159     SECURITY_STATUS st = SEC_E_OK;
160
161     if (schanCred)
162     {
163         st = schan_CheckCreds(schanCred);
164         if (st == SEC_E_NO_CREDENTIALS)
165             st = SEC_E_OK;
166     }
167
168     /* For now, the only thing I'm interested in is the direction of the
169      * connection, so just store it.
170      */
171     if (st == SEC_E_OK)
172     {
173         phCredential->dwUpper = SECPKG_CRED_OUTBOUND;
174         /* Outbound credentials have no expiry */
175         if (ptsExpiry)
176         {
177             ptsExpiry->LowPart = 0;
178             ptsExpiry->HighPart = 0;
179         }
180     }
181     return st;
182 }
183
184 static SECURITY_STATUS schan_AcquireServerCredentials(const SCHANNEL_CRED *schanCred,
185  PCredHandle phCredential, PTimeStamp ptsExpiry)
186 {
187     SECURITY_STATUS st;
188
189     if (!schanCred) return SEC_E_NO_CREDENTIALS;
190
191     st = schan_CheckCreds(schanCred);
192     if (st == SEC_E_OK)
193     {
194         phCredential->dwUpper = SECPKG_CRED_INBOUND;
195         /* FIXME: get expiry from cert */
196     }
197     return st;
198 }
199
200 static SECURITY_STATUS schan_AcquireCredentialsHandle(ULONG fCredentialUse,
201  const SCHANNEL_CRED *schanCred, PCredHandle phCredential, PTimeStamp ptsExpiry)
202 {
203     SECURITY_STATUS ret;
204
205     if (fCredentialUse == SECPKG_CRED_OUTBOUND)
206         ret = schan_AcquireClientCredentials(schanCred, phCredential,
207          ptsExpiry);
208     else
209         ret = schan_AcquireServerCredentials(schanCred, phCredential,
210          ptsExpiry);
211     return ret;
212 }
213
214 static SECURITY_STATUS SEC_ENTRY schan_AcquireCredentialsHandleA(
215  SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse,
216  PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
217  PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
218 {
219     TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n",
220      debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse,
221      pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
222     return schan_AcquireCredentialsHandle(fCredentialUse,
223      (PSCHANNEL_CRED)pAuthData, phCredential, ptsExpiry);
224 }
225
226 static SECURITY_STATUS SEC_ENTRY schan_AcquireCredentialsHandleW(
227  SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse,
228  PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
229  PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
230 {
231     TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n",
232      debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse,
233      pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
234     return schan_AcquireCredentialsHandle(fCredentialUse,
235      (PSCHANNEL_CRED)pAuthData, phCredential, ptsExpiry);
236 }
237
238 static SECURITY_STATUS SEC_ENTRY schan_FreeCredentialsHandle(
239  PCredHandle phCredential)
240 {
241     FIXME("(%p): stub\n", phCredential);
242     return SEC_E_OK;
243 }
244
245 /***********************************************************************
246  *              InitializeSecurityContextA
247  */
248 static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextA(
249  PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName,
250  ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
251  PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
252  PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
253 {
254     SECURITY_STATUS ret;
255
256     TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential, phContext,
257      debugstr_a(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
258      Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
259     if(phCredential)
260     {
261         FIXME("stub\n");
262         ret = SEC_E_UNSUPPORTED_FUNCTION;
263     }
264     else
265     {
266         ret = SEC_E_INVALID_HANDLE;
267     }
268     return ret;
269 }
270
271 /***********************************************************************
272  *              InitializeSecurityContextW
273  */
274 static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
275  PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName,
276  ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
277  PSecBufferDesc pInput,ULONG Reserved2, PCtxtHandle phNewContext,
278  PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
279 {
280     SECURITY_STATUS ret;
281
282     TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential, phContext,
283      debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
284      Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
285     if (phCredential)
286     {
287         FIXME("stub\n");
288         ret = SEC_E_UNSUPPORTED_FUNCTION;
289     }
290     else
291     {
292         ret = SEC_E_INVALID_HANDLE;
293     }
294     return ret;
295 }
296
297 static const SecurityFunctionTableA schanTableA = {
298     1,
299     NULL, /* EnumerateSecurityPackagesA */
300     schan_QueryCredentialsAttributesA,
301     schan_AcquireCredentialsHandleA,
302     schan_FreeCredentialsHandle,
303     NULL, /* Reserved2 */
304     schan_InitializeSecurityContextA, 
305     NULL, /* AcceptSecurityContext */
306     NULL, /* CompleteAuthToken */
307     NULL, /* DeleteSecurityContext */
308     NULL, /* ApplyControlToken */
309     NULL, /* QueryContextAttributesA */
310     NULL, /* ImpersonateSecurityContext */
311     NULL, /* RevertSecurityContext */
312     NULL, /* MakeSignature */
313     NULL, /* VerifySignature */
314     FreeContextBuffer,
315     NULL, /* QuerySecurityPackageInfoA */
316     NULL, /* Reserved3 */
317     NULL, /* Reserved4 */
318     NULL, /* ExportSecurityContext */
319     NULL, /* ImportSecurityContextA */
320     NULL, /* AddCredentialsA */
321     NULL, /* Reserved8 */
322     NULL, /* QuerySecurityContextToken */
323     NULL, /* EncryptMessage */
324     NULL, /* DecryptMessage */
325     NULL, /* SetContextAttributesA */
326 };
327
328 static const SecurityFunctionTableW schanTableW = {
329     1,
330     NULL, /* EnumerateSecurityPackagesW */
331     schan_QueryCredentialsAttributesW,
332     schan_AcquireCredentialsHandleW,
333     schan_FreeCredentialsHandle,
334     NULL, /* Reserved2 */
335     schan_InitializeSecurityContextW, 
336     NULL, /* AcceptSecurityContext */
337     NULL, /* CompleteAuthToken */
338     NULL, /* DeleteSecurityContext */
339     NULL, /* ApplyControlToken */
340     NULL, /* QueryContextAttributesW */
341     NULL, /* ImpersonateSecurityContext */
342     NULL, /* RevertSecurityContext */
343     NULL, /* MakeSignature */
344     NULL, /* VerifySignature */
345     FreeContextBuffer,
346     NULL, /* QuerySecurityPackageInfoW */
347     NULL, /* Reserved3 */
348     NULL, /* Reserved4 */
349     NULL, /* ExportSecurityContext */
350     NULL, /* ImportSecurityContextW */
351     NULL, /* AddCredentialsW */
352     NULL, /* Reserved8 */
353     NULL, /* QuerySecurityContextToken */
354     NULL, /* EncryptMessage */
355     NULL, /* DecryptMessage */
356     NULL, /* SetContextAttributesW */
357 };
358
359 static const WCHAR schannelComment[] = { 'S','c','h','a','n','n','e','l',' ',
360  'S','e','c','u','r','i','t','y',' ','P','a','c','k','a','g','e',0 };
361 static const WCHAR schannelDllName[] = { 's','c','h','a','n','n','e','l','.','d','l','l',0 };
362
363 void SECUR32_initSchannelSP(void)
364 {
365     SecureProvider *provider = SECUR32_addProvider(&schanTableA, &schanTableW,
366      schannelDllName);
367
368     if (provider)
369     {
370         /* This is what Windows reports.  This shouldn't break any applications
371          * even though the functions are missing, because the wrapper will
372          * return SEC_E_UNSUPPORTED_FUNCTION if our function is NULL.
373          */
374         static const long caps =
375          SECPKG_FLAG_INTEGRITY |
376          SECPKG_FLAG_PRIVACY |
377          SECPKG_FLAG_CONNECTION |
378          SECPKG_FLAG_MULTI_REQUIRED |
379          SECPKG_FLAG_EXTENDED_ERROR |
380          SECPKG_FLAG_IMPERSONATION |
381          SECPKG_FLAG_ACCEPT_WIN32_NAME |
382          SECPKG_FLAG_STREAM;
383         static const short version = 1;
384         static const long maxToken = 16384;
385         SEC_WCHAR *uniSPName = (SEC_WCHAR *)UNISP_NAME_W,
386          *schannel = (SEC_WCHAR *)SCHANNEL_NAME_W;
387
388         const SecPkgInfoW info[] = {
389          { caps, version, UNISP_RPC_ID, maxToken, uniSPName, uniSPName },
390          { caps, version, UNISP_RPC_ID, maxToken, schannel,
391           (SEC_WCHAR *)schannelComment },
392         };
393
394         SECUR32_addPackages(provider, sizeof(info) / sizeof(info[0]), NULL,
395          info);
396     }
397 }