xref: /reactos/dll/win32/advapi32/wine/cred.c (revision abc90fa5)
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 #ifdef __REACTOS__
22 #include <advapi32.h>
23 
24 #include <wincred.h>
25 #else
26 #include <stdarg.h>
27 #include <time.h>
28 #include <limits.h>
29 
30 #ifdef __APPLE__
31 # include <Security/SecKeychain.h>
32 # include <Security/SecKeychainItem.h>
33 # include <Security/SecKeychainSearch.h>
34 #endif
35 
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winreg.h"
39 #include "wincred.h"
40 #include "winternl.h"
41 
42 #include "crypt.h"
43 
44 #include "wine/unicode.h"
45 #include "wine/debug.h"
46 
47 #include "advapi32_misc.h"
48 #endif /* __REACTOS__ */
49 
50 WINE_DEFAULT_DEBUG_CHANNEL(cred);
51 
52 /* the size of the ARC4 key used to encrypt the password data */
53 #define KEY_SIZE 8
54 
55 static const WCHAR wszCredentialManagerKey[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
56     'C','r','e','d','e','n','t','i','a','l',' ','M','a','n','a','g','e','r',0};
57 static const WCHAR wszEncryptionKeyValue[] = {'E','n','c','r','y','p','t','i','o','n','K','e','y',0};
58 
59 static const WCHAR wszFlagsValue[] = {'F','l','a','g','s',0};
60 static const WCHAR wszTypeValue[] = {'T','y','p','e',0};
61 static const WCHAR wszCommentValue[] = {'C','o','m','m','e','n','t',0};
62 static const WCHAR wszLastWrittenValue[] = {'L','a','s','t','W','r','i','t','t','e','n',0};
63 static const WCHAR wszPersistValue[] = {'P','e','r','s','i','s','t',0};
64 static const WCHAR wszTargetAliasValue[] = {'T','a','r','g','e','t','A','l','i','a','s',0};
65 static const WCHAR wszUserNameValue[] = {'U','s','e','r','N','a','m','e',0};
66 static const WCHAR wszPasswordValue[] = {'P','a','s','s','w','o','r','d',0};
67 
read_credential_blob(HKEY hkey,const BYTE key_data[KEY_SIZE],LPBYTE credential_blob,DWORD * credential_blob_size)68 static DWORD read_credential_blob(HKEY hkey, const BYTE key_data[KEY_SIZE],
69                                   LPBYTE credential_blob,
70                                   DWORD *credential_blob_size)
71 {
72     DWORD ret;
73     DWORD type;
74 
75     *credential_blob_size = 0;
76     ret = RegQueryValueExW(hkey, wszPasswordValue, 0, &type, NULL, credential_blob_size);
77     if (ret != ERROR_SUCCESS)
78         return ret;
79     else if (type != REG_BINARY)
80         return ERROR_REGISTRY_CORRUPT;
81     if (credential_blob)
82     {
83         struct ustring data;
84         struct ustring key;
85 
86         ret = RegQueryValueExW(hkey, wszPasswordValue, 0, &type, credential_blob,
87                                credential_blob_size);
88         if (ret != ERROR_SUCCESS)
89             return ret;
90         else if (type != REG_BINARY)
91             return ERROR_REGISTRY_CORRUPT;
92 
93         key.Length = key.MaximumLength = KEY_SIZE;
94         key.Buffer = (unsigned char *)key_data;
95 
96         data.Length = data.MaximumLength = *credential_blob_size;
97         data.Buffer = credential_blob;
98         SystemFunction032(&data, &key);
99     }
100     return ERROR_SUCCESS;
101 }
102 
registry_read_credential(HKEY hkey,PCREDENTIALW credential,const BYTE key_data[KEY_SIZE],char * buffer,DWORD * len)103 static DWORD registry_read_credential(HKEY hkey, PCREDENTIALW credential,
104                                       const BYTE key_data[KEY_SIZE],
105                                       char *buffer, DWORD *len)
106 {
107     DWORD type;
108     DWORD ret;
109     DWORD count;
110 
111     ret = RegQueryValueExW(hkey, NULL, 0, &type, NULL, &count);
112     if (ret != ERROR_SUCCESS)
113         return ret;
114     else if (type != REG_SZ)
115         return ERROR_REGISTRY_CORRUPT;
116     *len += count;
117     if (credential)
118     {
119         credential->TargetName = (LPWSTR)buffer;
120         ret = RegQueryValueExW(hkey, NULL, 0, &type, (LPVOID)credential->TargetName,
121                                &count);
122 #ifdef __REACTOS__
123         if (ret != ERROR_SUCCESS)
124             return ret;
125         else if (type != REG_SZ)
126             return ERROR_REGISTRY_CORRUPT;
127 #else
128         if (ret != ERROR_SUCCESS || type != REG_SZ) return ret;
129 #endif
130         buffer += count;
131     }
132 
133     ret = RegQueryValueExW(hkey, wszCommentValue, 0, &type, NULL, &count);
134 #ifdef __REACTOS__
135     if (ret != ERROR_FILE_NOT_FOUND)
136     {
137         if (ret != ERROR_SUCCESS)
138             return ret;
139         else if (type != REG_SZ)
140             return ERROR_REGISTRY_CORRUPT;
141         *len += count;
142     }
143 #else
144     if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
145         return ret;
146     else if (type != REG_SZ)
147         return ERROR_REGISTRY_CORRUPT;
148     *len += count;
149 #endif
150     if (credential)
151     {
152         credential->Comment = (LPWSTR)buffer;
153         ret = RegQueryValueExW(hkey, wszCommentValue, 0, &type, (LPVOID)credential->Comment,
154                                &count);
155         if (ret == ERROR_FILE_NOT_FOUND)
156             credential->Comment = NULL;
157         else if (ret != ERROR_SUCCESS)
158             return ret;
159         else if (type != REG_SZ)
160             return ERROR_REGISTRY_CORRUPT;
161         else
162             buffer += count;
163     }
164 
165     ret = RegQueryValueExW(hkey, wszTargetAliasValue, 0, &type, NULL, &count);
166 #ifdef __REACTOS__
167     if (ret != ERROR_FILE_NOT_FOUND)
168     {
169         if (ret != ERROR_SUCCESS)
170             return ret;
171         else if (type != REG_SZ)
172             return ERROR_REGISTRY_CORRUPT;
173         *len += count;
174     }
175 #else
176     if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
177         return ret;
178     else if (type != REG_SZ)
179         return ERROR_REGISTRY_CORRUPT;
180     *len += count;
181 #endif
182     if (credential)
183     {
184         credential->TargetAlias = (LPWSTR)buffer;
185         ret = RegQueryValueExW(hkey, wszTargetAliasValue, 0, &type, (LPVOID)credential->TargetAlias,
186                                &count);
187         if (ret == ERROR_FILE_NOT_FOUND)
188             credential->TargetAlias = NULL;
189         else if (ret != ERROR_SUCCESS)
190             return ret;
191         else if (type != REG_SZ)
192             return ERROR_REGISTRY_CORRUPT;
193         else
194             buffer += count;
195     }
196 
197     ret = RegQueryValueExW(hkey, wszUserNameValue, 0, &type, NULL, &count);
198 #ifdef __REACTOS__
199     if (ret != ERROR_FILE_NOT_FOUND)
200     {
201         if (ret != ERROR_SUCCESS)
202             return ret;
203         else if (type != REG_SZ)
204             return ERROR_REGISTRY_CORRUPT;
205         *len += count;
206     }
207 #else
208     if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
209         return ret;
210     else if (type != REG_SZ)
211         return ERROR_REGISTRY_CORRUPT;
212     *len += count;
213 #endif
214     if (credential)
215     {
216         credential->UserName = (LPWSTR)buffer;
217         ret = RegQueryValueExW(hkey, wszUserNameValue, 0, &type, (LPVOID)credential->UserName,
218                                &count);
219         if (ret == ERROR_FILE_NOT_FOUND)
220             credential->UserName = NULL;
221         else if (ret != ERROR_SUCCESS)
222             return ret;
223         else if (type != REG_SZ)
224             return ERROR_REGISTRY_CORRUPT;
225         else
226             buffer += count;
227     }
228 
229     ret = read_credential_blob(hkey, key_data, NULL, &count);
230 #ifdef __REACTOS__
231     if (ret != ERROR_FILE_NOT_FOUND)
232     {
233         if (ret != ERROR_SUCCESS)
234             return ret;
235         *len += count;
236     }
237 #else
238     if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
239         return ret;
240     *len += count;
241 #endif
242     if (credential)
243     {
244         credential->CredentialBlob = (LPBYTE)buffer;
245         ret = read_credential_blob(hkey, key_data, credential->CredentialBlob, &count);
246         if (ret == ERROR_FILE_NOT_FOUND)
247             credential->CredentialBlob = NULL;
248         else if (ret != ERROR_SUCCESS)
249             return ret;
250         credential->CredentialBlobSize = count;
251     }
252 
253     /* FIXME: Attributes */
254     if (credential)
255     {
256         credential->AttributeCount = 0;
257         credential->Attributes = NULL;
258     }
259 
260     if (!credential) return ERROR_SUCCESS;
261 
262     count = sizeof(credential->Flags);
263     ret = RegQueryValueExW(hkey, wszFlagsValue, NULL, &type, (LPVOID)&credential->Flags,
264                            &count);
265     if (ret != ERROR_SUCCESS)
266         return ret;
267     else if (type != REG_DWORD)
268         return ERROR_REGISTRY_CORRUPT;
269     count = sizeof(credential->Type);
270     ret = RegQueryValueExW(hkey, wszTypeValue, NULL, &type, (LPVOID)&credential->Type,
271                            &count);
272     if (ret != ERROR_SUCCESS)
273         return ret;
274     else if (type != REG_DWORD)
275         return ERROR_REGISTRY_CORRUPT;
276 
277     count = sizeof(credential->LastWritten);
278     ret = RegQueryValueExW(hkey, wszLastWrittenValue, NULL, &type, (LPVOID)&credential->LastWritten,
279                            &count);
280     if (ret != ERROR_SUCCESS)
281         return ret;
282     else if (type != REG_BINARY)
283         return ERROR_REGISTRY_CORRUPT;
284     count = sizeof(credential->Persist);
285     ret = RegQueryValueExW(hkey, wszPersistValue, NULL, &type, (LPVOID)&credential->Persist,
286                            &count);
287     if (ret == ERROR_SUCCESS && type != REG_DWORD)
288         return ERROR_REGISTRY_CORRUPT;
289     return ret;
290 }
291 
292 #ifdef __APPLE__
mac_read_credential_from_item(SecKeychainItemRef item,BOOL require_password,PCREDENTIALW credential,char * buffer,DWORD * len)293 static DWORD mac_read_credential_from_item(SecKeychainItemRef item, BOOL require_password,
294                                            PCREDENTIALW credential, char *buffer,
295                                            DWORD *len)
296 {
297     int status;
298     UInt32 i, cred_blob_len;
299     void *cred_blob;
300     WCHAR *user = NULL;
301     BOOL user_name_present = FALSE;
302     SecKeychainAttributeInfo info;
303     SecKeychainAttributeList *attr_list;
304     UInt32 info_tags[] = { kSecServiceItemAttr, kSecAccountItemAttr,
305                            kSecCommentItemAttr, kSecCreationDateItemAttr };
306     info.count = sizeof(info_tags)/sizeof(info_tags[0]);
307     info.tag = info_tags;
308     info.format = NULL;
309     status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, &cred_blob_len, &cred_blob);
310     if (status == errSecAuthFailed && !require_password)
311     {
312         cred_blob_len = 0;
313         cred_blob = NULL;
314         status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, &cred_blob_len, NULL);
315     }
316     if (status != noErr)
317     {
318         WARN("SecKeychainItemCopyAttributesAndData returned status %d\n", status);
319         return ERROR_NOT_FOUND;
320     }
321 
322     for (i = 0; i < attr_list->count; i++)
323         if (attr_list->attr[i].tag == kSecAccountItemAttr && attr_list->attr[i].data)
324         {
325             user_name_present = TRUE;
326             break;
327         }
328     if (!user_name_present)
329     {
330         WARN("no kSecAccountItemAttr for item\n");
331         SecKeychainItemFreeAttributesAndData(attr_list, cred_blob);
332         return ERROR_NOT_FOUND;
333     }
334 
335     if (buffer)
336     {
337         credential->Flags = 0;
338         credential->Type = CRED_TYPE_DOMAIN_PASSWORD;
339         credential->TargetName = NULL;
340         credential->Comment = NULL;
341         memset(&credential->LastWritten, 0, sizeof(credential->LastWritten));
342         credential->CredentialBlobSize = 0;
343         credential->CredentialBlob = NULL;
344         credential->Persist = CRED_PERSIST_LOCAL_MACHINE;
345         credential->AttributeCount = 0;
346         credential->Attributes = NULL;
347         credential->TargetAlias = NULL;
348         credential->UserName = NULL;
349     }
350     for (i = 0; i < attr_list->count; i++)
351     {
352         switch (attr_list->attr[i].tag)
353         {
354             case kSecServiceItemAttr:
355                 TRACE("kSecServiceItemAttr: %.*s\n", (int)attr_list->attr[i].length,
356                       (char *)attr_list->attr[i].data);
357                 if (!attr_list->attr[i].data) continue;
358                 if (buffer)
359                 {
360                     INT str_len;
361                     credential->TargetName = (LPWSTR)buffer;
362                     str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
363                                                   attr_list->attr[i].length, (LPWSTR)buffer, 0xffff);
364                     credential->TargetName[str_len] = '\0';
365                     buffer += (str_len + 1) * sizeof(WCHAR);
366                     *len += (str_len + 1) * sizeof(WCHAR);
367                 }
368                 else
369                 {
370                     INT str_len;
371                     str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
372                                                   attr_list->attr[i].length, NULL, 0);
373                     *len += (str_len + 1) * sizeof(WCHAR);
374                 }
375                 break;
376             case kSecAccountItemAttr:
377             {
378                 INT str_len;
379                 TRACE("kSecAccountItemAttr: %.*s\n", (int)attr_list->attr[i].length,
380                       (char *)attr_list->attr[i].data);
381                 if (!attr_list->attr[i].data) continue;
382                 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
383                                               attr_list->attr[i].length, NULL, 0);
384                 user = heap_alloc((str_len + 1) * sizeof(WCHAR));
385                 MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
386                                     attr_list->attr[i].length, user, str_len);
387                 user[str_len] = '\0';
388                 break;
389             }
390             case kSecCommentItemAttr:
391                 TRACE("kSecCommentItemAttr: %.*s\n", (int)attr_list->attr[i].length,
392                       (char *)attr_list->attr[i].data);
393                 if (!attr_list->attr[i].data) continue;
394                 if (buffer)
395                 {
396                     INT str_len;
397                     credential->Comment = (LPWSTR)buffer;
398                     str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
399                                                   attr_list->attr[i].length, (LPWSTR)buffer, 0xffff);
400                     credential->Comment[str_len] = '\0';
401                     buffer += (str_len + 1) * sizeof(WCHAR);
402                     *len += (str_len + 1) * sizeof(WCHAR);
403                 }
404                 else
405                 {
406                     INT str_len;
407                     str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
408                                                   attr_list->attr[i].length, NULL, 0);
409                     *len += (str_len + 1) * sizeof(WCHAR);
410                 }
411                 break;
412             case kSecCreationDateItemAttr:
413                 TRACE("kSecCreationDateItemAttr: %.*s\n", (int)attr_list->attr[i].length,
414                       (char *)attr_list->attr[i].data);
415                 if (!attr_list->attr[i].data) continue;
416                 if (buffer)
417                 {
418                     LARGE_INTEGER win_time;
419                     struct tm tm;
420                     time_t time;
421                     memset(&tm, 0, sizeof(tm));
422                     strptime(attr_list->attr[i].data, "%Y%m%d%H%M%SZ", &tm);
423                     time = mktime(&tm);
424                     RtlSecondsSince1970ToTime(time, &win_time);
425                     credential->LastWritten.dwLowDateTime = win_time.u.LowPart;
426                     credential->LastWritten.dwHighDateTime = win_time.u.HighPart;
427                 }
428                 break;
429             default:
430                 FIXME("unhandled attribute %u\n", (unsigned)attr_list->attr[i].tag);
431                 break;
432         }
433     }
434 
435     if (user)
436     {
437         INT str_len;
438         if (buffer)
439             credential->UserName = (LPWSTR)buffer;
440         str_len = strlenW(user);
441         *len += (str_len + 1) * sizeof(WCHAR);
442         if (buffer)
443         {
444             memcpy(buffer, user, (str_len + 1) * sizeof(WCHAR));
445             buffer += (str_len + 1) * sizeof(WCHAR);
446             TRACE("UserName = %s\n", debugstr_w(credential->UserName));
447         }
448     }
449     heap_free(user);
450 
451     if (cred_blob)
452     {
453         if (buffer)
454         {
455             INT str_len;
456             credential->CredentialBlob = (BYTE *)buffer;
457             str_len = MultiByteToWideChar(CP_UTF8, 0, cred_blob, cred_blob_len,
458                                           (LPWSTR)buffer, 0xffff);
459             credential->CredentialBlobSize = str_len * sizeof(WCHAR);
460             *len += str_len * sizeof(WCHAR);
461         }
462         else
463         {
464             INT str_len;
465             str_len = MultiByteToWideChar(CP_UTF8, 0, cred_blob, cred_blob_len,
466                                           NULL, 0);
467             *len += str_len * sizeof(WCHAR);
468         }
469     }
470     SecKeychainItemFreeAttributesAndData(attr_list, cred_blob);
471     return ERROR_SUCCESS;
472 }
473 #endif
474 
write_credential_blob(HKEY hkey,LPCWSTR target_name,DWORD type,const BYTE key_data[KEY_SIZE],const BYTE * credential_blob,DWORD credential_blob_size)475 static DWORD write_credential_blob(HKEY hkey, LPCWSTR target_name, DWORD type,
476                                    const BYTE key_data[KEY_SIZE],
477                                    const BYTE *credential_blob, DWORD credential_blob_size)
478 {
479     LPBYTE encrypted_credential_blob;
480     struct ustring data;
481     struct ustring key;
482     DWORD ret;
483 
484     key.Length = key.MaximumLength = KEY_SIZE;
485     key.Buffer = (unsigned char *)key_data;
486 
487     encrypted_credential_blob = heap_alloc(credential_blob_size);
488     if (!encrypted_credential_blob) return ERROR_OUTOFMEMORY;
489 
490     memcpy(encrypted_credential_blob, credential_blob, credential_blob_size);
491     data.Length = data.MaximumLength = credential_blob_size;
492     data.Buffer = encrypted_credential_blob;
493     SystemFunction032(&data, &key);
494 
495     ret = RegSetValueExW(hkey, wszPasswordValue, 0, REG_BINARY, encrypted_credential_blob, credential_blob_size);
496     heap_free(encrypted_credential_blob);
497 
498     return ret;
499 }
500 
registry_write_credential(HKEY hkey,const CREDENTIALW * credential,const BYTE key_data[KEY_SIZE],BOOL preserve_blob)501 static DWORD registry_write_credential(HKEY hkey, const CREDENTIALW *credential,
502                                        const BYTE key_data[KEY_SIZE], BOOL preserve_blob)
503 {
504     DWORD ret;
505     FILETIME LastWritten;
506 
507     GetSystemTimeAsFileTime(&LastWritten);
508 
509     ret = RegSetValueExW(hkey, wszFlagsValue, 0, REG_DWORD, (const BYTE*)&credential->Flags,
510                          sizeof(credential->Flags));
511     if (ret != ERROR_SUCCESS) return ret;
512     ret = RegSetValueExW(hkey, wszTypeValue, 0, REG_DWORD, (const BYTE*)&credential->Type,
513                          sizeof(credential->Type));
514     if (ret != ERROR_SUCCESS) return ret;
515     ret = RegSetValueExW(hkey, NULL, 0, REG_SZ, (LPVOID)credential->TargetName,
516                          sizeof(WCHAR)*(strlenW(credential->TargetName)+1));
517     if (ret != ERROR_SUCCESS) return ret;
518     if (credential->Comment)
519     {
520         ret = RegSetValueExW(hkey, wszCommentValue, 0, REG_SZ, (LPVOID)credential->Comment,
521                              sizeof(WCHAR)*(strlenW(credential->Comment)+1));
522         if (ret != ERROR_SUCCESS) return ret;
523     }
524     ret = RegSetValueExW(hkey, wszLastWrittenValue, 0, REG_BINARY, (LPVOID)&LastWritten,
525                          sizeof(LastWritten));
526     if (ret != ERROR_SUCCESS) return ret;
527     ret = RegSetValueExW(hkey, wszPersistValue, 0, REG_DWORD, (const BYTE*)&credential->Persist,
528                          sizeof(credential->Persist));
529     if (ret != ERROR_SUCCESS) return ret;
530     /* FIXME: Attributes */
531     if (credential->TargetAlias)
532     {
533         ret = RegSetValueExW(hkey, wszTargetAliasValue, 0, REG_SZ, (LPVOID)credential->TargetAlias,
534                              sizeof(WCHAR)*(strlenW(credential->TargetAlias)+1));
535         if (ret != ERROR_SUCCESS) return ret;
536     }
537     if (credential->UserName)
538     {
539         ret = RegSetValueExW(hkey, wszUserNameValue, 0, REG_SZ, (LPVOID)credential->UserName,
540                              sizeof(WCHAR)*(strlenW(credential->UserName)+1));
541         if (ret != ERROR_SUCCESS) return ret;
542     }
543     if (!preserve_blob)
544     {
545         ret = write_credential_blob(hkey, credential->TargetName, credential->Type,
546                                     key_data, credential->CredentialBlob,
547                                     credential->CredentialBlobSize);
548     }
549     return ret;
550 }
551 
552 #ifdef __APPLE__
mac_write_credential(const CREDENTIALW * credential,BOOL preserve_blob)553 static DWORD mac_write_credential(const CREDENTIALW *credential, BOOL preserve_blob)
554 {
555     int status;
556     SecKeychainItemRef keychain_item;
557     char *username, *password, *servername;
558     UInt32 userlen, pwlen, serverlen;
559     SecKeychainAttribute attrs[1];
560     SecKeychainAttributeList attr_list;
561 
562     if (credential->Flags)
563         FIXME("Flags 0x%x not written\n", credential->Flags);
564     if (credential->Type != CRED_TYPE_DOMAIN_PASSWORD)
565         FIXME("credential type of %d not supported\n", credential->Type);
566     if (credential->Persist != CRED_PERSIST_LOCAL_MACHINE)
567         FIXME("persist value of %d not supported\n", credential->Persist);
568     if (credential->AttributeCount)
569         FIXME("custom attributes not supported\n");
570 
571     userlen = WideCharToMultiByte(CP_UTF8, 0, credential->UserName, -1, NULL, 0, NULL, NULL);
572     username = heap_alloc(userlen * sizeof(*username));
573     WideCharToMultiByte(CP_UTF8, 0, credential->UserName, -1, username, userlen, NULL, NULL);
574 
575     serverlen = WideCharToMultiByte(CP_UTF8, 0, credential->TargetName, -1, NULL, 0, NULL, NULL);
576     servername = heap_alloc(serverlen * sizeof(*servername));
577     WideCharToMultiByte(CP_UTF8, 0, credential->TargetName, -1, servername, serverlen, NULL, NULL);
578     pwlen = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)credential->CredentialBlob,
579                                 credential->CredentialBlobSize / sizeof(WCHAR), NULL, 0, NULL, NULL);
580     password = heap_alloc(pwlen * sizeof(*password));
581     WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)credential->CredentialBlob,
582                         credential->CredentialBlobSize / sizeof(WCHAR), password, pwlen, NULL, NULL);
583 
584     TRACE("adding server %s, username %s using Keychain\n", servername, username);
585     status = SecKeychainAddGenericPassword(NULL, strlen(servername), servername, strlen(username),
586                                            username, strlen(password), password, &keychain_item);
587     if (status != noErr)
588         ERR("SecKeychainAddGenericPassword returned %d\n", status);
589     if (status == errSecDuplicateItem)
590     {
591         status = SecKeychainFindGenericPassword(NULL, strlen(servername), servername, strlen(username),
592                                                 username, NULL, NULL, &keychain_item);
593         if (status != noErr)
594             ERR("SecKeychainFindGenericPassword returned %d\n", status);
595     }
596     heap_free(username);
597     heap_free(servername);
598     if (status != noErr)
599     {
600         heap_free(password);
601         return ERROR_GEN_FAILURE;
602     }
603     if (credential->Comment)
604     {
605         attr_list.count = 1;
606         attr_list.attr = attrs;
607         attrs[0].tag = kSecCommentItemAttr;
608         attrs[0].length = WideCharToMultiByte(CP_UTF8, 0, credential->Comment, -1, NULL, 0, NULL, NULL);
609         if (attrs[0].length) attrs[0].length--;
610         attrs[0].data = heap_alloc(attrs[0].length);
611         WideCharToMultiByte(CP_UTF8, 0, credential->Comment, -1, attrs[0].data, attrs[0].length, NULL, NULL);
612     }
613     else
614     {
615         attr_list.count = 0;
616         attr_list.attr = NULL;
617     }
618     status = SecKeychainItemModifyAttributesAndData(keychain_item, &attr_list,
619                                                     preserve_blob ? 0 : strlen(password),
620                                                     preserve_blob ? NULL : password);
621     if (credential->Comment)
622         heap_free(attrs[0].data);
623     heap_free(password);
624     /* FIXME: set TargetAlias attribute */
625     CFRelease(keychain_item);
626     if (status != noErr)
627         return ERROR_GEN_FAILURE;
628     return ERROR_SUCCESS;
629 }
630 #endif
631 
open_cred_mgr_key(HKEY * hkey,BOOL open_for_write)632 static DWORD open_cred_mgr_key(HKEY *hkey, BOOL open_for_write)
633 {
634     return RegCreateKeyExW(HKEY_CURRENT_USER, wszCredentialManagerKey, 0,
635                            NULL, REG_OPTION_NON_VOLATILE,
636                            KEY_READ | (open_for_write ? KEY_WRITE : 0), NULL, hkey, NULL);
637 }
638 
get_cred_mgr_encryption_key(HKEY hkeyMgr,BYTE key_data[KEY_SIZE])639 static DWORD get_cred_mgr_encryption_key(HKEY hkeyMgr, BYTE key_data[KEY_SIZE])
640 {
641     static const BYTE my_key_data[KEY_SIZE] = { 0 };
642     DWORD type;
643     DWORD count;
644     FILETIME ft;
645     ULONG seed;
646     ULONG value;
647     DWORD ret;
648 
649     memcpy(key_data, my_key_data, KEY_SIZE);
650 
651     count = KEY_SIZE;
652     ret = RegQueryValueExW(hkeyMgr, wszEncryptionKeyValue, NULL, &type, key_data,
653                            &count);
654     if (ret == ERROR_SUCCESS)
655     {
656         if (type != REG_BINARY)
657             return ERROR_REGISTRY_CORRUPT;
658         else
659             return ERROR_SUCCESS;
660     }
661     if (ret != ERROR_FILE_NOT_FOUND)
662         return ret;
663 
664     GetSystemTimeAsFileTime(&ft);
665     seed = ft.dwLowDateTime;
666     value = RtlUniform(&seed);
667     *(DWORD *)key_data = value;
668     seed = ft.dwHighDateTime;
669     value = RtlUniform(&seed);
670     *(DWORD *)(key_data + 4) = value;
671 
672     ret = RegSetValueExW(hkeyMgr, wszEncryptionKeyValue, 0, REG_BINARY,
673                          key_data, KEY_SIZE);
674     if (ret == ERROR_ACCESS_DENIED)
675     {
676         ret = open_cred_mgr_key(&hkeyMgr, TRUE);
677         if (ret == ERROR_SUCCESS)
678         {
679             ret = RegSetValueExW(hkeyMgr, wszEncryptionKeyValue, 0, REG_BINARY,
680                                  key_data, KEY_SIZE);
681             RegCloseKey(hkeyMgr);
682         }
683     }
684     return ret;
685 }
686 
get_key_name_for_target(LPCWSTR target_name,DWORD type)687 static LPWSTR get_key_name_for_target(LPCWSTR target_name, DWORD type)
688 {
689     static const WCHAR wszGenericPrefix[] = {'G','e','n','e','r','i','c',':',' ',0};
690     static const WCHAR wszDomPasswdPrefix[] = {'D','o','m','P','a','s','s','w','d',':',' ',0};
691     INT len;
692     LPCWSTR prefix = NULL;
693     LPWSTR key_name, p;
694 
695     len = strlenW(target_name);
696     if (type == CRED_TYPE_GENERIC)
697     {
698         prefix = wszGenericPrefix;
699         len += sizeof(wszGenericPrefix)/sizeof(wszGenericPrefix[0]);
700     }
701     else
702     {
703         prefix = wszDomPasswdPrefix;
704         len += sizeof(wszDomPasswdPrefix)/sizeof(wszDomPasswdPrefix[0]);
705     }
706 
707     key_name = heap_alloc(len * sizeof(WCHAR));
708     if (!key_name) return NULL;
709 
710     strcpyW(key_name, prefix);
711     strcatW(key_name, target_name);
712 
713     for (p = key_name; *p; p++)
714         if (*p == '\\') *p = '_';
715 
716     return key_name;
717 }
718 
registry_credential_matches_filter(HKEY hkeyCred,LPCWSTR filter)719 static BOOL registry_credential_matches_filter(HKEY hkeyCred, LPCWSTR filter)
720 {
721     LPWSTR target_name;
722     DWORD ret;
723     DWORD type;
724     DWORD count;
725     LPCWSTR p;
726 
727     if (!filter) return TRUE;
728 
729     ret = RegQueryValueExW(hkeyCred, NULL, 0, &type, NULL, &count);
730     if (ret != ERROR_SUCCESS)
731         return FALSE;
732     else if (type != REG_SZ)
733         return FALSE;
734 
735     target_name = heap_alloc(count);
736     if (!target_name)
737         return FALSE;
738     ret = RegQueryValueExW(hkeyCred, NULL, 0, &type, (LPVOID)target_name, &count);
739     if (ret != ERROR_SUCCESS || type != REG_SZ)
740     {
741         heap_free(target_name);
742         return FALSE;
743     }
744 
745     TRACE("comparing filter %s to target name %s\n", debugstr_w(filter),
746           debugstr_w(target_name));
747 
748     p = strchrW(filter, '*');
749     ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, filter,
750                          (p && !p[1] ? p - filter : -1), target_name,
751                          (p && !p[1] ? p - filter : -1)) == CSTR_EQUAL;
752 
753     heap_free(target_name);
754     return ret;
755 }
756 
registry_enumerate_credentials(HKEY hkeyMgr,LPCWSTR filter,LPWSTR target_name,DWORD target_name_len,const BYTE key_data[KEY_SIZE],PCREDENTIALW * credentials,char ** buffer,DWORD * len,DWORD * count)757 static DWORD registry_enumerate_credentials(HKEY hkeyMgr, LPCWSTR filter,
758                                             LPWSTR target_name,
759                                             DWORD target_name_len, const BYTE key_data[KEY_SIZE],
760                                             PCREDENTIALW *credentials, char **buffer,
761                                             DWORD *len, DWORD *count)
762 {
763     DWORD i;
764     DWORD ret;
765     for (i = 0;; i++)
766     {
767         HKEY hkeyCred;
768         ret = RegEnumKeyW(hkeyMgr, i, target_name, target_name_len+1);
769         if (ret == ERROR_NO_MORE_ITEMS)
770         {
771             ret = ERROR_SUCCESS;
772             break;
773         }
774         else if (ret != ERROR_SUCCESS)
775             continue;
776         TRACE("target_name = %s\n", debugstr_w(target_name));
777         ret = RegOpenKeyExW(hkeyMgr, target_name, 0, KEY_QUERY_VALUE, &hkeyCred);
778         if (ret != ERROR_SUCCESS)
779             continue;
780         if (!registry_credential_matches_filter(hkeyCred, filter))
781         {
782             RegCloseKey(hkeyCred);
783             continue;
784         }
785         if (buffer)
786         {
787             *len = sizeof(CREDENTIALW);
788             credentials[*count] = (PCREDENTIALW)*buffer;
789         }
790         else
791             *len += sizeof(CREDENTIALW);
792         ret = registry_read_credential(hkeyCred, buffer ? credentials[*count] : NULL,
793                                        key_data, buffer ? *buffer + sizeof(CREDENTIALW) : NULL,
794                                        len);
795         RegCloseKey(hkeyCred);
796         if (ret != ERROR_SUCCESS) break;
797         if (buffer) *buffer += *len;
798         (*count)++;
799     }
800     return ret;
801 }
802 
803 #ifdef __APPLE__
mac_credential_matches_filter(void * data,UInt32 data_len,const WCHAR * filter)804 static BOOL mac_credential_matches_filter(void *data, UInt32 data_len, const WCHAR *filter)
805 {
806     int len;
807     WCHAR *target_name;
808     const WCHAR *p;
809     BOOL ret;
810 
811     if (!filter) return TRUE;
812 
813     len = MultiByteToWideChar(CP_UTF8, 0, data, data_len, NULL, 0);
814     if (!(target_name = heap_alloc((len + 1) * sizeof(WCHAR)))) return FALSE;
815     MultiByteToWideChar(CP_UTF8, 0, data, data_len, target_name, len);
816     target_name[len] = 0;
817 
818     TRACE("comparing filter %s to target name %s\n", debugstr_w(filter), debugstr_w(target_name));
819 
820     p = strchrW(filter, '*');
821     ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, filter,
822                          (p && !p[1] ? p - filter : -1), target_name,
823                          (p && !p[1] ? p - filter : -1)) == CSTR_EQUAL;
824     heap_free(target_name);
825     return ret;
826 }
827 
mac_enumerate_credentials(LPCWSTR filter,PCREDENTIALW * credentials,char * buffer,DWORD * len,DWORD * count)828 static DWORD mac_enumerate_credentials(LPCWSTR filter, PCREDENTIALW *credentials,
829                                        char *buffer, DWORD *len, DWORD *count)
830 {
831     SecKeychainSearchRef search;
832     SecKeychainItemRef item;
833     int status;
834     Boolean saved_user_interaction_allowed;
835     DWORD ret;
836 
837     SecKeychainGetUserInteractionAllowed(&saved_user_interaction_allowed);
838     SecKeychainSetUserInteractionAllowed(false);
839 
840     status = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, NULL, &search);
841     if (status == noErr)
842     {
843         while (SecKeychainSearchCopyNext(search, &item) == noErr)
844         {
845             SecKeychainAttributeInfo info;
846             SecKeychainAttributeList *attr_list;
847             UInt32 info_tags[] = { kSecServiceItemAttr };
848             BOOL match;
849 
850             info.count = sizeof(info_tags)/sizeof(info_tags[0]);
851             info.tag = info_tags;
852             info.format = NULL;
853             status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, NULL, NULL);
854             if (status != noErr)
855             {
856                 WARN("SecKeychainItemCopyAttributesAndData returned status %d\n", status);
857                 continue;
858             }
859             if (buffer)
860             {
861                 *len = sizeof(CREDENTIALW);
862                 credentials[*count] = (PCREDENTIALW)buffer;
863             }
864             else
865                 *len += sizeof(CREDENTIALW);
866             if (attr_list->count != 1 || attr_list->attr[0].tag != kSecServiceItemAttr)
867             {
868                 SecKeychainItemFreeAttributesAndData(attr_list, NULL);
869                 continue;
870             }
871             TRACE("service item: %.*s\n", (int)attr_list->attr[0].length, (char *)attr_list->attr[0].data);
872             match = mac_credential_matches_filter(attr_list->attr[0].data, attr_list->attr[0].length, filter);
873             SecKeychainItemFreeAttributesAndData(attr_list, NULL);
874             if (!match) continue;
875             ret = mac_read_credential_from_item(item, FALSE,
876                                                 buffer ? credentials[*count] : NULL,
877                                                 buffer ? buffer + sizeof(CREDENTIALW) : NULL,
878                                                 len);
879             CFRelease(item);
880             if (ret == ERROR_SUCCESS)
881             {
882                 (*count)++;
883                 if (buffer) buffer += *len;
884             }
885         }
886         CFRelease(search);
887     }
888     else
889         ERR("SecKeychainSearchCreateFromAttributes returned status %d\n", status);
890     SecKeychainSetUserInteractionAllowed(saved_user_interaction_allowed);
891     return ERROR_SUCCESS;
892 }
893 
mac_delete_credential(LPCWSTR TargetName)894 static DWORD mac_delete_credential(LPCWSTR TargetName)
895 {
896     int status;
897     SecKeychainSearchRef search;
898     status = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, NULL, &search);
899     if (status == noErr)
900     {
901         SecKeychainItemRef item;
902         while (SecKeychainSearchCopyNext(search, &item) == noErr)
903         {
904             SecKeychainAttributeInfo info;
905             SecKeychainAttributeList *attr_list;
906             UInt32 info_tags[] = { kSecServiceItemAttr };
907             LPWSTR target_name;
908             INT str_len;
909             info.count = sizeof(info_tags)/sizeof(info_tags[0]);
910             info.tag = info_tags;
911             info.format = NULL;
912             status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, NULL, NULL);
913             if (status != noErr)
914             {
915                 WARN("SecKeychainItemCopyAttributesAndData returned status %d\n", status);
916                 continue;
917             }
918             if (attr_list->count != 1 || attr_list->attr[0].tag != kSecServiceItemAttr)
919             {
920                 CFRelease(item);
921                 continue;
922             }
923             str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, NULL, 0);
924             target_name = heap_alloc((str_len + 1) * sizeof(WCHAR));
925             MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, target_name, str_len);
926             /* nul terminate */
927             target_name[str_len] = '\0';
928             if (strcmpiW(TargetName, target_name))
929             {
930                 CFRelease(item);
931                 heap_free(target_name);
932                 continue;
933             }
934             heap_free(target_name);
935             SecKeychainItemFreeAttributesAndData(attr_list, NULL);
936             SecKeychainItemDelete(item);
937             CFRelease(item);
938             CFRelease(search);
939 
940             return ERROR_SUCCESS;
941         }
942         CFRelease(search);
943     }
944     return ERROR_NOT_FOUND;
945 }
946 #endif
947 
948 /******************************************************************************
949  * convert_PCREDENTIALW_to_PCREDENTIALA [internal]
950  *
951  * convert a Credential struct from UNICODE to ANSI and return the needed size in Bytes
952  *
953  */
954 
convert_PCREDENTIALW_to_PCREDENTIALA(const CREDENTIALW * CredentialW,PCREDENTIALA CredentialA,DWORD len)955 static INT convert_PCREDENTIALW_to_PCREDENTIALA(const CREDENTIALW *CredentialW, PCREDENTIALA CredentialA, DWORD len)
956 {
957     char *buffer;
958     INT string_len;
959     INT needed = sizeof(CREDENTIALA);
960 
961     if (!CredentialA)
962     {
963         if (CredentialW->TargetName)
964             needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetName, -1, NULL, 0, NULL, NULL);
965         if (CredentialW->Comment)
966             needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->Comment, -1, NULL, 0, NULL, NULL);
967         needed += CredentialW->CredentialBlobSize;
968         if (CredentialW->TargetAlias)
969             needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetAlias, -1, NULL, 0, NULL, NULL);
970         if (CredentialW->UserName)
971             needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->UserName, -1, NULL, 0, NULL, NULL);
972 
973         return needed;
974     }
975 
976 
977     buffer = (char *)CredentialA + sizeof(CREDENTIALA);
978     len -= sizeof(CREDENTIALA);
979     CredentialA->Flags = CredentialW->Flags;
980     CredentialA->Type = CredentialW->Type;
981 
982     if (CredentialW->TargetName)
983     {
984         CredentialA->TargetName = buffer;
985         string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetName, -1, buffer, len, NULL, NULL);
986         buffer += string_len;
987         needed += string_len;
988         len -= string_len;
989     }
990     else
991         CredentialA->TargetName = NULL;
992     if (CredentialW->Comment)
993     {
994         CredentialA->Comment = buffer;
995         string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->Comment, -1, buffer, len, NULL, NULL);
996         buffer += string_len;
997         needed += string_len;
998         len -= string_len;
999     }
1000     else
1001         CredentialA->Comment = NULL;
1002     CredentialA->LastWritten = CredentialW->LastWritten;
1003     CredentialA->CredentialBlobSize = CredentialW->CredentialBlobSize;
1004     if (CredentialW->CredentialBlobSize && (CredentialW->CredentialBlobSize <= len))
1005     {
1006         CredentialA->CredentialBlob =(LPBYTE)buffer;
1007         memcpy(CredentialA->CredentialBlob, CredentialW->CredentialBlob,
1008                CredentialW->CredentialBlobSize);
1009         buffer += CredentialW->CredentialBlobSize;
1010         needed += CredentialW->CredentialBlobSize;
1011         len -= CredentialW->CredentialBlobSize;
1012     }
1013     else
1014         CredentialA->CredentialBlob = NULL;
1015     CredentialA->Persist = CredentialW->Persist;
1016     CredentialA->AttributeCount = 0;
1017     CredentialA->Attributes = NULL; /* FIXME */
1018     if (CredentialW->TargetAlias)
1019     {
1020         CredentialA->TargetAlias = buffer;
1021         string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetAlias, -1, buffer, len, NULL, NULL);
1022         buffer += string_len;
1023         needed += string_len;
1024         len -= string_len;
1025     }
1026     else
1027         CredentialA->TargetAlias = NULL;
1028     if (CredentialW->UserName)
1029     {
1030         CredentialA->UserName = buffer;
1031         string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->UserName, -1, buffer, len, NULL, NULL);
1032         needed += string_len;
1033     }
1034     else
1035         CredentialA->UserName = NULL;
1036 
1037     return needed;
1038 }
1039 
1040 /******************************************************************************
1041  * convert_PCREDENTIALA_to_PCREDENTIALW [internal]
1042  *
1043  * convert a Credential struct from ANSI to UNICODE and return the needed size in Bytes
1044  *
1045  */
convert_PCREDENTIALA_to_PCREDENTIALW(const CREDENTIALA * CredentialA,PCREDENTIALW CredentialW,INT len)1046 static INT convert_PCREDENTIALA_to_PCREDENTIALW(const CREDENTIALA *CredentialA, PCREDENTIALW CredentialW, INT len)
1047 {
1048     char *buffer;
1049     INT string_len;
1050     INT needed = sizeof(CREDENTIALW);
1051 
1052     if (!CredentialW)
1053     {
1054         if (CredentialA->TargetName)
1055             needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetName, -1, NULL, 0);
1056         if (CredentialA->Comment)
1057             needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->Comment, -1, NULL, 0);
1058         needed += CredentialA->CredentialBlobSize;
1059         if (CredentialA->TargetAlias)
1060             needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetAlias, -1, NULL, 0);
1061         if (CredentialA->UserName)
1062             needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->UserName, -1, NULL, 0);
1063 
1064         return needed;
1065     }
1066 
1067     buffer = (char *)CredentialW + sizeof(CREDENTIALW);
1068     len -= sizeof(CREDENTIALW);
1069     CredentialW->Flags = CredentialA->Flags;
1070     CredentialW->Type = CredentialA->Type;
1071     if (CredentialA->TargetName)
1072     {
1073         CredentialW->TargetName = (LPWSTR)buffer;
1074         string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetName, -1, CredentialW->TargetName, len / sizeof(WCHAR));
1075         buffer += sizeof(WCHAR) * string_len;
1076         needed += sizeof(WCHAR) * string_len;
1077         len -= sizeof(WCHAR) * string_len;
1078     }
1079     else
1080         CredentialW->TargetName = NULL;
1081     if (CredentialA->Comment)
1082     {
1083         CredentialW->Comment = (LPWSTR)buffer;
1084         string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->Comment, -1, CredentialW->Comment, len / sizeof(WCHAR));
1085         buffer += sizeof(WCHAR) * string_len;
1086         needed += sizeof(WCHAR) * string_len;
1087         len -= sizeof(WCHAR) * string_len;
1088     }
1089     else
1090         CredentialW->Comment = NULL;
1091     CredentialW->LastWritten = CredentialA->LastWritten;
1092     CredentialW->CredentialBlobSize = CredentialA->CredentialBlobSize;
1093     if (CredentialA->CredentialBlobSize)
1094     {
1095         CredentialW->CredentialBlob =(LPBYTE)buffer;
1096         memcpy(CredentialW->CredentialBlob, CredentialA->CredentialBlob,
1097                CredentialA->CredentialBlobSize);
1098         buffer += CredentialA->CredentialBlobSize;
1099         needed += CredentialA->CredentialBlobSize;
1100         len -= CredentialA->CredentialBlobSize;
1101     }
1102     else
1103         CredentialW->CredentialBlob = NULL;
1104     CredentialW->Persist = CredentialA->Persist;
1105     CredentialW->AttributeCount = 0;
1106     CredentialW->Attributes = NULL; /* FIXME */
1107     if (CredentialA->TargetAlias)
1108     {
1109         CredentialW->TargetAlias = (LPWSTR)buffer;
1110         string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetAlias, -1, CredentialW->TargetAlias, len / sizeof(WCHAR));
1111         buffer += sizeof(WCHAR) * string_len;
1112         needed += sizeof(WCHAR) * string_len;
1113         len -= sizeof(WCHAR) * string_len;
1114     }
1115     else
1116         CredentialW->TargetAlias = NULL;
1117     if (CredentialA->UserName)
1118     {
1119         CredentialW->UserName = (LPWSTR)buffer;
1120         string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->UserName, -1, CredentialW->UserName, len / sizeof(WCHAR));
1121         needed += sizeof(WCHAR) * string_len;
1122     }
1123     else
1124         CredentialW->UserName = NULL;
1125 
1126     return needed;
1127 }
1128 
1129 /******************************************************************************
1130  * CredDeleteA [ADVAPI32.@]
1131  */
CredDeleteA(LPCSTR TargetName,DWORD Type,DWORD Flags)1132 BOOL WINAPI CredDeleteA(LPCSTR TargetName, DWORD Type, DWORD Flags)
1133 {
1134     LPWSTR TargetNameW;
1135     DWORD len;
1136     BOOL ret;
1137 
1138     TRACE("(%s, %d, 0x%x)\n", debugstr_a(TargetName), Type, Flags);
1139 
1140     if (!TargetName)
1141     {
1142         SetLastError(ERROR_INVALID_PARAMETER);
1143         return FALSE;
1144     }
1145 
1146     len = MultiByteToWideChar(CP_ACP, 0, TargetName, -1, NULL, 0);
1147     TargetNameW = heap_alloc(len * sizeof(WCHAR));
1148     if (!TargetNameW)
1149     {
1150         SetLastError(ERROR_OUTOFMEMORY);
1151         return FALSE;
1152     }
1153     MultiByteToWideChar(CP_ACP, 0, TargetName, -1, TargetNameW, len);
1154 
1155     ret = CredDeleteW(TargetNameW, Type, Flags);
1156 
1157     heap_free(TargetNameW);
1158 
1159     return ret;
1160 }
1161 
1162 /******************************************************************************
1163  * CredDeleteW [ADVAPI32.@]
1164  */
CredDeleteW(LPCWSTR TargetName,DWORD Type,DWORD Flags)1165 BOOL WINAPI CredDeleteW(LPCWSTR TargetName, DWORD Type, DWORD Flags)
1166 {
1167     HKEY hkeyMgr;
1168     DWORD ret;
1169     LPWSTR key_name;
1170 
1171     TRACE("(%s, %d, 0x%x)\n", debugstr_w(TargetName), Type, Flags);
1172 
1173     if (!TargetName)
1174     {
1175         SetLastError(ERROR_INVALID_PARAMETER);
1176         return FALSE;
1177     }
1178 
1179     if (Type != CRED_TYPE_GENERIC && Type != CRED_TYPE_DOMAIN_PASSWORD)
1180     {
1181         FIXME("unhandled type %d\n", Type);
1182         SetLastError(ERROR_INVALID_PARAMETER);
1183         return FALSE;
1184     }
1185 
1186     if (Flags)
1187     {
1188         FIXME("unhandled flags 0x%x\n", Flags);
1189         SetLastError(ERROR_INVALID_FLAGS);
1190         return FALSE;
1191     }
1192 
1193 #ifdef __APPLE__
1194     if (Type == CRED_TYPE_DOMAIN_PASSWORD)
1195     {
1196         ret = mac_delete_credential(TargetName);
1197         if (ret == ERROR_SUCCESS)
1198             return TRUE;
1199     }
1200 #endif
1201 
1202     ret = open_cred_mgr_key(&hkeyMgr, TRUE);
1203     if (ret != ERROR_SUCCESS)
1204     {
1205         WARN("couldn't open/create manager key, error %d\n", ret);
1206         SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1207         return FALSE;
1208     }
1209 
1210     key_name = get_key_name_for_target(TargetName, Type);
1211     ret = RegDeleteKeyW(hkeyMgr, key_name);
1212     heap_free(key_name);
1213     RegCloseKey(hkeyMgr);
1214     if (ret != ERROR_SUCCESS)
1215     {
1216         SetLastError(ERROR_NOT_FOUND);
1217         return FALSE;
1218     }
1219 
1220     return TRUE;
1221 }
1222 
1223 /******************************************************************************
1224  * CredEnumerateA [ADVAPI32.@]
1225  */
CredEnumerateA(LPCSTR Filter,DWORD Flags,DWORD * Count,PCREDENTIALA ** Credentials)1226 BOOL WINAPI CredEnumerateA(LPCSTR Filter, DWORD Flags, DWORD *Count,
1227                            PCREDENTIALA **Credentials)
1228 {
1229     LPWSTR FilterW;
1230     PCREDENTIALW *CredentialsW;
1231     DWORD i;
1232     INT len;
1233     INT needed;
1234     char *buffer;
1235 
1236     TRACE("(%s, 0x%x, %p, %p)\n", debugstr_a(Filter), Flags, Count, Credentials);
1237 
1238     if (Filter)
1239     {
1240         len = MultiByteToWideChar(CP_ACP, 0, Filter, -1, NULL, 0);
1241         FilterW = heap_alloc(len * sizeof(WCHAR));
1242         if (!FilterW)
1243         {
1244             SetLastError(ERROR_OUTOFMEMORY);
1245             return FALSE;
1246         }
1247         MultiByteToWideChar(CP_ACP, 0, Filter, -1, FilterW, len);
1248     }
1249     else
1250         FilterW = NULL;
1251 
1252     if (!CredEnumerateW(FilterW, Flags, Count, &CredentialsW))
1253     {
1254         heap_free(FilterW);
1255         return FALSE;
1256     }
1257     heap_free(FilterW);
1258 
1259     len = *Count * sizeof(PCREDENTIALA);
1260     for (i = 0; i < *Count; i++)
1261         len += convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], NULL, 0);
1262 
1263     *Credentials = heap_alloc(len);
1264     if (!*Credentials)
1265     {
1266         CredFree(CredentialsW);
1267         SetLastError(ERROR_OUTOFMEMORY);
1268         return FALSE;
1269     }
1270 
1271     buffer = (char *)&(*Credentials)[*Count];
1272     len -= *Count * sizeof(PCREDENTIALA);
1273     for (i = 0; i < *Count; i++)
1274     {
1275         (*Credentials)[i] = (PCREDENTIALA)buffer;
1276         needed = convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], (*Credentials)[i], len);
1277         buffer += needed;
1278         len -= needed;
1279     }
1280 
1281     CredFree(CredentialsW);
1282 
1283     return TRUE;
1284 }
1285 
1286 /******************************************************************************
1287  * CredEnumerateW [ADVAPI32.@]
1288  */
CredEnumerateW(LPCWSTR Filter,DWORD Flags,DWORD * Count,PCREDENTIALW ** Credentials)1289 BOOL WINAPI CredEnumerateW(LPCWSTR Filter, DWORD Flags, DWORD *Count,
1290                            PCREDENTIALW **Credentials)
1291 {
1292     HKEY hkeyMgr;
1293     DWORD ret;
1294     LPWSTR target_name;
1295     DWORD target_name_len;
1296     DWORD len;
1297     char *buffer;
1298     BYTE key_data[KEY_SIZE];
1299 
1300     TRACE("(%s, 0x%x, %p, %p)\n", debugstr_w(Filter), Flags, Count, Credentials);
1301 
1302     if (Flags)
1303     {
1304         SetLastError(ERROR_INVALID_FLAGS);
1305         return FALSE;
1306     }
1307 
1308     ret = open_cred_mgr_key(&hkeyMgr, FALSE);
1309     if (ret != ERROR_SUCCESS)
1310     {
1311         WARN("couldn't open/create manager key, error %d\n", ret);
1312         SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1313         return FALSE;
1314     }
1315 
1316     ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
1317     if (ret != ERROR_SUCCESS)
1318     {
1319         RegCloseKey(hkeyMgr);
1320         SetLastError(ret);
1321         return FALSE;
1322     }
1323 
1324     ret = RegQueryInfoKeyW(hkeyMgr, NULL, NULL, NULL, NULL, &target_name_len, NULL, NULL, NULL, NULL, NULL, NULL);
1325     if (ret != ERROR_SUCCESS)
1326     {
1327         RegCloseKey(hkeyMgr);
1328         SetLastError(ret);
1329         return FALSE;
1330     }
1331 
1332     target_name = heap_alloc((target_name_len+1)*sizeof(WCHAR));
1333     if (!target_name)
1334     {
1335         RegCloseKey(hkeyMgr);
1336         SetLastError(ERROR_OUTOFMEMORY);
1337         return FALSE;
1338     }
1339 
1340     *Count = 0;
1341     len = 0;
1342     ret = registry_enumerate_credentials(hkeyMgr, Filter, target_name, target_name_len,
1343                                          key_data, NULL, NULL, &len, Count);
1344 #ifdef __APPLE__
1345     if (ret == ERROR_SUCCESS)
1346         ret = mac_enumerate_credentials(Filter, NULL, NULL, &len, Count);
1347 #endif
1348     if (ret == ERROR_SUCCESS && *Count == 0)
1349         ret = ERROR_NOT_FOUND;
1350     if (ret != ERROR_SUCCESS)
1351     {
1352         heap_free(target_name);
1353         RegCloseKey(hkeyMgr);
1354         SetLastError(ret);
1355         return FALSE;
1356     }
1357     len += *Count * sizeof(PCREDENTIALW);
1358 
1359     if (ret == ERROR_SUCCESS)
1360     {
1361         buffer = heap_alloc(len);
1362         *Credentials = (PCREDENTIALW *)buffer;
1363         if (buffer)
1364         {
1365             buffer += *Count * sizeof(PCREDENTIALW);
1366             *Count = 0;
1367             ret = registry_enumerate_credentials(hkeyMgr, Filter, target_name,
1368                                                  target_name_len, key_data,
1369                                                  *Credentials, &buffer, &len,
1370                                                  Count);
1371 #ifdef __APPLE__
1372             if (ret == ERROR_SUCCESS)
1373                 ret = mac_enumerate_credentials(Filter, *Credentials,
1374                                                 buffer, &len, Count);
1375 #endif
1376         }
1377         else
1378             ret = ERROR_OUTOFMEMORY;
1379     }
1380 
1381     heap_free(target_name);
1382     RegCloseKey(hkeyMgr);
1383 
1384     if (ret != ERROR_SUCCESS)
1385     {
1386         SetLastError(ret);
1387         return FALSE;
1388     }
1389     return TRUE;
1390 }
1391 
1392 /******************************************************************************
1393  * CredFree [ADVAPI32.@]
1394  */
CredFree(PVOID Buffer)1395 VOID WINAPI CredFree(PVOID Buffer)
1396 {
1397     heap_free(Buffer);
1398 }
1399 
1400 /******************************************************************************
1401  * CredReadA [ADVAPI32.@]
1402  */
CredReadA(LPCSTR TargetName,DWORD Type,DWORD Flags,PCREDENTIALA * Credential)1403 BOOL WINAPI CredReadA(LPCSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALA *Credential)
1404 {
1405     LPWSTR TargetNameW;
1406     PCREDENTIALW CredentialW;
1407     INT len;
1408 
1409     TRACE("(%s, %d, 0x%x, %p)\n", debugstr_a(TargetName), Type, Flags, Credential);
1410 
1411     if (!TargetName)
1412     {
1413         SetLastError(ERROR_INVALID_PARAMETER);
1414         return FALSE;
1415     }
1416 
1417     len = MultiByteToWideChar(CP_ACP, 0, TargetName, -1, NULL, 0);
1418     TargetNameW = heap_alloc(len * sizeof(WCHAR));
1419     if (!TargetNameW)
1420     {
1421         SetLastError(ERROR_OUTOFMEMORY);
1422         return FALSE;
1423     }
1424     MultiByteToWideChar(CP_ACP, 0, TargetName, -1, TargetNameW, len);
1425 
1426     if (!CredReadW(TargetNameW, Type, Flags, &CredentialW))
1427     {
1428         heap_free(TargetNameW);
1429         return FALSE;
1430     }
1431     heap_free(TargetNameW);
1432 
1433     len = convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW, NULL, 0);
1434     *Credential = heap_alloc(len);
1435     if (!*Credential)
1436     {
1437         SetLastError(ERROR_OUTOFMEMORY);
1438         return FALSE;
1439     }
1440     convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW, *Credential, len);
1441 
1442     CredFree(CredentialW);
1443 
1444     return TRUE;
1445 }
1446 
1447 /******************************************************************************
1448  * CredReadW [ADVAPI32.@]
1449  */
CredReadW(LPCWSTR TargetName,DWORD Type,DWORD Flags,PCREDENTIALW * Credential)1450 BOOL WINAPI CredReadW(LPCWSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALW *Credential)
1451 {
1452     HKEY hkeyMgr;
1453     HKEY hkeyCred;
1454     DWORD ret;
1455     LPWSTR key_name;
1456     DWORD len;
1457     BYTE key_data[KEY_SIZE];
1458 
1459     TRACE("(%s, %d, 0x%x, %p)\n", debugstr_w(TargetName), Type, Flags, Credential);
1460 
1461     if (!TargetName)
1462     {
1463         SetLastError(ERROR_INVALID_PARAMETER);
1464         return FALSE;
1465     }
1466 
1467     if (Type != CRED_TYPE_GENERIC && Type != CRED_TYPE_DOMAIN_PASSWORD)
1468     {
1469         FIXME("unhandled type %d\n", Type);
1470         SetLastError(ERROR_INVALID_PARAMETER);
1471         return FALSE;
1472     }
1473 
1474     if (Flags)
1475     {
1476         FIXME("unhandled flags 0x%x\n", Flags);
1477         SetLastError(ERROR_INVALID_FLAGS);
1478         return FALSE;
1479     }
1480 
1481 #ifdef __APPLE__
1482     if (Type == CRED_TYPE_DOMAIN_PASSWORD)
1483     {
1484         int status;
1485         SecKeychainSearchRef search;
1486         status = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, NULL, &search);
1487         if (status == noErr)
1488         {
1489             SecKeychainItemRef item;
1490             while (SecKeychainSearchCopyNext(search, &item) == noErr)
1491             {
1492                 SecKeychainAttributeInfo info;
1493                 SecKeychainAttributeList *attr_list;
1494                 UInt32 info_tags[] = { kSecServiceItemAttr };
1495                 LPWSTR target_name;
1496                 INT str_len;
1497                 info.count = sizeof(info_tags)/sizeof(info_tags[0]);
1498                 info.tag = info_tags;
1499                 info.format = NULL;
1500                 status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, NULL, NULL);
1501                 len = sizeof(**Credential);
1502                 if (status != noErr)
1503                 {
1504                     WARN("SecKeychainItemCopyAttributesAndData returned status %d\n", status);
1505                     continue;
1506                 }
1507                 if (attr_list->count != 1 || attr_list->attr[0].tag != kSecServiceItemAttr)
1508                 {
1509                     CFRelease(item);
1510                     continue;
1511                 }
1512                 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, NULL, 0);
1513                 target_name = heap_alloc((str_len + 1) * sizeof(WCHAR));
1514                 MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, target_name, str_len);
1515                 /* nul terminate */
1516                 target_name[str_len] = '\0';
1517                 if (strcmpiW(TargetName, target_name))
1518                 {
1519                     CFRelease(item);
1520                     heap_free(target_name);
1521                     continue;
1522                 }
1523                 heap_free(target_name);
1524                 SecKeychainItemFreeAttributesAndData(attr_list, NULL);
1525                 ret = mac_read_credential_from_item(item, TRUE, NULL, NULL, &len);
1526                 if (ret == ERROR_SUCCESS)
1527                 {
1528                     *Credential = heap_alloc(len);
1529                     if (*Credential)
1530                     {
1531                         len = sizeof(**Credential);
1532                         ret = mac_read_credential_from_item(item, TRUE, *Credential,
1533                                                             (char *)(*Credential + 1), &len);
1534                     }
1535                     else
1536                         ret = ERROR_OUTOFMEMORY;
1537                     CFRelease(item);
1538                     CFRelease(search);
1539                     if (ret != ERROR_SUCCESS)
1540                     {
1541                         SetLastError(ret);
1542                         return FALSE;
1543                     }
1544                     return TRUE;
1545                 }
1546                 CFRelease(item);
1547             }
1548             CFRelease(search);
1549         }
1550     }
1551 #endif
1552 
1553     ret = open_cred_mgr_key(&hkeyMgr, FALSE);
1554     if (ret != ERROR_SUCCESS)
1555     {
1556         WARN("couldn't open/create manager key, error %d\n", ret);
1557         SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1558         return FALSE;
1559     }
1560 
1561     ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
1562     if (ret != ERROR_SUCCESS)
1563     {
1564         RegCloseKey(hkeyMgr);
1565         SetLastError(ret);
1566         return FALSE;
1567     }
1568 
1569     key_name = get_key_name_for_target(TargetName, Type);
1570     ret = RegOpenKeyExW(hkeyMgr, key_name, 0, KEY_QUERY_VALUE, &hkeyCred);
1571     heap_free(key_name);
1572     if (ret != ERROR_SUCCESS)
1573     {
1574         TRACE("credentials for target name %s not found\n", debugstr_w(TargetName));
1575         SetLastError(ERROR_NOT_FOUND);
1576         return FALSE;
1577     }
1578 
1579     len = sizeof(**Credential);
1580     ret = registry_read_credential(hkeyCred, NULL, key_data, NULL, &len);
1581     if (ret == ERROR_SUCCESS)
1582     {
1583         *Credential = heap_alloc(len);
1584         if (*Credential)
1585         {
1586             len = sizeof(**Credential);
1587             ret = registry_read_credential(hkeyCred, *Credential, key_data,
1588                                            (char *)(*Credential + 1), &len);
1589         }
1590         else
1591             ret = ERROR_OUTOFMEMORY;
1592     }
1593 
1594     RegCloseKey(hkeyCred);
1595     RegCloseKey(hkeyMgr);
1596 
1597     if (ret != ERROR_SUCCESS)
1598     {
1599         SetLastError(ret);
1600         return FALSE;
1601     }
1602     return TRUE;
1603 }
1604 
1605 /******************************************************************************
1606  * CredReadDomainCredentialsA [ADVAPI32.@]
1607  */
CredReadDomainCredentialsA(PCREDENTIAL_TARGET_INFORMATIONA TargetInformation,DWORD Flags,DWORD * Size,PCREDENTIALA ** Credentials)1608 BOOL WINAPI CredReadDomainCredentialsA(PCREDENTIAL_TARGET_INFORMATIONA TargetInformation,
1609                                        DWORD Flags, DWORD *Size, PCREDENTIALA **Credentials)
1610 {
1611     PCREDENTIAL_TARGET_INFORMATIONW TargetInformationW;
1612     INT len;
1613     DWORD i;
1614     WCHAR *buffer, *end;
1615     BOOL ret;
1616     PCREDENTIALW* CredentialsW;
1617 
1618     TRACE("(%p, 0x%x, %p, %p)\n", TargetInformation, Flags, Size, Credentials);
1619 
1620     /* follow Windows behavior - do not test for NULL, initialize early */
1621     *Size = 0;
1622     *Credentials = NULL;
1623 
1624     if (!TargetInformation)
1625     {
1626         SetLastError(ERROR_INVALID_PARAMETER);
1627         return FALSE;
1628     }
1629 
1630     len = sizeof(*TargetInformationW);
1631     if (TargetInformation->TargetName)
1632         len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->TargetName, -1, NULL, 0) * sizeof(WCHAR);
1633     if (TargetInformation->NetbiosServerName)
1634         len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosServerName, -1, NULL, 0) * sizeof(WCHAR);
1635     if (TargetInformation->DnsServerName)
1636         len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsServerName, -1, NULL, 0) * sizeof(WCHAR);
1637     if (TargetInformation->NetbiosDomainName)
1638         len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosDomainName, -1, NULL, 0) * sizeof(WCHAR);
1639     if (TargetInformation->DnsDomainName)
1640         len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsDomainName, -1, NULL, 0) * sizeof(WCHAR);
1641     if (TargetInformation->DnsTreeName)
1642         len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsTreeName, -1, NULL, 0) * sizeof(WCHAR);
1643     if (TargetInformation->PackageName)
1644         len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->PackageName, -1, NULL, 0) * sizeof(WCHAR);
1645 
1646     TargetInformationW = heap_alloc(len);
1647     if (!TargetInformationW)
1648     {
1649         SetLastError(ERROR_OUTOFMEMORY);
1650         return FALSE;
1651     }
1652     buffer = (WCHAR*)(TargetInformationW + 1);
1653     end = (WCHAR *)((char *)TargetInformationW + len);
1654 
1655     if (TargetInformation->TargetName)
1656     {
1657         TargetInformationW->TargetName = buffer;
1658         buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->TargetName, -1,
1659                                       TargetInformationW->TargetName, end - buffer);
1660     } else
1661         TargetInformationW->TargetName = NULL;
1662 
1663     if (TargetInformation->NetbiosServerName)
1664     {
1665         TargetInformationW->NetbiosServerName = buffer;
1666         buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosServerName, -1,
1667                                       TargetInformationW->NetbiosServerName, end - buffer);
1668     } else
1669         TargetInformationW->NetbiosServerName = NULL;
1670 
1671     if (TargetInformation->DnsServerName)
1672     {
1673         TargetInformationW->DnsServerName = buffer;
1674         buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsServerName, -1,
1675                                       TargetInformationW->DnsServerName, end - buffer);
1676     } else
1677         TargetInformationW->DnsServerName = NULL;
1678 
1679     if (TargetInformation->NetbiosDomainName)
1680     {
1681         TargetInformationW->NetbiosDomainName = buffer;
1682         buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosDomainName, -1,
1683                                       TargetInformationW->NetbiosDomainName, end - buffer);
1684     } else
1685         TargetInformationW->NetbiosDomainName = NULL;
1686 
1687     if (TargetInformation->DnsDomainName)
1688     {
1689         TargetInformationW->DnsDomainName = buffer;
1690         buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsDomainName, -1,
1691                                       TargetInformationW->DnsDomainName, end - buffer);
1692     } else
1693         TargetInformationW->DnsDomainName = NULL;
1694 
1695     if (TargetInformation->DnsTreeName)
1696     {
1697         TargetInformationW->DnsTreeName = buffer;
1698         buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsTreeName, -1,
1699                                       TargetInformationW->DnsTreeName, end - buffer);
1700     } else
1701         TargetInformationW->DnsTreeName = NULL;
1702 
1703     if (TargetInformation->PackageName)
1704     {
1705         TargetInformationW->PackageName = buffer;
1706         MultiByteToWideChar(CP_ACP, 0, TargetInformation->PackageName, -1,
1707                             TargetInformationW->PackageName, end - buffer);
1708     } else
1709         TargetInformationW->PackageName = NULL;
1710 
1711     TargetInformationW->Flags = TargetInformation->Flags;
1712     TargetInformationW->CredTypeCount = TargetInformation->CredTypeCount;
1713     TargetInformationW->CredTypes = TargetInformation->CredTypes;
1714 
1715     ret = CredReadDomainCredentialsW(TargetInformationW, Flags, Size, &CredentialsW);
1716 
1717     heap_free(TargetInformationW);
1718 
1719     if (ret)
1720     {
1721         char *buf;
1722         INT needed;
1723 
1724         len = *Size * sizeof(PCREDENTIALA);
1725         for (i = 0; i < *Size; i++)
1726             len += convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], NULL, 0);
1727 
1728         *Credentials = heap_alloc(len);
1729         if (!*Credentials)
1730         {
1731             CredFree(CredentialsW);
1732             SetLastError(ERROR_OUTOFMEMORY);
1733             return FALSE;
1734         }
1735 
1736         buf = (char *)&(*Credentials)[*Size];
1737         len -= *Size * sizeof(PCREDENTIALA);
1738         for (i = 0; i < *Size; i++)
1739         {
1740             (*Credentials)[i] = (PCREDENTIALA)buf;
1741             needed = convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], (*Credentials)[i], len);
1742             buf += needed;
1743             len -= needed;
1744         }
1745 
1746         CredFree(CredentialsW);
1747     }
1748     return ret;
1749 }
1750 
1751 /******************************************************************************
1752  * CredReadDomainCredentialsW [ADVAPI32.@]
1753  */
CredReadDomainCredentialsW(PCREDENTIAL_TARGET_INFORMATIONW TargetInformation,DWORD Flags,DWORD * Size,PCREDENTIALW ** Credentials)1754 BOOL WINAPI CredReadDomainCredentialsW(PCREDENTIAL_TARGET_INFORMATIONW TargetInformation, DWORD Flags,
1755                                        DWORD *Size, PCREDENTIALW **Credentials)
1756 {
1757     FIXME("(%p, 0x%x, %p, %p) stub\n", TargetInformation, Flags, Size, Credentials);
1758 
1759     /* follow Windows behavior - do not test for NULL, initialize early */
1760     *Size = 0;
1761     *Credentials = NULL;
1762     if (!TargetInformation)
1763     {
1764         SetLastError(ERROR_INVALID_PARAMETER);
1765         return FALSE;
1766     }
1767 
1768     SetLastError(ERROR_NOT_FOUND);
1769     return FALSE;
1770 }
1771 
1772 /******************************************************************************
1773  * CredWriteA [ADVAPI32.@]
1774  */
CredWriteA(PCREDENTIALA Credential,DWORD Flags)1775 BOOL WINAPI CredWriteA(PCREDENTIALA Credential, DWORD Flags)
1776 {
1777     BOOL ret;
1778     INT len;
1779     PCREDENTIALW CredentialW;
1780 
1781     TRACE("(%p, 0x%x)\n", Credential, Flags);
1782 
1783     if (!Credential || !Credential->TargetName)
1784     {
1785         SetLastError(ERROR_INVALID_PARAMETER);
1786         return FALSE;
1787     }
1788 
1789     len = convert_PCREDENTIALA_to_PCREDENTIALW(Credential, NULL, 0);
1790     CredentialW = heap_alloc(len);
1791     if (!CredentialW)
1792     {
1793         SetLastError(ERROR_OUTOFMEMORY);
1794         return FALSE;
1795     }
1796 
1797     convert_PCREDENTIALA_to_PCREDENTIALW(Credential, CredentialW, len);
1798 
1799     ret = CredWriteW(CredentialW, Flags);
1800 
1801     heap_free(CredentialW);
1802 
1803     return ret;
1804 }
1805 
1806 /******************************************************************************
1807  * CredWriteW [ADVAPI32.@]
1808  */
CredWriteW(PCREDENTIALW Credential,DWORD Flags)1809 BOOL WINAPI CredWriteW(PCREDENTIALW Credential, DWORD Flags)
1810 {
1811     HKEY hkeyMgr;
1812     HKEY hkeyCred;
1813     DWORD ret;
1814     LPWSTR key_name;
1815     BYTE key_data[KEY_SIZE];
1816 
1817     TRACE("(%p, 0x%x)\n", Credential, Flags);
1818 
1819     if (!Credential || !Credential->TargetName)
1820     {
1821         SetLastError(ERROR_INVALID_PARAMETER);
1822         return FALSE;
1823     }
1824 
1825     if (Flags & ~CRED_PRESERVE_CREDENTIAL_BLOB)
1826     {
1827         FIXME("unhandled flags 0x%x\n", Flags);
1828         SetLastError(ERROR_INVALID_FLAGS);
1829         return FALSE;
1830     }
1831 
1832     if (Credential->Type != CRED_TYPE_GENERIC && Credential->Type != CRED_TYPE_DOMAIN_PASSWORD)
1833     {
1834         FIXME("unhandled type %d\n", Credential->Type);
1835         SetLastError(ERROR_INVALID_PARAMETER);
1836         return FALSE;
1837     }
1838 
1839     TRACE("Credential->Flags = 0x%08x\n", Credential->Flags);
1840     TRACE("Credential->Type = %u\n", Credential->Type);
1841     TRACE("Credential->TargetName = %s\n", debugstr_w(Credential->TargetName));
1842     TRACE("Credential->Comment = %s\n", debugstr_w(Credential->Comment));
1843     TRACE("Credential->Persist = %u\n", Credential->Persist);
1844     TRACE("Credential->TargetAlias = %s\n", debugstr_w(Credential->TargetAlias));
1845     TRACE("Credential->UserName = %s\n", debugstr_w(Credential->UserName));
1846 
1847     if (Credential->Type == CRED_TYPE_DOMAIN_PASSWORD)
1848     {
1849         if (!Credential->UserName ||
1850             (Credential->Persist == CRED_PERSIST_ENTERPRISE &&
1851             (!strchrW(Credential->UserName, '\\') && !strchrW(Credential->UserName, '@'))))
1852         {
1853             ERR("bad username %s\n", debugstr_w(Credential->UserName));
1854             SetLastError(ERROR_BAD_USERNAME);
1855             return FALSE;
1856         }
1857     }
1858 
1859 #ifdef __APPLE__
1860     if (!Credential->AttributeCount &&
1861         Credential->Type == CRED_TYPE_DOMAIN_PASSWORD &&
1862         (Credential->Persist == CRED_PERSIST_LOCAL_MACHINE || Credential->Persist == CRED_PERSIST_ENTERPRISE))
1863     {
1864         ret = mac_write_credential(Credential, Flags & CRED_PRESERVE_CREDENTIAL_BLOB);
1865         if (ret != ERROR_SUCCESS)
1866         {
1867             SetLastError(ret);
1868             return FALSE;
1869         }
1870         return TRUE;
1871     }
1872 #endif
1873 
1874     ret = open_cred_mgr_key(&hkeyMgr, FALSE);
1875     if (ret != ERROR_SUCCESS)
1876     {
1877         WARN("couldn't open/create manager key, error %d\n", ret);
1878         SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1879         return FALSE;
1880     }
1881 
1882     ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
1883     if (ret != ERROR_SUCCESS)
1884     {
1885         RegCloseKey(hkeyMgr);
1886         SetLastError(ret);
1887         return FALSE;
1888     }
1889 
1890     key_name = get_key_name_for_target(Credential->TargetName, Credential->Type);
1891     ret = RegCreateKeyExW(hkeyMgr, key_name, 0, NULL,
1892                           Credential->Persist == CRED_PERSIST_SESSION ? REG_OPTION_VOLATILE : REG_OPTION_NON_VOLATILE,
1893                           KEY_READ|KEY_WRITE, NULL, &hkeyCred, NULL);
1894     heap_free(key_name);
1895     if (ret != ERROR_SUCCESS)
1896     {
1897         TRACE("credentials for target name %s not found\n",
1898               debugstr_w(Credential->TargetName));
1899         SetLastError(ERROR_NOT_FOUND);
1900         return FALSE;
1901     }
1902 
1903     ret = registry_write_credential(hkeyCred, Credential, key_data,
1904                                     Flags & CRED_PRESERVE_CREDENTIAL_BLOB);
1905 
1906     RegCloseKey(hkeyCred);
1907     RegCloseKey(hkeyMgr);
1908 
1909     if (ret != ERROR_SUCCESS)
1910     {
1911         SetLastError(ret);
1912         return FALSE;
1913     }
1914     return TRUE;
1915 }
1916 
1917 /******************************************************************************
1918  * CredGetSessionTypes [ADVAPI32.@]
1919  */
CredGetSessionTypes(DWORD persistCount,LPDWORD persists)1920 WINADVAPI BOOL WINAPI CredGetSessionTypes(DWORD persistCount, LPDWORD persists)
1921 {
1922     TRACE("(%u, %p)\n", persistCount, persists);
1923 
1924     memset(persists, CRED_PERSIST_NONE, persistCount*sizeof(*persists));
1925     if (CRED_TYPE_GENERIC < persistCount)
1926     {
1927         persists[CRED_TYPE_GENERIC] = CRED_PERSIST_ENTERPRISE;
1928 
1929         if (CRED_TYPE_DOMAIN_PASSWORD < persistCount)
1930         {
1931             persists[CRED_TYPE_DOMAIN_PASSWORD] = CRED_PERSIST_ENTERPRISE;
1932         }
1933     }
1934     return TRUE;
1935 }
1936 
1937 /******************************************************************************
1938  * CredMarshalCredentialA [ADVAPI32.@]
1939  */
CredMarshalCredentialA(CRED_MARSHAL_TYPE type,PVOID cred,LPSTR * out)1940 BOOL WINAPI CredMarshalCredentialA( CRED_MARSHAL_TYPE type, PVOID cred, LPSTR *out )
1941 {
1942     BOOL ret;
1943     WCHAR *outW;
1944 
1945     TRACE("%u, %p, %p\n", type, cred, out);
1946 
1947     if ((ret = CredMarshalCredentialW( type, cred, &outW )))
1948     {
1949         int len = WideCharToMultiByte( CP_ACP, 0, outW, -1, NULL, 0, NULL, NULL );
1950         if (!(*out = heap_alloc( len )))
1951         {
1952             heap_free( outW );
1953             return FALSE;
1954         }
1955         WideCharToMultiByte( CP_ACP, 0, outW, -1, *out, len, NULL, NULL );
1956         heap_free( outW );
1957     }
1958     return ret;
1959 }
1960 
cred_encode(const char * bin,unsigned int len,WCHAR * cred)1961 static UINT cred_encode( const char *bin, unsigned int len, WCHAR *cred )
1962 {
1963     static const char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#-";
1964     UINT n = 0, x;
1965 
1966     while (len > 0)
1967     {
1968         cred[n++] = enc[bin[0] & 0x3f];
1969         x = (bin[0] & 0xc0) >> 6;
1970         if (len == 1)
1971         {
1972             cred[n++] = enc[x];
1973             break;
1974         }
1975         cred[n++] = enc[((bin[1] & 0xf) << 2) | x];
1976         x = (bin[1] & 0xf0) >> 4;
1977         if (len == 2)
1978         {
1979             cred[n++] = enc[x];
1980             break;
1981         }
1982         cred[n++] = enc[((bin[2] & 0x3) << 4) | x];
1983         cred[n++] = enc[(bin[2] & 0xfc) >> 2];
1984         bin += 3;
1985         len -= 3;
1986     }
1987     return n;
1988 }
1989 
1990 /******************************************************************************
1991  * CredMarshalCredentialW [ADVAPI32.@]
1992  */
CredMarshalCredentialW(CRED_MARSHAL_TYPE type,PVOID cred,LPWSTR * out)1993 BOOL WINAPI CredMarshalCredentialW( CRED_MARSHAL_TYPE type, PVOID cred, LPWSTR *out )
1994 {
1995     CERT_CREDENTIAL_INFO *cert = cred;
1996     USERNAME_TARGET_CREDENTIAL_INFO *target = cred;
1997     DWORD len, size;
1998     WCHAR *p;
1999 
2000     TRACE("%u, %p, %p\n", type, cred, out);
2001 
2002     if (!cred || (type == CertCredential && cert->cbSize < sizeof(*cert)) ||
2003         (type != CertCredential && type != UsernameTargetCredential && type != BinaryBlobCredential) ||
2004         (type == UsernameTargetCredential && (!target->UserName || !target->UserName[0])))
2005     {
2006         SetLastError( ERROR_INVALID_PARAMETER );
2007         return FALSE;
2008     }
2009     switch (type)
2010     {
2011     case CertCredential:
2012     {
2013         size = (sizeof(cert->rgbHashOfCert) + 2) * 4 / 3;
2014         if (!(p = heap_alloc( (size + 4) * sizeof(WCHAR) ))) return FALSE;
2015         p[0] = '@';
2016         p[1] = '@';
2017         p[2] = 'A' + type;
2018         len = cred_encode( (const char *)cert->rgbHashOfCert, sizeof(cert->rgbHashOfCert), p + 3 );
2019         p[len + 3] = 0;
2020         break;
2021     }
2022     case UsernameTargetCredential:
2023     {
2024         len = strlenW( target->UserName );
2025         size = (sizeof(DWORD) + len * sizeof(WCHAR) + 2) * 4 / 3;
2026         if (!(p = heap_alloc( (size + 4) * sizeof(WCHAR) ))) return FALSE;
2027         p[0] = '@';
2028         p[1] = '@';
2029         p[2] = 'A' + type;
2030         size = len * sizeof(WCHAR);
2031         len = cred_encode( (const char *)&size, sizeof(DWORD), p + 3 );
2032         len += cred_encode( (const char *)target->UserName, size, p + 3 + len );
2033         p[len + 3] = 0;
2034         break;
2035     }
2036     case BinaryBlobCredential:
2037         FIXME("BinaryBlobCredential not implemented\n");
2038         return FALSE;
2039     default:
2040         return FALSE;
2041     }
2042     *out = p;
2043     return TRUE;
2044 }
2045 
2046 /******************************************************************************
2047  * CredUnmarshalCredentialA [ADVAPI32.@]
2048  */
CredUnmarshalCredentialA(LPCSTR cred,PCRED_MARSHAL_TYPE type,PVOID * out)2049 BOOL WINAPI CredUnmarshalCredentialA( LPCSTR cred, PCRED_MARSHAL_TYPE type, PVOID *out )
2050 {
2051     BOOL ret;
2052     WCHAR *credW = NULL;
2053 
2054     TRACE("%s, %p, %p\n", debugstr_a(cred), type, out);
2055 
2056     if (cred)
2057     {
2058         int len = MultiByteToWideChar( CP_ACP, 0, cred, -1, NULL, 0 );
2059         if (!(credW = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
2060         MultiByteToWideChar( CP_ACP, 0, cred, -1, credW, len );
2061     }
2062     ret = CredUnmarshalCredentialW( credW, type, out );
2063     heap_free( credW );
2064     return ret;
2065 }
2066 
char_decode(WCHAR c)2067 static inline char char_decode( WCHAR c )
2068 {
2069     if (c >= 'A' && c <= 'Z') return c - 'A';
2070     if (c >= 'a' && c <= 'z') return c - 'a' + 26;
2071     if (c >= '0' && c <= '9') return c - '0' + 52;
2072     if (c == '#') return 62;
2073     if (c == '-') return 63;
2074     return 64;
2075 }
2076 
cred_decode(const WCHAR * cred,unsigned int len,char * buf)2077 static BOOL cred_decode( const WCHAR *cred, unsigned int len, char *buf )
2078 {
2079     unsigned int i = 0;
2080     char c0, c1, c2, c3;
2081     const WCHAR *p = cred;
2082 
2083     while (len >= 4)
2084     {
2085         if ((c0 = char_decode( p[0] )) > 63) return FALSE;
2086         if ((c1 = char_decode( p[1] )) > 63) return FALSE;
2087         if ((c2 = char_decode( p[2] )) > 63) return FALSE;
2088         if ((c3 = char_decode( p[3] )) > 63) return FALSE;
2089 
2090         buf[i + 0] = (c1 << 6) | c0;
2091         buf[i + 1] = (c2 << 4) | (c1 >> 2);
2092         buf[i + 2] = (c3 << 2) | (c2 >> 4);
2093         len -= 4;
2094         i += 3;
2095         p += 4;
2096     }
2097     if (len == 3)
2098     {
2099         if ((c0 = char_decode( p[0] )) > 63) return FALSE;
2100         if ((c1 = char_decode( p[1] )) > 63) return FALSE;
2101         if ((c2 = char_decode( p[2] )) > 63) return FALSE;
2102 
2103         buf[i + 0] = (c1 << 6) | c0;
2104         buf[i + 1] = (c2 << 4) | (c1 >> 2);
2105     }
2106     else if (len == 2)
2107     {
2108         if ((c0 = char_decode( p[0] )) > 63) return FALSE;
2109         if ((c1 = char_decode( p[1] )) > 63) return FALSE;
2110 
2111         buf[i + 0] = (c1 << 6) | c0;
2112     }
2113     else if (len == 1)
2114     {
2115         return FALSE;
2116     }
2117     return TRUE;
2118 }
2119 
2120 /******************************************************************************
2121  * CredUnmarshalCredentialW [ADVAPI32.@]
2122  */
CredUnmarshalCredentialW(LPCWSTR cred,PCRED_MARSHAL_TYPE type,PVOID * out)2123 BOOL WINAPI CredUnmarshalCredentialW( LPCWSTR cred, PCRED_MARSHAL_TYPE type, PVOID *out )
2124 {
2125     unsigned int len, buflen;
2126 
2127     TRACE("%s, %p, %p\n", debugstr_w(cred), type, out);
2128 
2129     if (!cred || cred[0] != '@' || cred[1] != '@' ||
2130         char_decode( cred[2] ) > 63)
2131     {
2132         SetLastError( ERROR_INVALID_PARAMETER );
2133         return FALSE;
2134     }
2135     len = strlenW( cred + 3 );
2136     *type = char_decode( cred[2] );
2137     switch (*type)
2138     {
2139     case CertCredential:
2140     {
2141         char hash[CERT_HASH_LENGTH];
2142         CERT_CREDENTIAL_INFO *cert;
2143 
2144         if (len != 27 || !cred_decode( cred + 3, len, hash ))
2145         {
2146             SetLastError( ERROR_INVALID_PARAMETER );
2147             return FALSE;
2148         }
2149         if (!(cert = heap_alloc( sizeof(*cert) ))) return FALSE;
2150         memcpy( cert->rgbHashOfCert, hash, sizeof(cert->rgbHashOfCert) );
2151         cert->cbSize = sizeof(*cert);
2152         *out = cert;
2153         break;
2154     }
2155     case UsernameTargetCredential:
2156     {
2157         USERNAME_TARGET_CREDENTIAL_INFO *target;
2158         DWORD size;
2159 
2160         if (len < 9 || !cred_decode( cred + 3, 6, (char *)&size ) ||
2161             size % sizeof(WCHAR) || len - 6 != (size * 4 + 2) / 3)
2162         {
2163             SetLastError( ERROR_INVALID_PARAMETER );
2164             return FALSE;
2165         }
2166         buflen = sizeof(*target) + size + sizeof(WCHAR);
2167         if (!(target = heap_alloc( buflen ))) return FALSE;
2168         if (!cred_decode( cred + 9, len - 6, (char *)(target + 1) ))
2169         {
2170             heap_free( target );
2171             return FALSE;
2172         }
2173         target->UserName = (WCHAR *)(target + 1);
2174         target->UserName[size / sizeof(WCHAR)] = 0;
2175         *out = target;
2176         break;
2177     }
2178     case BinaryBlobCredential:
2179         FIXME("BinaryBlobCredential not implemented\n");
2180         return FALSE;
2181     default:
2182         WARN("unhandled type %u\n", *type);
2183         SetLastError( ERROR_INVALID_PARAMETER );
2184         return FALSE;
2185     }
2186     return TRUE;
2187 }
2188 
2189 /******************************************************************************
2190  * CredIsMarshaledCredentialW [ADVAPI32.@]
2191  *
2192  * Check, if the name parameter is a marshaled credential, hash or binary blob
2193  *
2194  * PARAMS
2195  *  name    the name to check
2196  *
2197  * RETURNS
2198  *  TRUE:  the name parameter is a marshaled credential, hash or binary blob
2199  *  FALSE: the name is a plain username
2200  */
CredIsMarshaledCredentialW(LPCWSTR name)2201 BOOL WINAPI CredIsMarshaledCredentialW(LPCWSTR name)
2202 {
2203     TRACE("(%s)\n", debugstr_w(name));
2204 
2205     if (name && name[0] == '@' && name[1] == '@' && name[2] > 'A' && name[3])
2206     {
2207         char hash[CERT_HASH_LENGTH];
2208         int len = strlenW(name + 3 );
2209         DWORD size;
2210 
2211         if ((name[2] - 'A') == CertCredential && (len == 27) && cred_decode(name + 3, len, hash))
2212             return TRUE;
2213 
2214         if (((name[2] - 'A') == UsernameTargetCredential) &&
2215             (len >= 9) && cred_decode(name + 3, 6, (char *)&size) && size)
2216             return TRUE;
2217 
2218         if ((name[2] - 'A') == BinaryBlobCredential)
2219             FIXME("BinaryBlobCredential not checked\n");
2220 
2221         if ((name[2] - 'A') > BinaryBlobCredential)
2222             TRACE("unknown type: %d\n", (name[2] - 'A'));
2223     }
2224 
2225     SetLastError(ERROR_INVALID_PARAMETER);
2226     return FALSE;
2227 }
2228 
2229 /******************************************************************************
2230  * CredIsMarshaledCredentialA [ADVAPI32.@]
2231  *
2232  * See CredIsMarshaledCredentialW
2233  *
2234  */
CredIsMarshaledCredentialA(LPCSTR name)2235 BOOL WINAPI CredIsMarshaledCredentialA(LPCSTR name)
2236 {
2237     LPWSTR nameW = NULL;
2238     BOOL res;
2239     int len;
2240 
2241     TRACE("(%s)\n", debugstr_a(name));
2242 
2243     if (name)
2244     {
2245         len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
2246         nameW = heap_alloc(len * sizeof(WCHAR));
2247         MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, len);
2248     }
2249 
2250     res = CredIsMarshaledCredentialW(nameW);
2251     heap_free(nameW);
2252     return res;
2253 }
2254