[CRT] Massively improve performance of rand_s
[reactos.git] / dll / win32 / schannel / secur32_wine.c
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 }