user32: Change the desktop colour and pattern to match win2k.
[wine] / dlls / advapi32 / cred.c
1 /*
2  * Credential Management APIs
3  *
4  * Copyright 2007 Robert Shearman for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winreg.h"
26 #include "wincred.h"
27 #include "winternl.h"
28
29 #include "crypt.h"
30
31 #include "wine/unicode.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(cred);
35
36 /* the size of the ARC4 key used to encrypt the password data */
37 #define KEY_SIZE 8
38
39 static const WCHAR wszCredentialManagerKey[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
40     'C','r','e','d','e','n','t','i','a','l',' ','M','a','n','a','g','e','r',0};
41 static const WCHAR wszEncryptionKeyValue[] = {'E','n','c','r','y','p','t','i','o','n','K','e','y',0};
42
43 static const WCHAR wszFlagsValue[] = {'F','l','a','g','s',0};
44 static const WCHAR wszTypeValue[] = {'T','y','p','e',0};
45 static const WCHAR wszTargetNameValue[] = {'T','a','r','g','e','t','N','a','m','e',0};
46 static const WCHAR wszCommentValue[] = {'C','o','m','m','e','n','t',0};
47 static const WCHAR wszLastWrittenValue[] = {'L','a','s','t','W','r','i','t','t','e','n',0};
48 static const WCHAR wszPersistValue[] = {'P','e','r','s','i','s','t',0};
49 static const WCHAR wszTargetAliasValue[] = {'T','a','r','g','e','t','A','l','i','a','s',0};
50 static const WCHAR wszUserNameValue[] = {'U','s','e','r','N','a','m','e',0};
51 static const WCHAR wszPasswordValue[] = {'P','a','s','s','w','o','r','d',0};
52
53 static DWORD read_credential_blob(HKEY hkey, const BYTE key_data[KEY_SIZE],
54                                   LPBYTE credential_blob,
55                                   DWORD *credential_blob_size)
56 {
57     DWORD ret;
58     DWORD type;
59
60     *credential_blob_size = 0;
61     ret = RegQueryValueExW(hkey, wszPasswordValue, 0, &type, NULL, credential_blob_size);
62     if (ret != ERROR_SUCCESS)
63         return ret;
64     else if (type != REG_BINARY)
65         return ERROR_REGISTRY_CORRUPT;
66     if (credential_blob)
67     {
68         struct ustring data;
69         struct ustring key;
70
71         ret = RegQueryValueExW(hkey, wszPasswordValue, 0, &type, (LPVOID)credential_blob,
72                                credential_blob_size);
73         if (ret != ERROR_SUCCESS)
74             return ret;
75         else if (type != REG_BINARY)
76             return ERROR_REGISTRY_CORRUPT;
77
78         key.Length = key.MaximumLength = sizeof(key_data);
79         key.Buffer = (unsigned char *)key_data;
80
81         data.Length = data.MaximumLength = *credential_blob_size;
82         data.Buffer = credential_blob;
83         SystemFunction032(&data, &key);
84     }
85     return ERROR_SUCCESS;
86 }
87
88 static DWORD read_credential(HKEY hkey, PCREDENTIALW credential,
89                              const BYTE key_data[KEY_SIZE], char *buffer, DWORD *len)
90 {
91     DWORD type;
92     DWORD ret;
93     DWORD count;
94
95     ret = RegQueryValueExW(hkey, NULL, 0, &type, NULL, &count);
96     if (ret != ERROR_SUCCESS)
97         return ret;
98     else if (type != REG_SZ)
99         return ERROR_REGISTRY_CORRUPT;
100     *len += count;
101     if (credential)
102     {
103         credential->TargetName = (LPWSTR)buffer;
104         ret = RegQueryValueExW(hkey, NULL, 0, &type, (LPVOID)credential->TargetName,
105                                &count);
106         if (ret != ERROR_SUCCESS || type != REG_SZ) return ret;
107         buffer += count;
108     }
109
110     ret = RegQueryValueExW(hkey, wszCommentValue, 0, &type, NULL, &count);
111     if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
112         return ret;
113     else if (type != REG_SZ)
114         return ERROR_REGISTRY_CORRUPT;
115     *len += count;
116     if (credential)
117     {
118         credential->Comment = (LPWSTR)buffer;
119         ret = RegQueryValueExW(hkey, wszCommentValue, 0, &type, (LPVOID)credential->Comment,
120                                &count);
121         if (ret == ERROR_FILE_NOT_FOUND)
122             credential->Comment = NULL;
123         else if (ret != ERROR_SUCCESS)
124             return ret;
125         else if (type != REG_SZ)
126             return ERROR_REGISTRY_CORRUPT;
127         else
128             buffer += count;
129     }
130
131     ret = RegQueryValueExW(hkey, wszTargetAliasValue, 0, &type, NULL, &count);
132     if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
133         return ret;
134     else if (type != REG_SZ)
135         return ERROR_REGISTRY_CORRUPT;
136     *len += count;
137     if (credential)
138     {
139         credential->TargetAlias = (LPWSTR)buffer;
140         ret = RegQueryValueExW(hkey, wszTargetAliasValue, 0, &type, (LPVOID)credential->TargetAlias,
141                                &count);
142         if (ret == ERROR_FILE_NOT_FOUND)
143             credential->TargetAlias = NULL;
144         else if (ret != ERROR_SUCCESS)
145             return ret;
146         else if (type != REG_SZ)
147             return ERROR_REGISTRY_CORRUPT;
148         else
149             buffer += count;
150     }
151
152     ret = RegQueryValueExW(hkey, wszUserNameValue, 0, &type, NULL, &count);
153     if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
154         return ret;
155     else if (type != REG_SZ)
156         return ERROR_REGISTRY_CORRUPT;
157     *len += count;
158     if (credential)
159     {
160         credential->UserName = (LPWSTR)buffer;
161         ret = RegQueryValueExW(hkey, wszUserNameValue, 0, &type, (LPVOID)credential->UserName,
162                                &count);
163         if (ret == ERROR_FILE_NOT_FOUND)
164         {
165             credential->UserName = NULL;
166             ret = ERROR_SUCCESS;
167         }
168         else if (ret != ERROR_SUCCESS)
169             return ret;
170         else if (type != REG_SZ)
171             return ERROR_REGISTRY_CORRUPT;
172         else
173             buffer += count;
174     }
175
176     ret = read_credential_blob(hkey, key_data, NULL, &count);
177     if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
178         return ret;
179     *len += count;
180     if (credential)
181     {
182         credential->CredentialBlob = (LPBYTE)buffer;
183         ret = read_credential_blob(hkey, key_data, credential->CredentialBlob, &count);
184         if (ret == ERROR_FILE_NOT_FOUND)
185         {
186             credential->CredentialBlob = NULL;
187             ret = ERROR_SUCCESS;
188         }
189         else if (ret != ERROR_SUCCESS)
190             return ret;
191         credential->CredentialBlobSize = count;
192         buffer += count;
193     }
194
195     /* FIXME: Attributes */
196     if (credential)
197     {
198         credential->AttributeCount = 0;
199         credential->Attributes = NULL;
200     }
201
202     if (!credential) return ERROR_SUCCESS;
203
204     count = sizeof(credential->Flags);
205     ret = RegQueryValueExW(hkey, wszFlagsValue, NULL, &type, (LPVOID)&credential->Flags,
206                            &count);
207     if (ret != ERROR_SUCCESS)
208         return ret;
209     else if (type != REG_DWORD)
210         return ERROR_REGISTRY_CORRUPT;
211     count = sizeof(credential->Type);
212     ret = RegQueryValueExW(hkey, wszTypeValue, NULL, &type, (LPVOID)&credential->Type,
213                            &count);
214     if (ret != ERROR_SUCCESS)
215         return ret;
216     else if (type != REG_DWORD)
217         return ERROR_REGISTRY_CORRUPT;
218
219     count = sizeof(credential->LastWritten);
220     ret = RegQueryValueExW(hkey, wszLastWrittenValue, NULL, &type, (LPVOID)&credential->LastWritten,
221                            &count);
222     if (ret != ERROR_SUCCESS)
223         return ret;
224     else if (type != REG_BINARY)
225         return ERROR_REGISTRY_CORRUPT;
226     count = sizeof(credential->Persist);
227     ret = RegQueryValueExW(hkey, wszPersistValue, NULL, &type, (LPVOID)&credential->Persist,
228                            &count);
229     if (ret == ERROR_SUCCESS && type != REG_DWORD)
230         return ERROR_REGISTRY_CORRUPT;
231     return ret;
232 }
233
234 static DWORD write_credential_blob(HKEY hkey, LPCWSTR target_name, DWORD type,
235                                    const BYTE key_data[KEY_SIZE],
236                                    const BYTE *credential_blob, DWORD credential_blob_size)
237 {
238     LPBYTE encrypted_credential_blob;
239     struct ustring data;
240     struct ustring key;
241     DWORD ret;
242
243     key.Length = key.MaximumLength = sizeof(key_data);
244     key.Buffer = (unsigned char *)key_data;
245
246     encrypted_credential_blob = HeapAlloc(GetProcessHeap(), 0, credential_blob_size);
247     if (!encrypted_credential_blob) return ERROR_OUTOFMEMORY;
248
249     memcpy(encrypted_credential_blob, credential_blob, credential_blob_size);
250     data.Length = data.MaximumLength = credential_blob_size;
251     data.Buffer = encrypted_credential_blob;
252     SystemFunction032(&data, &key);
253
254     ret = RegSetValueExW(hkey, wszPasswordValue, 0, REG_BINARY, (LPVOID)encrypted_credential_blob, credential_blob_size);
255     HeapFree(GetProcessHeap(), 0, encrypted_credential_blob);
256
257     return ret;
258 }
259
260 static DWORD write_credential(HKEY hkey, const CREDENTIALW *credential,
261                               const BYTE key_data[KEY_SIZE], BOOL preserve_blob)
262 {
263     DWORD ret;
264     FILETIME LastWritten;
265
266     GetSystemTimeAsFileTime(&LastWritten);
267
268     ret = RegSetValueExW(hkey, wszFlagsValue, 0, REG_DWORD, (LPVOID)&credential->Flags,
269                          sizeof(credential->Flags));
270     if (ret != ERROR_SUCCESS) return ret;
271     ret = RegSetValueExW(hkey, wszTypeValue, 0, REG_DWORD, (LPVOID)&credential->Type,
272                          sizeof(credential->Type));
273     if (ret != ERROR_SUCCESS) return ret;
274     ret = RegSetValueExW(hkey, NULL, 0, REG_SZ, (LPVOID)credential->TargetName,
275                          sizeof(WCHAR)*(strlenW(credential->TargetName)+1));
276     if (ret != ERROR_SUCCESS) return ret;
277     if (credential->Comment)
278     {
279         ret = RegSetValueExW(hkey, wszCommentValue, 0, REG_SZ, (LPVOID)credential->Comment,
280                              sizeof(WCHAR)*(strlenW(credential->Comment)+1));
281         if (ret != ERROR_SUCCESS) return ret;
282     }
283     ret = RegSetValueExW(hkey, wszLastWrittenValue, 0, REG_BINARY, (LPVOID)&LastWritten,
284                          sizeof(LastWritten));
285     if (ret != ERROR_SUCCESS) return ret;
286     ret = RegSetValueExW(hkey, wszPersistValue, 0, REG_DWORD, (LPVOID)&credential->Persist,
287                          sizeof(credential->Persist));
288     if (ret != ERROR_SUCCESS) return ret;
289     /* FIXME: Attributes */
290     if (credential->TargetAlias)
291     {
292         ret = RegSetValueExW(hkey, wszTargetAliasValue, 0, REG_SZ, (LPVOID)credential->TargetAlias,
293                              sizeof(WCHAR)*(strlenW(credential->TargetAlias)+1));
294         if (ret != ERROR_SUCCESS) return ret;
295     }
296     if (credential->UserName)
297     {
298         ret = RegSetValueExW(hkey, wszUserNameValue, 0, REG_SZ, (LPVOID)credential->UserName,
299                              sizeof(WCHAR)*(strlenW(credential->UserName)+1));
300         if (ret != ERROR_SUCCESS) return ret;
301     }
302     if (!preserve_blob)
303     {
304         ret = write_credential_blob(hkey, credential->TargetName, credential->Type,
305                                     key_data, credential->CredentialBlob,
306                                     credential->CredentialBlobSize);
307     }
308     return ret;
309 }
310
311 static DWORD open_cred_mgr_key(HKEY *hkey, BOOL open_for_write)
312 {
313     return RegCreateKeyExW(HKEY_CURRENT_USER, wszCredentialManagerKey, 0,
314                            NULL, REG_OPTION_NON_VOLATILE,
315                            KEY_READ | KEY_WRITE, NULL, hkey, NULL);
316 }
317
318 static DWORD get_cred_mgr_encryption_key(HKEY hkeyMgr, BYTE key_data[KEY_SIZE])
319 {
320     static const BYTE my_key_data[KEY_SIZE] = { 0 };
321     DWORD type;
322     DWORD count;
323     FILETIME ft;
324     ULONG seed;
325     ULONG value;
326     DWORD ret;
327
328     memcpy(key_data, my_key_data, KEY_SIZE);
329
330     count = KEY_SIZE;
331     ret = RegQueryValueExW(hkeyMgr, wszEncryptionKeyValue, NULL, &type, (LPVOID)key_data,
332                            &count);
333     if (ret == ERROR_SUCCESS)
334     {
335         if (type != REG_BINARY)
336             return ERROR_REGISTRY_CORRUPT;
337         else
338             return ERROR_SUCCESS;
339     }
340     if (ret != ERROR_FILE_NOT_FOUND)
341         return ret;
342
343     GetSystemTimeAsFileTime(&ft);
344     seed = ft.dwLowDateTime;
345     value = RtlUniform(&seed);
346     *(DWORD *)key_data = value;
347     seed = ft.dwHighDateTime;
348     value = RtlUniform(&seed);
349     *(DWORD *)(key_data + 4) = value;
350
351     return RegSetValueExW(hkeyMgr, wszEncryptionKeyValue, 0, REG_BINARY,
352                           (LPVOID)key_data, KEY_SIZE);
353 }
354
355 static LPWSTR get_key_name_for_target(LPCWSTR target_name, DWORD type)
356 {
357     static const WCHAR wszGenericPrefix[] = {'G','e','n','e','r','i','c',':',' ',0};
358     static const WCHAR wszDomPasswdPrefix[] = {'D','o','m','P','a','s','s','w','d',':',' ',0};
359     INT len;
360     LPCWSTR prefix = NULL;
361     LPWSTR key_name, p;
362
363     len = strlenW(target_name);
364     if (type == CRED_TYPE_GENERIC)
365     {
366         prefix = wszGenericPrefix;
367         len += sizeof(wszGenericPrefix)/sizeof(wszGenericPrefix[0]);
368     }
369     else
370     {
371         prefix = wszDomPasswdPrefix;
372         len += sizeof(wszDomPasswdPrefix)/sizeof(wszDomPasswdPrefix[0]);
373     }
374
375     key_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
376     if (!key_name) return NULL;
377
378     strcpyW(key_name, prefix);
379     strcatW(key_name, target_name);
380
381     for (p = key_name; *p; p++)
382         if (*p == '\\') *p = '_';
383
384     return key_name;
385 }
386
387 static void convert_PCREDENTIALW_to_PCREDENTIALA(const CREDENTIALW *CredentialW, PCREDENTIALA CredentialA, DWORD *len)
388 {
389     char *buffer = (char *)CredentialA + sizeof(CREDENTIALA);
390     INT string_len;
391
392     *len += sizeof(CREDENTIALA);
393     if (!CredentialA)
394     {
395         if (CredentialW->TargetName) *len += WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetName, -1, NULL, 0, NULL, NULL);
396         if (CredentialW->Comment) *len += WideCharToMultiByte(CP_ACP, 0, CredentialW->Comment, -1, NULL, 0, NULL, NULL);
397         *len += CredentialW->CredentialBlobSize;
398         if (CredentialW->TargetAlias) *len += WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetAlias, -1, NULL, 0, NULL, NULL);
399         if (CredentialW->UserName) *len += WideCharToMultiByte(CP_ACP, 0, CredentialW->UserName, -1, NULL, 0, NULL, NULL);
400
401         return;
402     }
403
404     CredentialA->Flags = CredentialW->Flags;
405     CredentialA->Type = CredentialW->Type;
406     if (CredentialW->TargetName)
407     {
408         CredentialA->TargetName = (LPSTR)buffer;
409         string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetName, -1, CredentialA->TargetName, -1, NULL, NULL);
410         buffer += string_len;
411         *len += string_len;
412     }
413     else
414         CredentialA->TargetName = NULL;
415     if (CredentialW->Comment)
416     {
417         CredentialA->Comment = (LPSTR)buffer;
418         string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->Comment, -1, CredentialA->Comment, -1, NULL, NULL);
419         buffer += string_len;
420         *len += string_len;
421     }
422     else
423         CredentialA->Comment = NULL;
424     CredentialA->LastWritten = CredentialW->LastWritten;
425     CredentialA->CredentialBlobSize = CredentialW->CredentialBlobSize;
426     if (CredentialW->CredentialBlobSize)
427     {
428         CredentialA->CredentialBlob =(LPBYTE)buffer;
429         memcpy(CredentialA->CredentialBlob, CredentialW->CredentialBlob,
430                CredentialW->CredentialBlobSize);
431         buffer += CredentialW->CredentialBlobSize;
432         *len += CredentialW->CredentialBlobSize;
433     }
434     else
435         CredentialA->CredentialBlob = NULL;
436     CredentialA->Persist = CredentialW->Persist;
437     CredentialA->AttributeCount = 0;
438     CredentialA->Attributes = NULL; /* FIXME */
439     if (CredentialW->TargetAlias)
440     {
441         CredentialA->TargetAlias = (LPSTR)buffer;
442         string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetAlias, -1, CredentialA->TargetAlias, -1, NULL, NULL);
443         buffer += string_len;
444         *len += string_len;
445     }
446     else
447         CredentialA->TargetAlias = NULL;
448     if (CredentialW->UserName)
449     {
450         CredentialA->UserName = (LPSTR)buffer;
451         string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->UserName, -1, CredentialA->UserName, -1, NULL, NULL);
452         buffer += string_len;
453         *len += string_len;
454     }
455     else
456         CredentialA->UserName = NULL;
457 }
458
459 static void convert_PCREDENTIALA_to_PCREDENTIALW(const CREDENTIALA *CredentialA, PCREDENTIALW CredentialW, DWORD *len)
460 {
461     char *buffer = (char *)CredentialW + sizeof(CREDENTIALW);
462     INT string_len;
463
464     *len += sizeof(CREDENTIALW);
465     if (!CredentialW)
466     {
467         if (CredentialA->TargetName) *len += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetName, -1, NULL, 0);
468         if (CredentialA->Comment) *len += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->Comment, -1, NULL, 0);
469         *len += CredentialA->CredentialBlobSize;
470         if (CredentialA->TargetAlias) *len += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetAlias, -1, NULL, 0);
471         if (CredentialA->UserName) *len += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->UserName, -1, NULL, 0);
472
473         return;
474     }
475
476     CredentialW->Flags = CredentialA->Flags;
477     CredentialW->Type = CredentialA->Type;
478     if (CredentialA->TargetName)
479     {
480         CredentialW->TargetName = (LPWSTR)buffer;
481         string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetName, -1, CredentialW->TargetName, -1);
482         buffer += sizeof(WCHAR) * string_len;
483         *len += sizeof(WCHAR) * string_len;
484     }
485     else
486         CredentialW->TargetName = NULL;
487     if (CredentialA->Comment)
488     {
489         CredentialW->Comment = (LPWSTR)buffer;
490         string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->Comment, -1, CredentialW->Comment, -1);
491         buffer += sizeof(WCHAR) * string_len;
492         *len += sizeof(WCHAR) * string_len;
493     }
494     else
495         CredentialW->Comment = NULL;
496     CredentialW->LastWritten = CredentialA->LastWritten;
497     CredentialW->CredentialBlobSize = CredentialA->CredentialBlobSize;
498     if (CredentialA->CredentialBlobSize)
499     {
500         CredentialW->CredentialBlob =(LPBYTE)buffer;
501         memcpy(CredentialW->CredentialBlob, CredentialA->CredentialBlob,
502                CredentialA->CredentialBlobSize);
503         buffer += CredentialA->CredentialBlobSize;
504         *len += CredentialA->CredentialBlobSize;
505     }
506     else
507         CredentialW->CredentialBlob = NULL;
508     CredentialW->Persist = CredentialA->Persist;
509     CredentialW->AttributeCount = 0;
510     CredentialW->Attributes = NULL; /* FIXME */
511     if (CredentialA->TargetAlias)
512     {
513         CredentialW->TargetAlias = (LPWSTR)buffer;
514         string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetAlias, -1, CredentialW->TargetAlias, -1);
515         buffer += sizeof(WCHAR) * string_len;
516         *len += sizeof(WCHAR) * string_len;
517     }
518     else
519         CredentialW->TargetAlias = NULL;
520     if (CredentialA->UserName)
521     {
522         CredentialW->UserName = (LPWSTR)buffer;
523         string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->UserName, -1, CredentialW->UserName, -1);
524         buffer += sizeof(WCHAR) * string_len;
525         *len += sizeof(WCHAR) * string_len;
526     }
527     else
528         CredentialW->UserName = NULL;
529 }
530
531 /******************************************************************************
532  * CredDeleteA [ADVAPI32.@]
533  */
534 BOOL WINAPI CredDeleteA(LPCSTR TargetName, DWORD Type, DWORD Flags)
535 {
536     LPWSTR TargetNameW;
537     DWORD len;
538     BOOL ret;
539
540     TRACE("(%s, %d, 0x%x)\n", debugstr_a(TargetName), Type, Flags);
541
542     if (!TargetName)
543     {
544         SetLastError(ERROR_INVALID_PARAMETER);
545         return FALSE;
546     }
547
548     len = MultiByteToWideChar(CP_ACP, 0, TargetName, -1, NULL, 0);
549     TargetNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
550     if (!TargetNameW)
551     {
552         SetLastError(ERROR_OUTOFMEMORY);
553         return FALSE;
554     }
555     MultiByteToWideChar(CP_ACP, 0, TargetName, -1, TargetNameW, len);
556
557     ret = CredDeleteW(TargetNameW, Type, Flags);
558
559     HeapFree(GetProcessHeap(), 0, TargetNameW);
560
561     return ret;
562 }
563
564 /******************************************************************************
565  * CredDeleteW [ADVAPI32.@]
566  */
567 BOOL WINAPI CredDeleteW(LPCWSTR TargetName, DWORD Type, DWORD Flags)
568 {
569     HKEY hkeyMgr;
570     DWORD ret;
571     LPWSTR key_name;
572
573     TRACE("(%s, %d, 0x%x)\n", debugstr_w(TargetName), Type, Flags);
574
575     if (!TargetName)
576     {
577         SetLastError(ERROR_INVALID_PARAMETER);
578         return FALSE;
579     }
580
581     if (Type != CRED_TYPE_GENERIC && Type != CRED_TYPE_DOMAIN_PASSWORD)
582     {
583         FIXME("unhandled type %d\n", Type);
584         SetLastError(ERROR_INVALID_PARAMETER);
585         return FALSE;
586     }
587
588     if (Flags)
589     {
590         FIXME("unhandled flags 0x%x\n", Flags);
591         SetLastError(ERROR_INVALID_FLAGS);
592         return FALSE;
593     }
594
595     ret = open_cred_mgr_key(&hkeyMgr, TRUE);
596     if (ret != ERROR_SUCCESS)
597     {
598         WARN("couldn't open/create manager key, error %d\n", ret);
599         SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
600         return FALSE;
601     }
602
603     key_name = get_key_name_for_target(TargetName, Type);
604     ret = RegDeleteKeyW(hkeyMgr, key_name);
605     HeapFree(GetProcessHeap(), 0, key_name);
606     RegCloseKey(hkeyMgr);
607     if (ret != ERROR_SUCCESS)
608     {
609         SetLastError(ERROR_NOT_FOUND);
610         return FALSE;
611     }
612
613     return TRUE;
614 }
615
616 /******************************************************************************
617  * CredEnumerateA [ADVAPI32.@]
618  */
619 BOOL WINAPI CredEnumerateA(LPCSTR Filter, DWORD Flags, DWORD *Count,
620                            PCREDENTIALA **Credentials)
621 {
622     LPWSTR FilterW;
623     PCREDENTIALW *CredentialsW;
624     DWORD i;
625     DWORD len;
626     char *buffer;
627
628     TRACE("(%s, 0x%x, %p, %p)\n", debugstr_a(Filter), Flags, Count, Credentials);
629
630     if (Filter)
631     {
632         len = MultiByteToWideChar(CP_ACP, 0, Filter, -1, NULL, 0);
633         FilterW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
634         if (!FilterW)
635         {
636             SetLastError(ERROR_OUTOFMEMORY);
637             return FALSE;
638         }
639         MultiByteToWideChar(CP_ACP, 0, Filter, -1, FilterW, len);
640     }
641     else
642         FilterW = NULL;
643
644     if (!CredEnumerateW(FilterW, Flags, Count, &CredentialsW))
645     {
646         HeapFree(GetProcessHeap(), 0, FilterW);
647         return FALSE;
648     }
649     HeapFree(GetProcessHeap(), 0, FilterW);
650
651     len = *Count * sizeof(PCREDENTIALA);
652     for (i = 0; i < *Count; i++)
653         convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], NULL, &len);
654
655     *Credentials = HeapAlloc(GetProcessHeap(), 0, len);
656     if (!*Credentials)
657     {
658         CredFree(CredentialsW);
659         SetLastError(ERROR_OUTOFMEMORY);
660         return FALSE;
661     }
662
663     buffer = (char *)&(*Credentials)[*Count];
664     for (i = 0; i < *Count; i++)
665     {
666         len = 0;
667         (*Credentials)[i] = (PCREDENTIALA)buffer;
668         convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], (*Credentials)[i], &len);
669         buffer += len;
670     }
671
672     CredFree(CredentialsW);
673
674     return TRUE;
675 }
676
677 static BOOL credential_matches_filter(HKEY hkeyCred, LPCWSTR filter)
678 {
679     LPWSTR target_name;
680     DWORD ret;
681     DWORD type;
682     DWORD count;
683     LPCWSTR p;
684
685     if (!filter) return TRUE;
686
687     ret = RegQueryValueExW(hkeyCred, NULL, 0, &type, NULL, &count);
688     if (ret != ERROR_SUCCESS)
689         return FALSE;
690     else if (type != REG_SZ)
691         return FALSE;
692
693     target_name = HeapAlloc(GetProcessHeap(), 0, count);
694     if (!target_name)
695         return FALSE;
696     ret = RegQueryValueExW(hkeyCred, NULL, 0, &type, (LPVOID)target_name, &count);
697     if (ret != ERROR_SUCCESS || type != REG_SZ)
698     {
699         HeapFree(GetProcessHeap(), 0, target_name);
700         return FALSE;
701     }
702
703     TRACE("comparing filter %s to target name %s\n", debugstr_w(filter),
704           debugstr_w(target_name));
705
706     p = strchrW(filter, '*');
707     ret = CompareStringW(GetThreadLocale(), 0, filter,
708                          (p && !p[1] ? p - filter : -1), target_name,
709                          (p && !p[1] ? p - filter : -1)) == CSTR_EQUAL;
710
711     HeapFree(GetProcessHeap(), 0, target_name);
712     return ret;
713 }
714
715 /******************************************************************************
716  * CredEnumerateW [ADVAPI32.@]
717  */
718 BOOL WINAPI CredEnumerateW(LPCWSTR Filter, DWORD Flags, DWORD *Count,
719                            PCREDENTIALW **Credentials)
720 {
721     HKEY hkeyMgr;
722     HKEY hkeyCred;
723     DWORD ret;
724     LPWSTR target_name;
725     DWORD target_name_len;
726     DWORD len;
727     char *buffer;
728     DWORD i;
729     BYTE key_data[KEY_SIZE];
730
731     TRACE("(%s, 0x%x, %p, %p)\n", debugstr_w(Filter), Flags, Count, Credentials);
732
733     if (Flags)
734     {
735         SetLastError(ERROR_INVALID_FLAGS);
736         return FALSE;
737     }
738
739     ret = open_cred_mgr_key(&hkeyMgr, FALSE);
740     if (ret != ERROR_SUCCESS)
741     {
742         WARN("couldn't open/create manager key, error %d\n", ret);
743         SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
744         return FALSE;
745     }
746
747     ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
748     if (ret != ERROR_SUCCESS)
749     {
750         RegCloseKey(hkeyMgr);
751         SetLastError(ret);
752         return FALSE;
753     }
754
755     ret = RegQueryInfoKeyW(hkeyMgr, NULL, NULL, NULL, NULL, &target_name_len, NULL, NULL, NULL, NULL, NULL, NULL);
756     if (ret != ERROR_SUCCESS)
757     {
758         RegCloseKey(hkeyMgr);
759         SetLastError(ret);
760         return FALSE;
761     }
762
763     target_name = HeapAlloc(GetProcessHeap(), 0, (target_name_len+1)*sizeof(WCHAR));
764     if (!target_name)
765     {
766         RegCloseKey(hkeyMgr);
767         SetLastError(ERROR_OUTOFMEMORY);
768         return FALSE;
769     }
770
771     *Count = 0;
772     len = 0;
773     for (i = 0;; i++)
774     {
775         ret = RegEnumKeyW(hkeyMgr, i, target_name, target_name_len+1);
776         if (ret == ERROR_NO_MORE_ITEMS)
777         {
778             ret = ERROR_SUCCESS;
779             break;
780         }
781         else if (ret != ERROR_SUCCESS)
782         {
783             ret = ERROR_SUCCESS;
784             continue;
785         }
786         ret = RegOpenKeyExW(hkeyMgr, target_name, 0, KEY_QUERY_VALUE, &hkeyCred);
787         if (ret != ERROR_SUCCESS)
788         {
789             ret = ERROR_SUCCESS;
790             continue;
791         }
792         if (!credential_matches_filter(hkeyCred, Filter))
793         {
794             RegCloseKey(hkeyCred);
795             continue;
796         }
797         len += sizeof(CREDENTIALW);
798         ret = read_credential(hkeyCred, NULL, key_data, NULL, &len);
799         RegCloseKey(hkeyCred);
800         if (ret != ERROR_SUCCESS) break;
801         (*Count)++;
802     }
803     if (ret == ERROR_SUCCESS && *Count == 0)
804         ret = ERROR_NOT_FOUND;
805     if (ret != ERROR_SUCCESS)
806     {
807         HeapFree(GetProcessHeap(), 0, target_name);
808         RegCloseKey(hkeyMgr);
809         SetLastError(ret);
810         return FALSE;
811     }
812     len += *Count + sizeof(PCREDENTIALW);
813
814     if (ret == ERROR_SUCCESS)
815     {
816         buffer = HeapAlloc(GetProcessHeap(), 0, len);
817         *Credentials = (PCREDENTIALW *)buffer;
818         if (buffer)
819         {
820             buffer += *Count * sizeof(PCREDENTIALW);
821             *Count = 0;
822             for (i = 0;; i++)
823             {
824                 ret = RegEnumKeyW(hkeyMgr, i, target_name, target_name_len+1);
825                 if (ret == ERROR_NO_MORE_ITEMS)
826                 {
827                     ret = ERROR_SUCCESS;
828                     break;
829                 }
830                 else if (ret != ERROR_SUCCESS)
831                 {
832                     ret = ERROR_SUCCESS;
833                     continue;
834                 }
835                 TRACE("target_name = %s\n", debugstr_w(target_name));
836                 ret = RegOpenKeyExW(hkeyMgr, target_name, 0, KEY_QUERY_VALUE, &hkeyCred);
837                 if (ret != ERROR_SUCCESS)
838                 {
839                     ret = ERROR_SUCCESS;
840                     continue;
841                 }
842                 if (!credential_matches_filter(hkeyCred, Filter))
843                 {
844                     RegCloseKey(hkeyCred);
845                     continue;
846                 }
847                 len = sizeof(CREDENTIALW);
848                 (*Credentials)[*Count] = (PCREDENTIALW)buffer;
849                 ret = read_credential(hkeyCred, (*Credentials)[*Count],
850                                       key_data,
851                                       buffer + sizeof(CREDENTIALW), &len);
852                 RegCloseKey(hkeyCred);
853                 if (ret != ERROR_SUCCESS) break;
854                 buffer += len;
855                 (*Count)++;
856             }
857         }
858         else
859             ret = ERROR_OUTOFMEMORY;
860     }
861
862     HeapFree(GetProcessHeap(), 0, target_name);
863     RegCloseKey(hkeyMgr);
864
865     if (ret != ERROR_SUCCESS)
866     {
867         SetLastError(ret);
868         return FALSE;
869     }
870     return TRUE;
871 }
872
873 /******************************************************************************
874  * CredFree [ADVAPI32.@]
875  */
876 VOID WINAPI CredFree(PVOID Buffer)
877 {
878     HeapFree(GetProcessHeap(), 0, Buffer);
879 }
880
881 /******************************************************************************
882  * CredReadA [ADVAPI32.@]
883  */
884 BOOL WINAPI CredReadA(LPCSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALA *Credential)
885 {
886     LPWSTR TargetNameW;
887     PCREDENTIALW CredentialW;
888     DWORD len;
889
890     TRACE("(%s, %d, 0x%x, %p)\n", debugstr_a(TargetName), Type, Flags, Credential);
891
892     if (!TargetName)
893     {
894         SetLastError(ERROR_INVALID_PARAMETER);
895         return FALSE;
896     }
897
898     len = MultiByteToWideChar(CP_ACP, 0, TargetName, -1, NULL, 0);
899     TargetNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
900     if (!TargetNameW)
901     {
902         SetLastError(ERROR_OUTOFMEMORY);
903         return FALSE;
904     }
905     MultiByteToWideChar(CP_ACP, 0, TargetName, -1, TargetNameW, len);
906
907     if (!CredReadW(TargetNameW, Type, Flags, &CredentialW))
908     {
909         HeapFree(GetProcessHeap(), 0, TargetNameW);
910         return FALSE;
911     }
912     HeapFree(GetProcessHeap(), 0, TargetNameW);
913
914     len = 0;
915     convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW, NULL, &len);
916     *Credential = HeapAlloc(GetProcessHeap(), 0, len);
917     if (!*Credential)
918     {
919         SetLastError(ERROR_OUTOFMEMORY);
920         return FALSE;
921     }
922     len = 0;
923     convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW, *Credential, &len);
924
925     CredFree(CredentialW);
926
927     return TRUE;
928 }
929
930 /******************************************************************************
931  * CredReadW [ADVAPI32.@]
932  */
933 BOOL WINAPI CredReadW(LPCWSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALW *Credential)
934 {
935     HKEY hkeyMgr;
936     HKEY hkeyCred;
937     DWORD ret;
938     LPWSTR key_name;
939     DWORD len;
940     BYTE key_data[KEY_SIZE];
941
942     TRACE("(%s, %d, 0x%x, %p)\n", debugstr_w(TargetName), Type, Flags, Credential);
943
944     if (!TargetName)
945     {
946         SetLastError(ERROR_INVALID_PARAMETER);
947         return FALSE;
948     }
949
950     if (Type != CRED_TYPE_GENERIC && Type != CRED_TYPE_DOMAIN_PASSWORD)
951     {
952         FIXME("unhandled type %d\n", Type);
953         SetLastError(ERROR_INVALID_PARAMETER);
954         return FALSE;
955     }
956
957     if (Flags)
958     {
959         FIXME("unhandled flags 0x%x\n", Flags);
960         SetLastError(ERROR_INVALID_FLAGS);
961         return FALSE;
962     }
963
964     ret = open_cred_mgr_key(&hkeyMgr, FALSE);
965     if (ret != ERROR_SUCCESS)
966     {
967         WARN("couldn't open/create manager key, error %d\n", ret);
968         SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
969         return FALSE;
970     }
971
972     ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
973     if (ret != ERROR_SUCCESS)
974     {
975         RegCloseKey(hkeyMgr);
976         SetLastError(ret);
977         return FALSE;
978     }
979
980     key_name = get_key_name_for_target(TargetName, Type);
981     ret = RegOpenKeyExW(hkeyMgr, key_name, 0, KEY_QUERY_VALUE, &hkeyCred);
982     HeapFree(GetProcessHeap(), 0, key_name);
983     if (ret != ERROR_SUCCESS)
984     {
985         TRACE("credentials for target name %s not found\n", debugstr_w(TargetName));
986         SetLastError(ERROR_NOT_FOUND);
987         return FALSE;
988     }
989
990     len = sizeof(**Credential);
991     ret = read_credential(hkeyCred, NULL, key_data, NULL, &len);
992     if (ret == ERROR_SUCCESS)
993     {
994         *Credential = HeapAlloc(GetProcessHeap(), 0, len);
995         if (*Credential)
996         {
997             len = sizeof(**Credential);
998             ret = read_credential(hkeyCred, *Credential, key_data,
999                                   (char *)(*Credential + 1), &len);
1000         }
1001         else
1002             ret = ERROR_OUTOFMEMORY;
1003     }
1004
1005     RegCloseKey(hkeyCred);
1006     RegCloseKey(hkeyMgr);
1007
1008     if (ret != ERROR_SUCCESS)
1009     {
1010         SetLastError(ret);
1011         return FALSE;
1012     }
1013     return TRUE;
1014 }
1015
1016 /******************************************************************************
1017  * CredWriteA [ADVAPI32.@]
1018  */
1019 BOOL WINAPI CredWriteA(PCREDENTIALA Credential, DWORD Flags)
1020 {
1021     BOOL ret;
1022     DWORD len;
1023     PCREDENTIALW CredentialW;
1024
1025     TRACE("(%p, 0x%x)\n", Credential, Flags);
1026
1027     if (!Credential || !Credential->TargetName)
1028     {
1029         SetLastError(ERROR_INVALID_PARAMETER);
1030         return FALSE;
1031     }
1032
1033     len = 0;
1034     convert_PCREDENTIALA_to_PCREDENTIALW(Credential, NULL, &len);
1035     CredentialW = HeapAlloc(GetProcessHeap(), 0, len);
1036     if (!CredentialW)
1037     {
1038         SetLastError(ERROR_OUTOFMEMORY);
1039         return FALSE;
1040     }
1041     len = 0;
1042     convert_PCREDENTIALA_to_PCREDENTIALW(Credential, CredentialW, &len);
1043
1044     ret = CredWriteW(CredentialW, Flags);
1045
1046     HeapFree(GetProcessHeap(), 0, CredentialW);
1047
1048     return ret;
1049 }
1050
1051 /******************************************************************************
1052  * CredWriteW [ADVAPI32.@]
1053  */
1054 BOOL WINAPI CredWriteW(PCREDENTIALW Credential, DWORD Flags)
1055 {
1056     HKEY hkeyMgr;
1057     HKEY hkeyCred;
1058     DWORD ret;
1059     LPWSTR key_name;
1060     BYTE key_data[KEY_SIZE];
1061
1062     TRACE("(%p, 0x%x)\n", Credential, Flags);
1063
1064     if (!Credential || !Credential->TargetName)
1065     {
1066         SetLastError(ERROR_INVALID_PARAMETER);
1067         return FALSE;
1068     }
1069
1070     if (Flags & ~CRED_PRESERVE_CREDENTIAL_BLOB)
1071     {
1072         FIXME("unhandled flags 0x%x\n", Flags);
1073         SetLastError(ERROR_INVALID_FLAGS);
1074         return FALSE;
1075     }
1076
1077     if (Credential->Type != CRED_TYPE_GENERIC && Credential->Type != CRED_TYPE_DOMAIN_PASSWORD)
1078     {
1079         FIXME("unhandled type %d\n", Credential->Type);
1080         SetLastError(ERROR_INVALID_PARAMETER);
1081         return FALSE;
1082     }
1083
1084     TRACE("Credential->TargetName = %s\n", debugstr_w(Credential->TargetName));
1085     TRACE("Credential->UserName = %s\n", debugstr_w(Credential->UserName));
1086
1087     if (Credential->Type == CRED_TYPE_DOMAIN_PASSWORD)
1088     {
1089         if (!Credential->UserName ||
1090             (!strchrW(Credential->UserName, '\\') && !strchrW(Credential->UserName, '@')))
1091         {
1092             ERR("bad username %s\n", debugstr_w(Credential->UserName));
1093             SetLastError(ERROR_BAD_USERNAME);
1094             return FALSE;
1095         }
1096     }
1097
1098     ret = open_cred_mgr_key(&hkeyMgr, FALSE);
1099     if (ret != ERROR_SUCCESS)
1100     {
1101         WARN("couldn't open/create manager key, error %d\n", ret);
1102         SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1103         return FALSE;
1104     }
1105
1106     ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
1107     if (ret != ERROR_SUCCESS)
1108     {
1109         RegCloseKey(hkeyMgr);
1110         SetLastError(ret);
1111         return FALSE;
1112     }
1113
1114     key_name = get_key_name_for_target(Credential->TargetName, Credential->Type);
1115     ret = RegCreateKeyExW(hkeyMgr, key_name, 0, NULL, REG_OPTION_VOLATILE,
1116                           KEY_READ|KEY_WRITE, NULL, &hkeyCred, NULL);
1117     HeapFree(GetProcessHeap(), 0, key_name);
1118     if (ret != ERROR_SUCCESS)
1119     {
1120         TRACE("credentials for target name %s not found\n",
1121               debugstr_w(Credential->TargetName));
1122         SetLastError(ERROR_NOT_FOUND);
1123         return FALSE;
1124     }
1125
1126     ret = write_credential(hkeyCred, Credential, key_data,
1127                            Flags & CRED_PRESERVE_CREDENTIAL_BLOB);
1128
1129     RegCloseKey(hkeyCred);
1130     RegCloseKey(hkeyMgr);
1131
1132     if (ret != ERROR_SUCCESS)
1133     {
1134         SetLastError(ret);
1135         return FALSE;
1136     }
1137     return TRUE;
1138 }