usp10: Implement ScriptGetProperties.
[wine] / dlls / crypt32 / oid.c
1 /*
2  * Copyright 2002 Mike McCormack for CodeWeavers
3  * Copyright 2005 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 #include <stdio.h>
20 #include <stdarg.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "wincrypt.h"
24 #include "winreg.h"
25 #include "wine/debug.h"
26 #include "wine/list.h"
27 #include "crypt32_private.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
30
31 static const WCHAR DllW[] = { 'D','l','l',0 };
32 CRITICAL_SECTION funcSetCS;
33 struct list funcSets;
34
35 struct OIDFunctionSet
36 {
37     LPSTR name;
38     CRITICAL_SECTION cs; /* protects functions */
39     struct list functions;
40     struct list next;
41 };
42
43 struct OIDFunction
44 {
45     DWORD encoding;
46     CRYPT_OID_FUNC_ENTRY entry;
47     struct list next;
48 };
49
50 void CRYPT_InitFunctionSets(void)
51 {
52     InitializeCriticalSection(&funcSetCS);
53     list_init(&funcSets);
54 }
55
56 void CRYPT_FreeFunctionSets(void)
57 {
58     struct OIDFunctionSet *setCursor, *setNext;
59
60     LIST_FOR_EACH_ENTRY_SAFE(setCursor, setNext, &funcSets,
61      struct OIDFunctionSet, next)
62     {
63         struct OIDFunction *functionCursor, *funcNext;
64
65         list_remove(&setCursor->next);
66         CryptMemFree(setCursor->name);
67         CryptMemFree(setCursor);
68         LIST_FOR_EACH_ENTRY_SAFE(functionCursor, funcNext,
69          &setCursor->functions, struct OIDFunction, next)
70         {
71             list_remove(&functionCursor->next);
72             CryptMemFree(functionCursor);
73         }
74         DeleteCriticalSection(&setCursor->cs);
75     }
76     DeleteCriticalSection(&funcSetCS);
77 }
78
79 BOOL WINAPI CryptEnumOIDInfo(DWORD dwGroupId, DWORD dwFlags, void *pvArg,
80  PFN_CRYPT_ENUM_OID_INFO pfnEnumOIDInfo)
81 {
82     FIXME("(%ld, %08lx, %p, %p): stub\n", dwGroupId, dwFlags, pvArg,
83      pfnEnumOIDInfo);
84     return TRUE;
85 }
86
87 /* There is no free function associated with this; therefore, the sets are
88  * freed when crypt32.dll is unloaded.
89  */
90 HCRYPTOIDFUNCSET WINAPI CryptInitOIDFunctionSet(LPCSTR pszFuncName,
91  DWORD dwFlags)
92 {
93     struct OIDFunctionSet *cursor, *ret = NULL;
94
95     TRACE("(%s, %lx)\n", debugstr_a(pszFuncName), dwFlags);
96
97     EnterCriticalSection(&funcSetCS);
98     LIST_FOR_EACH_ENTRY(cursor, &funcSets, struct OIDFunctionSet, next)
99     {
100         if (!strcasecmp(pszFuncName, cursor->name))
101         {
102             ret = (HCRYPTOIDFUNCSET)cursor;
103             break;
104         }
105     }
106     if (!ret)
107     {
108         ret = CryptMemAlloc(sizeof(struct OIDFunctionSet));
109         if (ret)
110         {
111             memset(ret, 0, sizeof(*ret));
112             ret->name = CryptMemAlloc(strlen(pszFuncName) + 1);
113             if (ret->name)
114             {
115                 InitializeCriticalSection(&ret->cs);
116                 list_init(&ret->functions);
117                 strcpy(ret->name, pszFuncName);
118                 list_add_tail(&funcSets, &ret->next);
119             }
120             else
121             {
122                 CryptMemFree(ret);
123                 ret = NULL;
124             }
125         }
126     }
127     LeaveCriticalSection(&funcSetCS);
128
129     return (HCRYPTOIDFUNCSET)ret;
130 }
131
132 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
133  LPCSTR pszOID)
134 {
135     static const char szEncodingTypeFmt[] =
136      "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
137     UINT len;
138     char numericOID[7]; /* enough for "#65535" */
139     const char *oid;
140     LPSTR szKey;
141
142     /* MSDN says the encoding type is a mask, but it isn't treated that way.
143      * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
144      * "EncodingType 2" would be expected if it were a mask.  Instead native
145      * stores values in "EncodingType 3".
146      */
147     if (!HIWORD(pszOID))
148     {
149         snprintf(numericOID, sizeof(numericOID), "#%d", LOWORD(pszOID));
150         oid = numericOID;
151     }
152     else
153         oid = pszOID;
154
155     /* This is enough: the lengths of the two string parameters are explicitly
156      * counted, and we need up to five additional characters for the encoding
157      * type.  These are covered by the "%d", "%s", and "%s" characters in the
158      * format specifier that are removed by sprintf.
159      */
160     len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
161     szKey = CryptMemAlloc(len);
162     if (szKey)
163         sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
164     return szKey;
165 }
166
167 BOOL WINAPI CryptGetDefaultOIDDllList(HCRYPTOIDFUNCSET hFuncSet,
168  DWORD dwEncodingType, LPWSTR pwszDllList, DWORD *pcchDllList)
169 {
170     BOOL ret = TRUE;
171     struct OIDFunctionSet *set = (struct OIDFunctionSet *)hFuncSet;
172     char *keyName;
173     HKEY key;
174     long rc;
175
176     TRACE("(%p, %ld, %p, %p)\n", hFuncSet, dwEncodingType, pwszDllList,
177      pcchDllList);
178
179     keyName = CRYPT_GetKeyName(dwEncodingType, set->name, "DEFAULT");
180     rc = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keyName, 0, NULL, 0,
181      KEY_READ, NULL, &key, NULL);
182     if (!rc)
183     {
184         DWORD size = *pcchDllList * sizeof(WCHAR);
185
186         rc = RegQueryValueExW(key, DllW, NULL, NULL, (LPBYTE)pwszDllList,
187          &size);
188         if (!rc)
189             *pcchDllList = size / sizeof(WCHAR);
190         else
191         {
192             /* No value, return an empty list */
193             if (*pcchDllList)
194                 *pwszDllList = '\0';
195             *pcchDllList = 1;
196         }
197         RegCloseKey(key);
198     }
199     else
200     {
201         SetLastError(rc);
202         ret = FALSE;
203     }
204     CryptMemFree(keyName);
205
206     return ret;
207 }
208
209 BOOL WINAPI CryptInstallOIDFunctionAddress(HMODULE hModule,
210  DWORD dwEncodingType, LPCSTR pszFuncName, DWORD cFuncEntry,
211  const CRYPT_OID_FUNC_ENTRY rgFuncEntry[], DWORD dwFlags)
212 {
213     BOOL ret = TRUE;
214     struct OIDFunctionSet *set;
215
216     TRACE("(%p, %ld, %s, %ld, %p, %08lx)\n", hModule, dwEncodingType,
217      debugstr_a(pszFuncName), cFuncEntry, rgFuncEntry, dwFlags);
218
219     set = (struct OIDFunctionSet *)CryptInitOIDFunctionSet(pszFuncName, 0);
220     if (set)
221     {
222         DWORD i;
223
224         EnterCriticalSection(&set->cs);
225         for (i = 0; ret && i < cFuncEntry; i++)
226         {
227             struct OIDFunction *func;
228
229             if (HIWORD(rgFuncEntry[i].pszOID))
230                 func = CryptMemAlloc(sizeof(struct OIDFunction)
231                  + strlen(rgFuncEntry[i].pszOID) + 1);
232             else
233                 func = CryptMemAlloc(sizeof(struct OIDFunction));
234             if (func)
235             {
236                 func->encoding = dwEncodingType;
237                 if (HIWORD(rgFuncEntry[i].pszOID))
238                 {
239                     func->entry.pszOID = (LPSTR)((LPBYTE)func + sizeof(*func));
240                     strcpy((LPSTR)func->entry.pszOID, rgFuncEntry[i].pszOID);
241                 }
242                 else
243                     func->entry.pszOID = rgFuncEntry[i].pszOID;
244                 func->entry.pvFuncAddr = rgFuncEntry[i].pvFuncAddr;
245                 list_add_tail(&set->functions, &func->next);
246             }
247             else
248                 ret = FALSE;
249         }
250         LeaveCriticalSection(&set->cs);
251     }
252     else
253         ret = FALSE;
254     return ret;
255 }
256
257 static BOOL CRYPT_GetFuncFromReg(DWORD dwEncodingType, LPCSTR pszOID,
258  LPCSTR szFuncName, LPVOID *ppvFuncAddr, HCRYPTOIDFUNCADDR *phFuncAddr)
259 {
260     BOOL ret = FALSE;
261     char *keyName;
262     const char *funcName;
263     HKEY key;
264     long rc;
265
266     keyName = CRYPT_GetKeyName(dwEncodingType, szFuncName, pszOID);
267     rc = RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyName, 0, KEY_READ, &key);
268     if (!rc)
269     {
270         DWORD type, size = 0;
271
272         rc = RegQueryValueExA(key, "FuncName", NULL, &type, NULL, &size);
273         if (rc == ERROR_MORE_DATA && type == REG_SZ)
274         {
275             funcName = CryptMemAlloc(size);
276             rc = RegQueryValueExA(key, "FuncName", NULL, &type,
277              (LPBYTE)funcName, &size);
278         }
279         else
280             funcName = szFuncName;
281         rc = RegQueryValueExW(key, DllW, NULL, &type, NULL, &size);
282         if (rc == ERROR_MORE_DATA && type == REG_SZ)
283         {
284             LPWSTR dllName = CryptMemAlloc(size);
285
286             if (dllName)
287             {
288                 rc = RegQueryValueExW(key, DllW, NULL, NULL,
289                  (LPBYTE)dllName, &size);
290                 if (!rc)
291                 {
292                     HMODULE lib;
293
294                     /* This is a bit of a hack; MSDN describes a more
295                      * complicated unload routine than this will allow.
296                      * Still, this seems to suffice for now.
297                      */
298                     lib = LoadLibraryW(dllName);
299                     if (lib)
300                     {
301                         *ppvFuncAddr = GetProcAddress(lib, szFuncName);
302                         if (*ppvFuncAddr)
303                         {
304                             *phFuncAddr = (HCRYPTOIDFUNCADDR)lib;
305                             ret = TRUE;
306                         }
307                         else
308                         {
309                             /* Unload the library, the caller doesn't want
310                              * to unload it when the return value is NULL.
311                              */
312                             FreeLibrary(lib);
313                         }
314                     }
315                 }
316                 else
317                     SetLastError(rc);
318                 CryptMemFree(dllName);
319             }
320         }
321         else
322             SetLastError(rc);
323         if (funcName != szFuncName)
324             CryptMemFree((char *)funcName);
325         RegCloseKey(key);
326     }
327     else
328         SetLastError(rc);
329     CryptMemFree(keyName);
330     return ret;
331 }
332
333 BOOL WINAPI CryptGetOIDFunctionAddress(HCRYPTOIDFUNCSET hFuncSet,
334  DWORD dwEncodingType, LPCSTR pszOID, DWORD dwFlags, void **ppvFuncAddr,
335  HCRYPTOIDFUNCADDR *phFuncAddr)
336 {
337     BOOL ret = FALSE;
338     struct OIDFunctionSet *set = (struct OIDFunctionSet *)hFuncSet;
339
340     TRACE("(%p, %ld, %s, %08lx, %p, %p)\n", hFuncSet, dwEncodingType,
341      debugstr_a(pszOID), dwFlags, ppvFuncAddr, phFuncAddr);
342
343     *ppvFuncAddr = NULL;
344     if (!(dwFlags & CRYPT_GET_INSTALLED_OID_FUNC_FLAG))
345     {
346         struct OIDFunction *function;
347
348         EnterCriticalSection(&set->cs);
349         LIST_FOR_EACH_ENTRY(function, &set->functions, struct OIDFunction, next)
350         {
351             if (function->encoding == dwEncodingType)
352             {
353                 if (HIWORD(pszOID))
354                 {
355                     if (HIWORD(function->entry.pszOID &&
356                      !strcasecmp(function->entry.pszOID, pszOID)))
357                     {
358                         *ppvFuncAddr = function->entry.pvFuncAddr;
359                         *phFuncAddr = NULL; /* FIXME: what should it be? */
360                         ret = TRUE;
361                         break;
362                     }
363                 }
364                 else if (function->entry.pszOID == pszOID)
365                 {
366                     *ppvFuncAddr = function->entry.pvFuncAddr;
367                     *phFuncAddr = NULL; /* FIXME: what should it be? */
368                     ret = TRUE;
369                     break;
370                 }
371             }
372         }
373         LeaveCriticalSection(&set->cs);
374     }
375     if (!*ppvFuncAddr)
376         ret = CRYPT_GetFuncFromReg(dwEncodingType, pszOID, set->name,
377          ppvFuncAddr, phFuncAddr);
378     return ret;
379 }
380
381 BOOL WINAPI CryptFreeOIDFunctionAddress(HCRYPTOIDFUNCADDR hFuncAddr,
382  DWORD dwFlags)
383 {
384     TRACE("(%p, %08lx)\n", hFuncAddr, dwFlags);
385
386     /* FIXME: as MSDN states, need to check for DllCanUnloadNow in the DLL,
387      * and only unload it if it can be unloaded.  Also need to implement ref
388      * counting on the functions.
389      */
390     FreeLibrary((HMODULE)hFuncAddr);
391     return TRUE;
392 }
393
394 BOOL WINAPI CryptRegisterDefaultOIDFunction(DWORD dwEncodingType,
395  LPCSTR pszFuncName, DWORD dwIndex, LPCWSTR pwszDll)
396 {
397     FIXME("(%lx,%s,%lx,%s) stub!\n", dwEncodingType, pszFuncName, dwIndex,
398           debugstr_w(pwszDll));
399     return FALSE;
400 }
401
402 BOOL WINAPI CryptUnregisterDefaultOIDFunction(DWORD dwEncodingType,
403  LPCSTR pszFuncName, LPCWSTR pwszDll)
404 {
405     FIXME("(%lx %s %s): stub\n", dwEncodingType, debugstr_a(pszFuncName),
406      debugstr_w(pwszDll));
407     return FALSE;
408 }
409
410 BOOL WINAPI CryptGetDefaultOIDFunctionAddress(HCRYPTOIDFUNCSET hFuncSet,
411  DWORD dwEncodingType, LPCWSTR pwszDll, DWORD dwFlags, void *ppvFuncAddr,
412  HCRYPTOIDFUNCADDR *phFuncAddr)
413 {
414     FIXME("(%p, %ld, %s, %08lx, %p, %p): stub\n", hFuncSet, dwEncodingType,
415      debugstr_w(pwszDll), dwFlags, ppvFuncAddr, phFuncAddr);
416     return FALSE;
417 }
418
419 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
420                   LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
421 {
422     LONG r;
423     HKEY hKey;
424     LPSTR szKey;
425
426     TRACE("(%lx, %s, %s, %s, %s)\n", dwEncodingType, pszFuncName, pszOID,
427      debugstr_w(pwszDll), pszOverrideFuncName);
428
429     /* This only registers functions for encoding certs, not messages */
430     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
431         return TRUE;
432
433     /* Native does nothing pwszDll is NULL */
434     if (!pwszDll)
435         return TRUE;
436
437     /* I'm not matching MS bug for bug here, because I doubt any app depends on
438      * it:  native "succeeds" if pszFuncName is NULL, but the nonsensical entry
439      * it creates would never be used.
440      */
441     if (!pszFuncName || !pszOID)
442     {
443         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
444         return FALSE;
445     }
446
447     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
448     TRACE("Key name is %s\n", debugstr_a(szKey));
449
450     if (!szKey)
451         return FALSE;
452
453     r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
454     CryptMemFree(szKey);
455     if(r != ERROR_SUCCESS)
456         return FALSE;
457
458     /* write the values */
459     if (pszOverrideFuncName)
460         RegSetValueExA(hKey, "FuncName", 0, REG_SZ,
461          (const BYTE*)pszOverrideFuncName, lstrlenA(pszOverrideFuncName) + 1);
462     RegSetValueExW(hKey, DllW, 0, REG_SZ, (const BYTE*) pwszDll,
463      (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
464
465     RegCloseKey(hKey);
466     return TRUE;
467 }
468
469 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
470  LPCSTR pszOID)
471 {
472     LPSTR szKey;
473     LONG rc;
474
475     TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
476
477     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
478         return TRUE;
479
480     if (!pszFuncName || !pszOID)
481     {
482         SetLastError(ERROR_INVALID_PARAMETER);
483         return FALSE;
484     }
485
486     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
487     rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
488     CryptMemFree(szKey);
489     if (rc)
490         SetLastError(rc);
491     return rc ? FALSE : TRUE;
492 }
493
494 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
495  LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
496  DWORD *pcbValueData)
497 {
498     LPSTR szKey;
499     LONG rc;
500     HKEY hKey;
501
502     TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
503      debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
504      pcbValueData);
505
506     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
507         return TRUE;
508
509     if (!pszFuncName || !pszOID || !pwszValueName)
510     {
511         SetLastError(ERROR_INVALID_PARAMETER);
512         return FALSE;
513     }
514
515     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
516     rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
517     CryptMemFree(szKey);
518     if (rc)
519         SetLastError(rc);
520     else
521     {
522         rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
523          pbValueData, pcbValueData);
524         if (rc)
525             SetLastError(rc);
526         RegCloseKey(hKey);
527     }
528     return rc ? FALSE : TRUE;
529 }
530
531 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
532  LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
533  const BYTE *pbValueData, DWORD cbValueData)
534 {
535     LPSTR szKey;
536     LONG rc;
537     HKEY hKey;
538
539     TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
540      debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
541      cbValueData);
542
543     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
544         return TRUE;
545
546     if (!pszFuncName || !pszOID || !pwszValueName)
547     {
548         SetLastError(ERROR_INVALID_PARAMETER);
549         return FALSE;
550     }
551
552     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
553     rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
554     CryptMemFree(szKey);
555     if (rc)
556         SetLastError(rc);
557     else
558     {
559         rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
560          cbValueData);
561         if (rc)
562             SetLastError(rc);
563         RegCloseKey(hKey);
564     }
565     return rc ? FALSE : TRUE;
566 }