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