xref: /reactos/dll/win32/schannel/secur32_wine.c (revision c7bba39a)
1 /* Copyright (C) 2004 Juan Lang
2  *
3  * This file implements loading of SSP DLLs.
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 
20 #include "precomp.h"
21 
22 #include <assert.h>
23 
24 WINE_DEFAULT_DEBUG_CHANNEL(schannel);
25 
26 typedef struct _SecurePackageTable
27 {
28     DWORD numPackages;
29     DWORD numAllocated;
30     struct list table;
31 } SecurePackageTable;
32 
33 typedef struct _SecureProviderTable
34 {
35     DWORD numProviders;
36     DWORD numAllocated;
37     struct list table;
38 } SecureProviderTable;
39 
40 /**
41  *  Globals
42  */
43 
44 static CRITICAL_SECTION cs;
45 static CRITICAL_SECTION_DEBUG cs_debug =
46 {
47     0, 0, &cs,
48     { &cs_debug.ProcessLocksList, &cs_debug.ProcessLocksList },
49       0, 0, { (DWORD_PTR)(__FILE__ ": cs") }
50 };
51 static CRITICAL_SECTION cs = { &cs_debug, -1, 0, 0, 0, 0 };
52 static SecurePackageTable *packageTable = NULL;
53 static SecureProviderTable *providerTable = NULL;
54 
55 /***********************************************************************
56  *      EnumerateSecurityPackagesW (SECUR32.@)
57  */
58 SECURITY_STATUS WINAPI schan_EnumerateSecurityPackagesW(PULONG pcPackages,
59  PSecPkgInfoW *ppPackageInfo)
60 {
61     SECURITY_STATUS ret = SEC_E_OK;
62 
63     TRACE("(%p, %p)\n", pcPackages, ppPackageInfo);
64 
65     /* windows just crashes if pcPackages or ppPackageInfo is NULL, so will I */
66     *pcPackages = 0;
67     EnterCriticalSection(&cs);
68     if (packageTable)
69     {
70         SecurePackage *package;
71         size_t bytesNeeded;
72 
73         bytesNeeded = packageTable->numPackages * sizeof(SecPkgInfoW);
74         LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
75         {
76             if (package->infoW.Name)
77                 bytesNeeded += (lstrlenW(package->infoW.Name) + 1) * sizeof(WCHAR);
78             if (package->infoW.Comment)
79                 bytesNeeded += (lstrlenW(package->infoW.Comment) + 1) * sizeof(WCHAR);
80         }
81         if (bytesNeeded)
82         {
83             *ppPackageInfo = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
84             if (*ppPackageInfo)
85             {
86                 ULONG i = 0;
87                 PWSTR nextString;
88 
89                 *pcPackages = packageTable->numPackages;
90                 nextString = (PWSTR)((PBYTE)*ppPackageInfo +
91                  packageTable->numPackages * sizeof(SecPkgInfoW));
92                 LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
93                 {
94                     PSecPkgInfoW pkgInfo = *ppPackageInfo + i++;
95 
96                     *pkgInfo = package->infoW;
97                     if (package->infoW.Name)
98                     {
99                         TRACE("Name[%d] = %S\n", i - 1, package->infoW.Name);
100                         pkgInfo->Name = nextString;
101                         lstrcpyW(nextString, package->infoW.Name);
102                         nextString += lstrlenW(nextString) + 1;
103                     }
104                     else
105                         pkgInfo->Name = NULL;
106                     if (package->infoW.Comment)
107                     {
108                         TRACE("Comment[%d] = %S\n", i - 1, package->infoW.Comment);
109                         pkgInfo->Comment = nextString;
110                         lstrcpyW(nextString, package->infoW.Comment);
111                         nextString += lstrlenW(nextString) + 1;
112                     }
113                     else
114                         pkgInfo->Comment = NULL;
115                 }
116             }
117             else
118                 ret = SEC_E_INSUFFICIENT_MEMORY;
119         }
120     }
121     LeaveCriticalSection(&cs);
122     TRACE("<-- 0x%08x\n", ret);
123     return ret;
124 }
125 
126 /* Converts info (which is assumed to be an array of cPackages SecPkgInfoW
127  * structures) into an array of SecPkgInfoA structures, which it returns.
128  */
129 static PSecPkgInfoA thunk_PSecPkgInfoWToA(ULONG cPackages,
130  const SecPkgInfoW *info)
131 {
132     PSecPkgInfoA ret;
133 
134     if (info)
135     {
136         size_t bytesNeeded = cPackages * sizeof(SecPkgInfoA);
137         ULONG i;
138 
139         for (i = 0; i < cPackages; i++)
140         {
141             if (info[i].Name)
142                 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Name,
143                  -1, NULL, 0, NULL, NULL);
144             if (info[i].Comment)
145                 bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Comment,
146                  -1, NULL, 0, NULL, NULL);
147         }
148         ret = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
149         if (ret)
150         {
151             PSTR nextString;
152 
153             nextString = (PSTR)((PBYTE)ret + cPackages * sizeof(SecPkgInfoA));
154             for (i = 0; i < cPackages; i++)
155             {
156                 PSecPkgInfoA pkgInfo = ret + i;
157                 int bytes;
158 
159                 memcpy(pkgInfo, &info[i], sizeof(SecPkgInfoA));
160                 if (info[i].Name)
161                 {
162                     pkgInfo->Name = nextString;
163                     /* just repeat back to WideCharToMultiByte how many bytes
164                      * it requires, since we asked it earlier
165                      */
166                     bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
167                      NULL, 0, NULL, NULL);
168                     WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
169                      pkgInfo->Name, bytes, NULL, NULL);
170                     nextString += lstrlenA(nextString) + 1;
171                 }
172                 else
173                     pkgInfo->Name = NULL;
174                 if (info[i].Comment)
175                 {
176                     pkgInfo->Comment = nextString;
177                     /* just repeat back to WideCharToMultiByte how many bytes
178                      * it requires, since we asked it earlier
179                      */
180                     bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
181                      NULL, 0, NULL, NULL);
182                     WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
183                      pkgInfo->Comment, bytes, NULL, NULL);
184                     nextString += lstrlenA(nextString) + 1;
185                 }
186                 else
187                     pkgInfo->Comment = NULL;
188             }
189         }
190     }
191     else
192         ret = NULL;
193     return ret;
194 }
195 
196 /***********************************************************************
197  *      EnumerateSecurityPackagesA (SECUR32.@)
198  */
199 SECURITY_STATUS WINAPI schan_EnumerateSecurityPackagesA(PULONG pcPackages,
200  PSecPkgInfoA *ppPackageInfo)
201 {
202     SECURITY_STATUS ret;
203     PSecPkgInfoW info;
204 
205     ret = schan_EnumerateSecurityPackagesW(pcPackages, &info);
206     if (ret == SEC_E_OK && *pcPackages && info)
207     {
208         *ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
209         if (*pcPackages && !*ppPackageInfo)
210         {
211             *pcPackages = 0;
212             ret = SEC_E_INSUFFICIENT_MEMORY;
213         }
214         schan_FreeContextBuffer(info);
215     }
216     return ret;
217 }
218 
219 SECURITY_STATUS
220 WINAPI
221 schan_FreeContextBuffer (
222     PVOID pvoid
223     )
224 {
225     HeapFree(GetProcessHeap(), 0, pvoid);
226     return SEC_E_OK;
227 }
228 
229 
230 
231 static PWSTR SECUR32_strdupW(PCWSTR str)
232 {
233     PWSTR ret;
234 
235     if (str)
236     {
237         ret = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(str) + 1) * sizeof(WCHAR));
238         if (ret)
239             lstrcpyW(ret, str);
240     }
241     else
242         ret = NULL;
243     return ret;
244 }
245 
246 PWSTR SECUR32_AllocWideFromMultiByte(PCSTR str)
247 {
248     PWSTR ret;
249 
250     if (str)
251     {
252         int charsNeeded = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
253 
254         if (charsNeeded)
255         {
256             ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded * sizeof(WCHAR));
257             if (ret)
258                 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, charsNeeded);
259         }
260         else
261             ret = NULL;
262     }
263     else
264         ret = NULL;
265     return ret;
266 }
267 
268 PSTR SECUR32_AllocMultiByteFromWide(PCWSTR str)
269 {
270     PSTR ret;
271 
272     if (str)
273     {
274         int charsNeeded = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0,
275          NULL, NULL);
276 
277         if (charsNeeded)
278         {
279             ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded);
280             if (ret)
281                 WideCharToMultiByte(CP_ACP, 0, str, -1, ret, charsNeeded,
282                  NULL, NULL);
283         }
284         else
285             ret = NULL;
286     }
287     else
288         ret = NULL;
289     return ret;
290 }
291 
292 static void _copyPackageInfo(PSecPkgInfoW info, const SecPkgInfoA *inInfoA,
293  const SecPkgInfoW *inInfoW)
294 {
295     if (info && (inInfoA || inInfoW))
296     {
297         /* odd, I know, but up until Name and Comment the structures are
298          * identical
299          */
300         memcpy(info, inInfoW ? inInfoW : (const SecPkgInfoW *)inInfoA, sizeof(*info));
301         if (inInfoW)
302         {
303             info->Name = SECUR32_strdupW(inInfoW->Name);
304             info->Comment = SECUR32_strdupW(inInfoW->Comment);
305         }
306         else
307         {
308             info->Name = SECUR32_AllocWideFromMultiByte(inInfoA->Name);
309             info->Comment = SECUR32_AllocWideFromMultiByte(inInfoA->Comment);
310         }
311     }
312 }
313 
314 SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA,
315  const SecurityFunctionTableW *fnTableW, PCWSTR moduleName)
316 {
317     SecureProvider *ret;
318 
319     EnterCriticalSection(&cs);
320 
321     if (!providerTable)
322     {
323         providerTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProviderTable));
324         if (!providerTable)
325         {
326             LeaveCriticalSection(&cs);
327             return NULL;
328         }
329 
330         list_init(&providerTable->table);
331     }
332 
333     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProvider));
334     if (!ret)
335     {
336         LeaveCriticalSection(&cs);
337         return NULL;
338     }
339 
340     list_add_tail(&providerTable->table, &ret->entry);
341     ret->lib = NULL;
342 
343 #ifndef __REACTOS__
344     if (fnTableA || fnTableW)
345     {
346         ret->moduleName = moduleName ? SECUR32_strdupW(moduleName) : NULL;
347         _makeFnTableA(&ret->fnTableA, fnTableA, fnTableW);
348         _makeFnTableW(&ret->fnTableW, fnTableA, fnTableW);
349         ret->loaded = !moduleName;
350     }
351     else
352 #endif
353     {
354         ret->moduleName = SECUR32_strdupW(moduleName);
355         ret->loaded = FALSE;
356     }
357 
358     LeaveCriticalSection(&cs);
359     return ret;
360 }
361 
362 void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd,
363  const SecPkgInfoA *infoA, const SecPkgInfoW *infoW)
364 {
365     ULONG i;
366 
367     assert(provider);
368     assert(infoA || infoW);
369 
370     EnterCriticalSection(&cs);
371 
372     if (!packageTable)
373     {
374         packageTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackageTable));
375         if (!packageTable)
376         {
377             LeaveCriticalSection(&cs);
378             return;
379         }
380 
381         packageTable->numPackages = 0;
382         list_init(&packageTable->table);
383     }
384 
385     for (i = 0; i < toAdd; i++)
386     {
387         SecurePackage *package = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackage));
388         if (!package)
389             continue;
390 
391         list_add_tail(&packageTable->table, &package->entry);
392 
393         package->provider = provider;
394         _copyPackageInfo(&package->infoW,
395             infoA ? &infoA[i] : NULL,
396             infoW ? &infoW[i] : NULL);
397     }
398     packageTable->numPackages += toAdd;
399 
400     LeaveCriticalSection(&cs);
401 }
402