~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/crypt32/oid.c

Version: ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * Copyright 2002 Mike McCormack for CodeWeavers
  3  * Copyright 2005-2006 Juan Lang
  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 "config.h"
 21 #include "wine/port.h"
 22 
 23 #include <stdio.h>
 24 #include <stdarg.h>
 25 #define NONAMELESSUNION
 26 #include "windef.h"
 27 #include "winbase.h"
 28 #include "wincrypt.h"
 29 #include "winreg.h"
 30 #include "winuser.h"
 31 #include "wine/debug.h"
 32 #include "wine/list.h"
 33 #include "crypt32_private.h"
 34 #include "cryptres.h"
 35 
 36 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
 37 
 38 static const WCHAR DllW[] = { 'D','l','l',0 };
 39 
 40 static void init_oid_info(HINSTANCE hinst);
 41 static void free_function_sets(void);
 42 static void free_oid_info(void);
 43 
 44 void crypt_oid_init(HINSTANCE hinst)
 45 {
 46     init_oid_info(hinst);
 47 }
 48 
 49 void crypt_oid_free(void)
 50 {
 51     free_function_sets();
 52     free_oid_info();
 53 }
 54 
 55 static CRITICAL_SECTION funcSetCS;
 56 static CRITICAL_SECTION_DEBUG funcSetCSDebug =
 57 {
 58     0, 0, &funcSetCS,
 59     { &funcSetCSDebug.ProcessLocksList, &funcSetCSDebug.ProcessLocksList },
 60     0, 0, { (DWORD_PTR)(__FILE__ ": funcSetCS") }
 61 };
 62 static CRITICAL_SECTION funcSetCS = { &funcSetCSDebug, -1, 0, 0, 0, 0 };
 63 static struct list funcSets = { &funcSets, &funcSets };
 64 
 65 struct OIDFunctionSet
 66 {
 67     LPSTR name;
 68     CRITICAL_SECTION cs; /* protects functions */
 69     struct list functions;
 70     struct list next;
 71 };
 72 
 73 struct OIDFunction
 74 {
 75     DWORD encoding;
 76     CRYPT_OID_FUNC_ENTRY entry;
 77     struct list next;
 78 };
 79 
 80 static const WCHAR ROOT[] = {'R','O','O','T',0};
 81 static const WCHAR MY[] = {'M','Y',0};
 82 static const WCHAR CA[] = {'C','A',0};
 83 static const WCHAR ADDRESSBOOK[] = {'A','D','D','R','E','S','S','B','O','O','K',0};
 84 static const LPCWSTR LocalizedKeys[] = {ROOT,MY,CA,ADDRESSBOOK};
 85 static WCHAR LocalizedNames[4][256];
 86 
 87 static void free_function_sets(void)
 88 {
 89     struct OIDFunctionSet *setCursor, *setNext;
 90 
 91     LIST_FOR_EACH_ENTRY_SAFE(setCursor, setNext, &funcSets,
 92      struct OIDFunctionSet, next)
 93     {
 94         struct OIDFunction *functionCursor, *funcNext;
 95 
 96         list_remove(&setCursor->next);
 97         CryptMemFree(setCursor->name);
 98         LIST_FOR_EACH_ENTRY_SAFE(functionCursor, funcNext,
 99          &setCursor->functions, struct OIDFunction, next)
100         {
101             list_remove(&functionCursor->next);
102             CryptMemFree(functionCursor);
103         }
104         setCursor->cs.DebugInfo->Spare[0] = 0;
105         DeleteCriticalSection(&setCursor->cs);
106         CryptMemFree(setCursor);
107     }
108 }
109 
110 /* There is no free function associated with this; therefore, the sets are
111  * freed when crypt32.dll is unloaded.
112  */
113 HCRYPTOIDFUNCSET WINAPI CryptInitOIDFunctionSet(LPCSTR pszFuncName,
114  DWORD dwFlags)
115 {
116     struct OIDFunctionSet *cursor, *ret = NULL;
117 
118     TRACE("(%s, %x)\n", debugstr_a(pszFuncName), dwFlags);
119 
120     EnterCriticalSection(&funcSetCS);
121     LIST_FOR_EACH_ENTRY(cursor, &funcSets, struct OIDFunctionSet, next)
122     {
123         if (!strcasecmp(pszFuncName, cursor->name))
124         {
125             ret = (HCRYPTOIDFUNCSET)cursor;
126             break;
127         }
128     }
129     if (!ret)
130     {
131         ret = CryptMemAlloc(sizeof(struct OIDFunctionSet));
132         if (ret)
133         {
134             memset(ret, 0, sizeof(*ret));
135             ret->name = CryptMemAlloc(strlen(pszFuncName) + 1);
136             if (ret->name)
137             {
138                 InitializeCriticalSection(&ret->cs);
139                 ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": OIDFunctionSet.cs");
140                 list_init(&ret->functions);
141                 strcpy(ret->name, pszFuncName);
142                 list_add_tail(&funcSets, &ret->next);
143             }
144             else
145             {
146                 CryptMemFree(ret);
147                 ret = NULL;
148             }
149         }
150     }
151     LeaveCriticalSection(&funcSetCS);
152 
153     return (HCRYPTOIDFUNCSET)ret;
154 }
155 
156 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
157  LPCSTR pszOID)
158 {
159     static const char szEncodingTypeFmt[] =
160      "Software\\Microsoft\\Cryptography\\OID\\EncodingType %d\\%s\\%s";
161     UINT len;
162     char numericOID[7]; /* enough for "#65535" */
163     const char *oid;
164     LPSTR szKey;
165 
166     /* MSDN says the encoding type is a mask, but it isn't treated that way.
167      * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
168      * "EncodingType 2" would be expected if it were a mask.  Instead native
169      * stores values in "EncodingType 3".
170      */
171     if (!HIWORD(pszOID))
172     {
173         snprintf(numericOID, sizeof(numericOID), "#%d", LOWORD(pszOID));
174         oid = numericOID;
175     }
176     else
177         oid = pszOID;
178 
179     /* This is enough: the lengths of the two string parameters are explicitly
180      * counted, and we need up to five additional characters for the encoding
181      * type.  These are covered by the "%d", "%s", and "%s" characters in the
182      * format specifier that are removed by sprintf.
183      */
184     len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
185     szKey = CryptMemAlloc(len);
186     if (szKey)
187         sprintf(szKey, szEncodingTypeFmt,
188          GET_CERT_ENCODING_TYPE(dwEncodingType), pszFuncName, oid);
189     return szKey;
190 }
191 
192 BOOL WINAPI CryptGetDefaultOIDDllList(HCRYPTOIDFUNCSET hFuncSet,
193  DWORD dwEncodingType, LPWSTR pwszDllList, DWORD *pcchDllList)
194 {
195     BOOL ret = TRUE;
196     struct OIDFunctionSet *set = (struct OIDFunctionSet *)hFuncSet;
197     char *keyName;
198     HKEY key;
199     long rc;
200 
201     TRACE("(%p, %d, %p, %p)\n", hFuncSet, dwEncodingType, pwszDllList,
202      pcchDllList);
203 
204     keyName = CRYPT_GetKeyName(dwEncodingType, set->name, "DEFAULT");
205     rc = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keyName, 0, NULL, 0,
206      KEY_READ, NULL, &key, NULL);
207     if (!rc)
208     {
209         DWORD size = *pcchDllList * sizeof(WCHAR);
210 
211         rc = RegQueryValueExW(key, DllW, NULL, NULL, (LPBYTE)pwszDllList,
212          &size);
213         if (!rc)
214             *pcchDllList = size / sizeof(WCHAR);
215         else
216         {
217             /* No value, return an empty list */
218             if (pwszDllList && *pcchDllList)
219                 *pwszDllList = '\0';
220             *pcchDllList = 1;
221         }
222         RegCloseKey(key);
223     }
224     else
225     {
226         /* No value, return an empty list */
227         if (pwszDllList && *pcchDllList)
228             *pwszDllList = '\0';
229         *pcchDllList = 1;
230     }
231     CryptMemFree(keyName);
232 
233     return ret;
234 }
235 
236 BOOL WINAPI CryptInstallOIDFunctionAddress(HMODULE hModule,
237  DWORD dwEncodingType, LPCSTR pszFuncName, DWORD cFuncEntry,
238  const CRYPT_OID_FUNC_ENTRY rgFuncEntry[], DWORD dwFlags)
239 {
240     BOOL ret = TRUE;
241     struct OIDFunctionSet *set;
242 
243     TRACE("(%p, %d, %s, %d, %p, %08x)\n", hModule, dwEncodingType,
244      debugstr_a(pszFuncName), cFuncEntry, rgFuncEntry, dwFlags);
245 
246     set = (struct OIDFunctionSet *)CryptInitOIDFunctionSet(pszFuncName, 0);
247     if (set)
248     {
249         DWORD i;
250 
251         EnterCriticalSection(&set->cs);
252         for (i = 0; ret && i < cFuncEntry; i++)
253         {
254             struct OIDFunction *func;
255 
256             if (HIWORD(rgFuncEntry[i].pszOID))
257                 func = CryptMemAlloc(sizeof(struct OIDFunction)
258                  + strlen(rgFuncEntry[i].pszOID) + 1);
259             else
260                 func = CryptMemAlloc(sizeof(struct OIDFunction));
261             if (func)
262             {
263                 func->encoding = GET_CERT_ENCODING_TYPE(dwEncodingType);
264                 if (HIWORD(rgFuncEntry[i].pszOID))
265                 {
266                     LPSTR oid;
267 
268                     oid = (LPSTR)((LPBYTE)func + sizeof(*func));
269                     strcpy(oid, rgFuncEntry[i].pszOID);
270                     func->entry.pszOID = oid;
271                 }
272                 else
273                     func->entry.pszOID = rgFuncEntry[i].pszOID;
274                 func->entry.pvFuncAddr = rgFuncEntry[i].pvFuncAddr;
275                 list_add_tail(&set->functions, &func->next);
276             }
277             else
278                 ret = FALSE;
279         }
280         LeaveCriticalSection(&set->cs);
281     }
282     else
283         ret = FALSE;
284     return ret;
285 }
286 
287 struct FuncAddr
288 {
289     HMODULE lib;
290     LPWSTR  dllList;
291     LPWSTR  currentDll;
292 };
293 
294 static BOOL CRYPT_GetFuncFromReg(DWORD dwEncodingType, LPCSTR pszOID,
295  LPCSTR szFuncName, LPVOID *ppvFuncAddr, HCRYPTOIDFUNCADDR *phFuncAddr)
296 {
297     BOOL ret = FALSE;
298     char *keyName;
299     const char *funcName;
300     HKEY key;
301     long rc;
302 
303     keyName = CRYPT_GetKeyName(dwEncodingType, szFuncName, pszOID);
304     rc = RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyName, 0, KEY_READ, &key);
305     if (!rc)
306     {
307         DWORD type, size = 0;
308 
309         rc = RegQueryValueExA(key, "FuncName", NULL, &type, NULL, &size);
310         if ((!rc || rc == ERROR_MORE_DATA) && type == REG_SZ)
311         {
312             funcName = CryptMemAlloc(size);
313             rc = RegQueryValueExA(key, "FuncName", NULL, &type,
314              (LPBYTE)funcName, &size);
315         }
316         else
317             funcName = szFuncName;
318         rc = RegQueryValueExW(key, DllW, NULL, &type, NULL, &size);
319         if ((!rc || rc == ERROR_MORE_DATA) && type == REG_SZ)
320         {
321             LPWSTR dllName = CryptMemAlloc(size);
322 
323             if (dllName)
324             {
325                 rc = RegQueryValueExW(key, DllW, NULL, NULL,
326                  (LPBYTE)dllName, &size);
327                 if (!rc)
328                 {
329                     HMODULE lib;
330 
331                     /* This is a bit of a hack; MSDN describes a more
332                      * complicated unload routine than this will allow.
333                      * Still, this seems to suffice for now.
334                      */
335                     lib = LoadLibraryW(dllName);
336                     if (lib)
337                     {
338                         *ppvFuncAddr = GetProcAddress(lib, funcName);
339                         if (*ppvFuncAddr)
340                         {
341                             struct FuncAddr *addr =
342                              CryptMemAlloc(sizeof(struct FuncAddr));
343 
344                             if (addr)
345                             {
346                                 addr->lib = lib;
347                                 addr->dllList = addr->currentDll = NULL;
348                                 *phFuncAddr = addr;
349                                 ret = TRUE;
350                             }
351                             else
352                             {
353                                 *phFuncAddr = NULL;
354                                 FreeLibrary(lib);
355                             }
356                         }
357                         else
358                         {
359                             /* Unload the library, the caller doesn't want
360                              * to unload it when the return value is NULL.
361                              */
362                             FreeLibrary(lib);
363                         }
364                     }
365                 }
366                 else
367                     SetLastError(rc);
368                 CryptMemFree(dllName);
369             }
370         }
371         else
372             SetLastError(rc);
373         if (funcName != szFuncName)
374             CryptMemFree((char *)funcName);
375         RegCloseKey(key);
376     }
377     else
378         SetLastError(rc);
379     CryptMemFree(keyName);
380     return ret;
381 }
382 
383 BOOL WINAPI CryptGetOIDFunctionAddress(HCRYPTOIDFUNCSET hFuncSet,
384  DWORD dwEncodingType, LPCSTR pszOID, DWORD dwFlags, void **ppvFuncAddr,
385  HCRYPTOIDFUNCADDR *phFuncAddr)
386 {
387     BOOL ret = FALSE;
388     struct OIDFunctionSet *set = (struct OIDFunctionSet *)hFuncSet;
389 
390     TRACE("(%p, %d, %s, %08x, %p, %p)\n", hFuncSet, dwEncodingType,
391      debugstr_a(pszOID), dwFlags, ppvFuncAddr, phFuncAddr);
392 
393     *ppvFuncAddr = NULL;
394     if (!(dwFlags & CRYPT_GET_INSTALLED_OID_FUNC_FLAG))
395     {
396         struct OIDFunction *function;
397 
398         EnterCriticalSection(&set->cs);
399         LIST_FOR_EACH_ENTRY(function, &set->functions, struct OIDFunction, next)
400         {
401             if (function->encoding == GET_CERT_ENCODING_TYPE(dwEncodingType))
402             {
403                 if (HIWORD(pszOID))
404                 {
405                     if (HIWORD(function->entry.pszOID) &&
406                      !strcasecmp(function->entry.pszOID, pszOID))
407                     {
408                         *ppvFuncAddr = function->entry.pvFuncAddr;
409                         *phFuncAddr = NULL; /* FIXME: what should it be? */
410                         ret = TRUE;
411                         break;
412                     }
413                 }
414                 else if (function->entry.pszOID == pszOID)
415                 {
416                     *ppvFuncAddr = function->entry.pvFuncAddr;
417                     *phFuncAddr = NULL; /* FIXME: what should it be? */
418                     ret = TRUE;
419                     break;
420                 }
421             }
422         }
423         LeaveCriticalSection(&set->cs);
424     }
425     if (!*ppvFuncAddr)
426         ret = CRYPT_GetFuncFromReg(dwEncodingType, pszOID, set->name,
427          ppvFuncAddr, phFuncAddr);
428     TRACE("returning %d\n", ret);
429     return ret;
430 }
431 
432 BOOL WINAPI CryptFreeOIDFunctionAddress(HCRYPTOIDFUNCADDR hFuncAddr,
433  DWORD dwFlags)
434 {
435     TRACE("(%p, %08x)\n", hFuncAddr, dwFlags);
436 
437     /* FIXME: as MSDN states, need to check for DllCanUnloadNow in the DLL,
438      * and only unload it if it can be unloaded.  Also need to implement ref
439      * counting on the functions.
440      */
441     if (hFuncAddr)
442     {
443         struct FuncAddr *addr = (struct FuncAddr *)hFuncAddr;
444 
445         CryptMemFree(addr->dllList);
446         FreeLibrary(addr->lib);
447         CryptMemFree(addr);
448     }
449     return TRUE;
450 }
451 
452 static BOOL CRYPT_GetFuncFromDll(LPCWSTR dll, LPCSTR func, HMODULE *lib,
453  void **ppvFuncAddr)
454 {
455     BOOL ret = FALSE;
456 
457     *lib = LoadLibraryW(dll);
458     if (*lib)
459     {
460         *ppvFuncAddr = GetProcAddress(*lib, func);
461         if (*ppvFuncAddr)
462             ret = TRUE;
463         else
464         {
465             FreeLibrary(*lib);
466             *lib = NULL;
467         }
468     }
469     return ret;
470 }
471 
472 BOOL WINAPI CryptGetDefaultOIDFunctionAddress(HCRYPTOIDFUNCSET hFuncSet,
473  DWORD dwEncodingType, LPCWSTR pwszDll, DWORD dwFlags, void **ppvFuncAddr,
474  HCRYPTOIDFUNCADDR *phFuncAddr)
475 {
476     struct OIDFunctionSet *set = (struct OIDFunctionSet *)hFuncSet;
477     BOOL ret = FALSE;
478 
479     TRACE("(%p, %d, %s, %08x, %p, %p)\n", hFuncSet, dwEncodingType,
480      debugstr_w(pwszDll), dwFlags, ppvFuncAddr, phFuncAddr);
481 
482     if (pwszDll)
483     {
484         HMODULE lib;
485 
486         *phFuncAddr = NULL;
487         ret = CRYPT_GetFuncFromDll(pwszDll, set->name, &lib, ppvFuncAddr);
488         if (ret)
489         {
490             struct FuncAddr *addr = CryptMemAlloc(sizeof(struct FuncAddr));
491 
492             if (addr)
493             {
494                 addr->lib = lib;
495                 addr->dllList = addr->currentDll = NULL;
496                 *phFuncAddr = addr;
497             }
498             else
499             {
500                 FreeLibrary(lib);
501                 *ppvFuncAddr = NULL;
502                 SetLastError(ERROR_OUTOFMEMORY);
503                 ret = FALSE;
504             }
505         }
506         else
507             SetLastError(ERROR_FILE_NOT_FOUND);
508     }
509     else
510     {
511         struct FuncAddr *addr = (struct FuncAddr *)*phFuncAddr;
512 
513         if (!addr)
514         {
515             DWORD size;
516 
517             ret = CryptGetDefaultOIDDllList(hFuncSet, dwEncodingType, NULL,
518              &size);
519             if (ret)
520             {
521                 LPWSTR dllList = CryptMemAlloc(size * sizeof(WCHAR));
522 
523                 if (dllList)
524                 {
525                     ret = CryptGetDefaultOIDDllList(hFuncSet, dwEncodingType,
526                      dllList, &size);
527                     if (ret)
528                     {
529                         addr = CryptMemAlloc(sizeof(struct FuncAddr));
530                         if (addr)
531                         {
532                             addr->dllList = dllList;
533                             addr->currentDll = dllList;
534                             addr->lib = NULL;
535                             *phFuncAddr = addr;
536                         }
537                         else
538                         {
539                             CryptMemFree(dllList);
540                             SetLastError(ERROR_OUTOFMEMORY);
541                             ret = FALSE;
542                         }
543                     }
544                 }
545                 else
546                 {
547                     SetLastError(ERROR_OUTOFMEMORY);
548                     ret = FALSE;
549                 }
550             }
551         }
552         if (addr)
553         {
554             if (!*addr->currentDll)
555             {
556                 CryptFreeOIDFunctionAddress(*phFuncAddr, 0);
557                 SetLastError(ERROR_FILE_NOT_FOUND);
558                 *phFuncAddr = NULL;
559                 ret = FALSE;
560             }
561             else
562             {
563                 /* FIXME: as elsewhere, can't free until DllCanUnloadNow says
564                  * it's possible, and should defer unloading for some time to
565                  * avoid repeated LoadLibrary/FreeLibrary on the same dll.
566                  */
567                 FreeLibrary(addr->lib);
568                 ret = CRYPT_GetFuncFromDll(addr->currentDll, set->name,
569                  &addr->lib, ppvFuncAddr);
570                 if (ret)
571                 {
572                     /* Move past the current DLL */
573                     addr->currentDll += lstrlenW(addr->currentDll) + 1;
574                     *phFuncAddr = addr;
575                 }
576                 else
577                 {
578                     CryptFreeOIDFunctionAddress(*phFuncAddr, 0);
579                     SetLastError(ERROR_FILE_NOT_FOUND);
580                     *phFuncAddr = NULL;
581                 }
582             }
583         }
584     }
585     return ret;
586 }
587 
588 /***********************************************************************
589  *             CryptRegisterOIDFunction (CRYPT32.@)
590  *
591  * Register the DLL and the functions it uses to cover the combination
592  * of encoding type, functionname and OID.
593  *
594  * PARAMS
595  *  dwEncodingType       [I] Encoding type to be used.
596  *  pszFuncName          [I] Name of the function to be registered.
597  *  pszOID               [I] OID of the function (numeric or string).
598  *  pwszDll              [I] The DLL that is to be registered.
599  *  pszOverrideFuncName  [I] Name of the function in the DLL.
600  *
601  * RETURNS
602  *  Success: TRUE.
603  *  Failure: FALSE. (Look at GetLastError()).
604  *
605  * NOTES
606  *  Registry errors are always reported via SetLastError().
607  */
608 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
609                   LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
610 {
611     LONG r;
612     HKEY hKey;
613     LPSTR szKey;
614 
615     TRACE("(%x, %s, %s, %s, %s)\n", dwEncodingType, pszFuncName,
616      debugstr_a(pszOID), debugstr_w(pwszDll), pszOverrideFuncName);
617 
618     /* Native does nothing pwszDll is NULL */
619     if (!pwszDll)
620         return TRUE;
621 
622     /* I'm not matching MS bug for bug here, because I doubt any app depends on
623      * it:  native "succeeds" if pszFuncName is NULL, but the nonsensical entry
624      * it creates would never be used.
625      */
626     if (!pszFuncName || !pszOID)
627     {
628         SetLastError(E_INVALIDARG);
629         return FALSE;
630     }
631 
632     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
633     TRACE("Key name is %s\n", debugstr_a(szKey));
634 
635     if (!szKey)
636         return FALSE;
637 
638     r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
639     CryptMemFree(szKey);
640 
641     if (r != ERROR_SUCCESS) goto error_close_key;
642 
643     /* write the values */
644     if (pszOverrideFuncName)
645     {
646         r = RegSetValueExA(hKey, "FuncName", 0, REG_SZ,
647              (const BYTE*)pszOverrideFuncName, lstrlenA(pszOverrideFuncName) + 1);
648         if (r != ERROR_SUCCESS) goto error_close_key;
649     }
650     r = RegSetValueExW(hKey, DllW, 0, REG_SZ, (const BYTE*) pwszDll,
651          (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
652 
653 error_close_key:
654 
655     RegCloseKey(hKey);
656 
657     if (r != ERROR_SUCCESS) 
658     {
659         SetLastError(r);
660         return FALSE;
661     }
662 
663     return TRUE;
664 }
665 
666 /***********************************************************************
667  *             CryptUnregisterOIDFunction (CRYPT32.@)
668  */
669 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
670  LPCSTR pszOID)
671 {
672     LPSTR szKey;
673     LONG rc;
674 
675     TRACE("%x %s %s\n", dwEncodingType, debugstr_a(pszFuncName),
676      debugstr_a(pszOID));
677 
678     if (!pszFuncName || !pszOID)
679     {
680         SetLastError(ERROR_INVALID_PARAMETER);
681         return FALSE;
682     }
683 
684     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
685     rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
686     CryptMemFree(szKey);
687     if (rc)
688         SetLastError(rc);
689     return rc ? FALSE : TRUE;
690 }
691 
692 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
693  LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
694  DWORD *pcbValueData)
695 {
696     LPSTR szKey;
697     LONG rc;
698     HKEY hKey;
699 
700     TRACE("%x %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
701      debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
702      pcbValueData);
703 
704     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
705         return TRUE;
706 
707     if (!pszFuncName || !pszOID || !pwszValueName)
708     {
709         SetLastError(ERROR_INVALID_PARAMETER);
710         return FALSE;
711     }
712 
713     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
714     rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
715     CryptMemFree(szKey);
716     if (rc)
717         SetLastError(rc);
718     else
719     {
720         rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
721          pbValueData, pcbValueData);
722         if (rc)
723             SetLastError(rc);
724         RegCloseKey(hKey);
725     }
726     return rc ? FALSE : TRUE;
727 }
728 
729 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
730  LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
731  const BYTE *pbValueData, DWORD cbValueData)
732 {
733     LPSTR szKey;
734     LONG rc;
735     HKEY hKey;
736 
737     TRACE("%x %s %s %s %d %p %d\n", dwEncodingType, debugstr_a(pszFuncName),
738      debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
739      cbValueData);
740 
741     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
742         return TRUE;
743 
744     if (!pszFuncName || !pszOID || !pwszValueName)
745     {
746         SetLastError(ERROR_INVALID_PARAMETER);
747         return FALSE;
748     }
749 
750     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
751     rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
752     CryptMemFree(szKey);
753     if (rc)
754         SetLastError(rc);
755     else
756     {
757         rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
758          cbValueData);
759         if (rc)
760             SetLastError(rc);
761         RegCloseKey(hKey);
762     }
763     return rc ? FALSE : TRUE;
764 }
765 
766 static LPCWSTR CRYPT_FindStringInMultiString(LPCWSTR multi, LPCWSTR toFind)
767 {
768     LPCWSTR ret = NULL, ptr;
769 
770     for (ptr = multi; ptr && *ptr && !ret; ptr += lstrlenW(ptr) + 1)
771     {
772         if (!lstrcmpiW(ptr, toFind))
773             ret = ptr;
774     }
775     return ret;
776 }
777 
778 static DWORD CRYPT_GetMultiStringCharacterLen(LPCWSTR multi)
779 {
780     DWORD ret;
781 
782     if (multi)
783     {
784         LPCWSTR ptr;
785 
786         /* Count terminating empty string */
787         ret = 1;
788         for (ptr = multi; *ptr; ptr += lstrlenW(ptr) + 1)
789             ret += lstrlenW(ptr) + 1;
790     }
791     else
792         ret = 0;
793     return ret;
794 }
795 
796 static LPWSTR CRYPT_AddStringToMultiString(LPWSTR multi, LPCWSTR toAdd,
797  DWORD index)
798 {
799     LPWSTR ret;
800 
801     if (!multi)
802     {
803         /* FIXME: ignoring index, is that okay? */
804         ret = CryptMemAlloc((lstrlenW(toAdd) + 2) * sizeof(WCHAR));
805         if (ret)
806         {
807             /* copy string, including NULL terminator */
808             memcpy(ret, toAdd, (lstrlenW(toAdd) + 1) * sizeof(WCHAR));
809             /* add terminating empty string */
810             *(ret + lstrlenW(toAdd) + 1) = 0;
811         }
812     }
813     else
814     {
815         DWORD len = CRYPT_GetMultiStringCharacterLen(multi);
816 
817         ret = CryptMemRealloc(multi, (len + lstrlenW(toAdd) + 1) *
818          sizeof(WCHAR));
819         if (ret)
820         {
821             LPWSTR spotToAdd;
822 
823             if (index == CRYPT_REGISTER_LAST_INDEX)
824                 spotToAdd = ret + len - 1;
825             else
826             {
827                 DWORD i;
828 
829                 /* FIXME: if index is too large for the string, toAdd is
830                  * added to the end.  Is that okay?
831                  */
832                 for (i = 0, spotToAdd = ret; i < index && *spotToAdd;
833                  spotToAdd += lstrlenW(spotToAdd) + 1)
834                     ;
835             }
836             if (spotToAdd)
837             {
838                 /* Copy existing string "right" */
839                 memmove(spotToAdd + lstrlenW(toAdd) + 1, spotToAdd,
840                  (len - (spotToAdd - ret)) * sizeof(WCHAR));
841                 /* Copy new string */
842                 memcpy(spotToAdd, toAdd, (lstrlenW(toAdd) + 1) * sizeof(WCHAR));
843             }
844             else
845             {
846                 CryptMemFree(ret);
847                 ret = NULL;
848             }
849         }
850     }
851     return ret;
852 }
853 
854 static BOOL CRYPT_RemoveStringFromMultiString(LPWSTR multi, LPCWSTR toRemove)
855 {
856     LPWSTR spotToRemove = (LPWSTR)CRYPT_FindStringInMultiString(multi,
857      toRemove);
858     BOOL ret;
859 
860     if (spotToRemove)
861     {
862         DWORD len = CRYPT_GetMultiStringCharacterLen(multi);
863 
864         /* Copy remainder of string "left" */
865         memmove(spotToRemove, spotToRemove + lstrlenW(toRemove) + 1,
866          (len - (spotToRemove - multi)) * sizeof(WCHAR));
867         ret = TRUE;
868     }
869     else
870     {
871         SetLastError(ERROR_FILE_NOT_FOUND);
872         ret = FALSE;
873     }
874     return ret;
875 }
876 
877 static BOOL CRYPT_GetDefaultOIDKey(DWORD dwEncodingType, LPCSTR pszFuncName,
878  PHKEY key)
879 {
880     LPSTR keyName;
881     LONG r;
882 
883     keyName = CRYPT_GetKeyName(dwEncodingType, pszFuncName, "DEFAULT");
884     TRACE("Key name is %s\n", debugstr_a(keyName));
885 
886     if (!keyName)
887         return FALSE;
888 
889     r = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keyName, 0, NULL, 0, KEY_ALL_ACCESS,
890      NULL, key, NULL);
891     CryptMemFree(keyName);
892     if (r != ERROR_SUCCESS)
893     {
894         SetLastError(r);
895         return FALSE;
896     }
897     return TRUE;
898 }
899 
900 static LPWSTR CRYPT_GetDefaultOIDDlls(HKEY key)
901 {
902     LONG r;
903     DWORD type, size;
904     LPWSTR dlls;
905 
906     r = RegQueryValueExW(key, DllW, NULL, &type, NULL, &size);
907     if (r == ERROR_SUCCESS && type == REG_MULTI_SZ)
908     {
909         dlls = CryptMemAlloc(size);
910         r = RegQueryValueExW(key, DllW, NULL, &type, (LPBYTE)dlls, &size);
911         if (r != ERROR_SUCCESS)
912         {
913             CryptMemFree(dlls);
914             dlls = NULL;
915         }
916     }
917     else
918         dlls = NULL;
919     return dlls;
920 }
921 
922 static inline BOOL CRYPT_SetDefaultOIDDlls(HKEY key, LPCWSTR dlls)
923 {
924     DWORD len = CRYPT_GetMultiStringCharacterLen(dlls);
925     LONG r;
926 
927     if ((r = RegSetValueExW(key, DllW, 0, REG_MULTI_SZ, (const BYTE *)dlls,
928      len * sizeof (WCHAR))))
929         SetLastError(r);
930     return r == ERROR_SUCCESS;
931 }
932 
933 /***********************************************************************
934  *             CryptRegisterDefaultOIDFunction (CRYPT32.@)
935  */
936 BOOL WINAPI CryptRegisterDefaultOIDFunction(DWORD dwEncodingType,
937  LPCSTR pszFuncName, DWORD dwIndex, LPCWSTR pwszDll)
938 {
939     HKEY key;
940     LPWSTR dlls;
941     BOOL ret = FALSE;
942 
943     TRACE("(%x, %s, %d, %s)\n", dwEncodingType, debugstr_a(pszFuncName),
944      dwIndex, debugstr_w(pwszDll));
945 
946     if (!pwszDll)
947     {
948         SetLastError(E_INVALIDARG);
949         return FALSE;
950     }
951 
952     if (!CRYPT_GetDefaultOIDKey(dwEncodingType, pszFuncName, &key))
953         return FALSE;
954 
955     dlls = CRYPT_GetDefaultOIDDlls(key);
956     if (CRYPT_FindStringInMultiString(dlls, pwszDll))
957         SetLastError(ERROR_FILE_EXISTS);
958     else
959     {
960         dlls = CRYPT_AddStringToMultiString(dlls, pwszDll, dwIndex);
961         if (dlls)
962             ret = CRYPT_SetDefaultOIDDlls(key, dlls);
963     }
964     CryptMemFree(dlls);
965     RegCloseKey(key);
966     return ret;
967 }
968 
969 BOOL WINAPI CryptUnregisterDefaultOIDFunction(DWORD dwEncodingType,
970  LPCSTR pszFuncName, LPCWSTR pwszDll)
971 {
972     HKEY key;
973     LPWSTR dlls;
974     BOOL ret;
975 
976     TRACE("(%x, %s, %s)\n", dwEncodingType, debugstr_a(pszFuncName),
977      debugstr_w(pwszDll));
978 
979     if (!pwszDll)
980     {
981         SetLastError(E_INVALIDARG);
982         return FALSE;
983     }
984 
985     if (!CRYPT_GetDefaultOIDKey(dwEncodingType, pszFuncName, &key))
986         return FALSE;
987 
988     dlls = CRYPT_GetDefaultOIDDlls(key);
989     if ((ret = CRYPT_RemoveStringFromMultiString(dlls, pwszDll)))
990         ret = CRYPT_SetDefaultOIDDlls(key, dlls);
991     CryptMemFree(dlls);
992     RegCloseKey(key);
993     return ret;
994 }
995 
996 static void oid_init_localizednames(HINSTANCE hInstance)
997 {
998     int i;
999 
1000     for(i = 0; i < sizeof(LocalizedKeys)/sizeof(LPCWSTR); i++)
1001     {
1002         LoadStringW(hInstance, IDS_LOCALIZEDNAME_ROOT+i, LocalizedNames[i], 256);
1003     }
1004 }
1005 
1006 /********************************************************************
1007  *              CryptFindLocalizedName (CRYPT32.@)
1008  */
1009 LPCWSTR WINAPI CryptFindLocalizedName(LPCWSTR pwszCryptName)
1010 {
1011     int i;
1012 
1013     for(i = 0; i < sizeof(LocalizedKeys)/sizeof(LPCWSTR); i++)
1014     {
1015         if(!lstrcmpiW(LocalizedKeys[i], pwszCryptName))
1016         {
1017             return LocalizedNames[i];
1018         }
1019     }
1020 
1021     FIXME("No name for: %s - stub\n",debugstr_w(pwszCryptName));
1022     return NULL;
1023 }
1024 
1025 static CRITICAL_SECTION oidInfoCS;
1026 static CRITICAL_SECTION_DEBUG oidInfoCSDebug =
1027 {
1028     0, 0, &oidInfoCS,
1029     { &oidInfoCSDebug.ProcessLocksList, &oidInfoCSDebug.ProcessLocksList },
1030