mlang: Added IMLangConvertCharset stub.
[wine.git] / dlls / advapi32 / cred.c
blob98c4ba7b800d9363d563ac32811e4024c30ea6c6
1 /*
2 * Credential Management APIs
4 * Copyright 2007 Robert Shearman for CodeWeavers
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.
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.
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
21 #include <stdarg.h>
22 #include <time.h>
24 #ifdef __APPLE__
25 # include <Security/SecKeychain.h>
26 # include <Security/SecKeychainItem.h>
27 # include <Security/SecKeychainSearch.h>
28 #endif
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winreg.h"
33 #include "wincred.h"
34 #include "winternl.h"
36 #include "crypt.h"
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(cred);
43 /* the size of the ARC4 key used to encrypt the password data */
44 #define KEY_SIZE 8
46 static const WCHAR wszCredentialManagerKey[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
47 'C','r','e','d','e','n','t','i','a','l',' ','M','a','n','a','g','e','r',0};
48 static const WCHAR wszEncryptionKeyValue[] = {'E','n','c','r','y','p','t','i','o','n','K','e','y',0};
50 static const WCHAR wszFlagsValue[] = {'F','l','a','g','s',0};
51 static const WCHAR wszTypeValue[] = {'T','y','p','e',0};
52 static const WCHAR wszCommentValue[] = {'C','o','m','m','e','n','t',0};
53 static const WCHAR wszLastWrittenValue[] = {'L','a','s','t','W','r','i','t','t','e','n',0};
54 static const WCHAR wszPersistValue[] = {'P','e','r','s','i','s','t',0};
55 static const WCHAR wszTargetAliasValue[] = {'T','a','r','g','e','t','A','l','i','a','s',0};
56 static const WCHAR wszUserNameValue[] = {'U','s','e','r','N','a','m','e',0};
57 static const WCHAR wszPasswordValue[] = {'P','a','s','s','w','o','r','d',0};
59 static DWORD read_credential_blob(HKEY hkey, const BYTE key_data[KEY_SIZE],
60 LPBYTE credential_blob,
61 DWORD *credential_blob_size)
63 DWORD ret;
64 DWORD type;
66 *credential_blob_size = 0;
67 ret = RegQueryValueExW(hkey, wszPasswordValue, 0, &type, NULL, credential_blob_size);
68 if (ret != ERROR_SUCCESS)
69 return ret;
70 else if (type != REG_BINARY)
71 return ERROR_REGISTRY_CORRUPT;
72 if (credential_blob)
74 struct ustring data;
75 struct ustring key;
77 ret = RegQueryValueExW(hkey, wszPasswordValue, 0, &type, credential_blob,
78 credential_blob_size);
79 if (ret != ERROR_SUCCESS)
80 return ret;
81 else if (type != REG_BINARY)
82 return ERROR_REGISTRY_CORRUPT;
84 key.Length = key.MaximumLength = KEY_SIZE;
85 key.Buffer = (unsigned char *)key_data;
87 data.Length = data.MaximumLength = *credential_blob_size;
88 data.Buffer = credential_blob;
89 SystemFunction032(&data, &key);
91 return ERROR_SUCCESS;
94 static DWORD registry_read_credential(HKEY hkey, PCREDENTIALW credential,
95 const BYTE key_data[KEY_SIZE],
96 char *buffer, DWORD *len)
98 DWORD type;
99 DWORD ret;
100 DWORD count;
102 ret = RegQueryValueExW(hkey, NULL, 0, &type, NULL, &count);
103 if (ret != ERROR_SUCCESS)
104 return ret;
105 else if (type != REG_SZ)
106 return ERROR_REGISTRY_CORRUPT;
107 *len += count;
108 if (credential)
110 credential->TargetName = (LPWSTR)buffer;
111 ret = RegQueryValueExW(hkey, NULL, 0, &type, (LPVOID)credential->TargetName,
112 &count);
113 if (ret != ERROR_SUCCESS || type != REG_SZ) return ret;
114 buffer += count;
117 ret = RegQueryValueExW(hkey, wszCommentValue, 0, &type, NULL, &count);
118 if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
119 return ret;
120 else if (type != REG_SZ)
121 return ERROR_REGISTRY_CORRUPT;
122 *len += count;
123 if (credential)
125 credential->Comment = (LPWSTR)buffer;
126 ret = RegQueryValueExW(hkey, wszCommentValue, 0, &type, (LPVOID)credential->Comment,
127 &count);
128 if (ret == ERROR_FILE_NOT_FOUND)
129 credential->Comment = NULL;
130 else if (ret != ERROR_SUCCESS)
131 return ret;
132 else if (type != REG_SZ)
133 return ERROR_REGISTRY_CORRUPT;
134 else
135 buffer += count;
138 ret = RegQueryValueExW(hkey, wszTargetAliasValue, 0, &type, NULL, &count);
139 if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
140 return ret;
141 else if (type != REG_SZ)
142 return ERROR_REGISTRY_CORRUPT;
143 *len += count;
144 if (credential)
146 credential->TargetAlias = (LPWSTR)buffer;
147 ret = RegQueryValueExW(hkey, wszTargetAliasValue, 0, &type, (LPVOID)credential->TargetAlias,
148 &count);
149 if (ret == ERROR_FILE_NOT_FOUND)
150 credential->TargetAlias = NULL;
151 else if (ret != ERROR_SUCCESS)
152 return ret;
153 else if (type != REG_SZ)
154 return ERROR_REGISTRY_CORRUPT;
155 else
156 buffer += count;
159 ret = RegQueryValueExW(hkey, wszUserNameValue, 0, &type, NULL, &count);
160 if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
161 return ret;
162 else if (type != REG_SZ)
163 return ERROR_REGISTRY_CORRUPT;
164 *len += count;
165 if (credential)
167 credential->UserName = (LPWSTR)buffer;
168 ret = RegQueryValueExW(hkey, wszUserNameValue, 0, &type, (LPVOID)credential->UserName,
169 &count);
170 if (ret == ERROR_FILE_NOT_FOUND)
171 credential->UserName = NULL;
172 else if (ret != ERROR_SUCCESS)
173 return ret;
174 else if (type != REG_SZ)
175 return ERROR_REGISTRY_CORRUPT;
176 else
177 buffer += count;
180 ret = read_credential_blob(hkey, key_data, NULL, &count);
181 if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
182 return ret;
183 *len += count;
184 if (credential)
186 credential->CredentialBlob = (LPBYTE)buffer;
187 ret = read_credential_blob(hkey, key_data, credential->CredentialBlob, &count);
188 if (ret == ERROR_FILE_NOT_FOUND)
189 credential->CredentialBlob = NULL;
190 else if (ret != ERROR_SUCCESS)
191 return ret;
192 credential->CredentialBlobSize = count;
195 /* FIXME: Attributes */
196 if (credential)
198 credential->AttributeCount = 0;
199 credential->Attributes = NULL;
202 if (!credential) return ERROR_SUCCESS;
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;
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;
234 #ifdef __APPLE__
235 static DWORD mac_read_credential_from_item(SecKeychainItemRef item, BOOL require_password,
236 PCREDENTIALW credential, char *buffer,
237 DWORD *len)
239 OSStatus status;
240 UInt32 i;
241 UInt32 cred_blob_len;
242 void *cred_blob;
243 LPWSTR domain = NULL;
244 LPWSTR user = NULL;
245 BOOL user_name_present = FALSE;
246 SecKeychainAttributeInfo info;
247 SecKeychainAttributeList *attr_list;
248 UInt32 info_tags[] = { kSecServerItemAttr, kSecSecurityDomainItemAttr, kSecAccountItemAttr,
249 kSecCommentItemAttr, kSecCreationDateItemAttr };
250 info.count = sizeof(info_tags)/sizeof(info_tags[0]);
251 info.tag = info_tags;
252 info.format = NULL;
253 status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, &cred_blob_len, &cred_blob);
254 if (status == errSecAuthFailed && !require_password)
256 cred_blob_len = 0;
257 cred_blob = NULL;
258 status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, &cred_blob_len, NULL);
260 if (status != noErr)
262 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status);
263 return ERROR_NOT_FOUND;
266 for (i = 0; i < attr_list->count; i++)
267 if (attr_list->attr[i].tag == kSecAccountItemAttr && attr_list->attr[i].data)
269 user_name_present = TRUE;
270 break;
272 if (!user_name_present)
274 WARN("no kSecAccountItemAttr for item\n");
275 SecKeychainItemFreeAttributesAndData(attr_list, cred_blob);
276 return ERROR_NOT_FOUND;
279 if (buffer)
281 credential->Flags = 0;
282 credential->Type = CRED_TYPE_DOMAIN_PASSWORD;
283 credential->TargetName = NULL;
284 credential->Comment = NULL;
285 memset(&credential->LastWritten, 0, sizeof(credential->LastWritten));
286 credential->CredentialBlobSize = 0;
287 credential->CredentialBlob = NULL;
288 credential->Persist = CRED_PERSIST_LOCAL_MACHINE;
289 credential->AttributeCount = 0;
290 credential->Attributes = NULL;
291 credential->TargetAlias = NULL;
292 credential->UserName = NULL;
294 for (i = 0; i < attr_list->count; i++)
296 switch (attr_list->attr[i].tag)
298 case kSecServerItemAttr:
299 TRACE("kSecServerItemAttr: %.*s\n", (int)attr_list->attr[i].length,
300 (char *)attr_list->attr[i].data);
301 if (!attr_list->attr[i].data) continue;
302 if (buffer)
304 INT str_len;
305 credential->TargetName = (LPWSTR)buffer;
306 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
307 attr_list->attr[i].length, (LPWSTR)buffer, 0xffff);
308 credential->TargetName[str_len] = '\0';
309 buffer += (str_len + 1) * sizeof(WCHAR);
310 *len += (str_len + 1) * sizeof(WCHAR);
312 else
314 INT str_len;
315 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
316 attr_list->attr[i].length, NULL, 0);
317 *len += (str_len + 1) * sizeof(WCHAR);
319 break;
320 case kSecAccountItemAttr:
322 INT str_len;
323 TRACE("kSecAccountItemAttr: %.*s\n", (int)attr_list->attr[i].length,
324 (char *)attr_list->attr[i].data);
325 if (!attr_list->attr[i].data) continue;
326 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
327 attr_list->attr[i].length, NULL, 0);
328 user = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
329 MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
330 attr_list->attr[i].length, user, str_len);
331 user[str_len] = '\0';
332 break;
334 case kSecCommentItemAttr:
335 TRACE("kSecCommentItemAttr: %.*s\n", (int)attr_list->attr[i].length,
336 (char *)attr_list->attr[i].data);
337 if (!attr_list->attr[i].data) continue;
338 if (buffer)
340 INT str_len;
341 credential->Comment = (LPWSTR)buffer;
342 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
343 attr_list->attr[i].length, (LPWSTR)buffer, 0xffff);
344 credential->Comment[str_len] = '\0';
345 buffer += (str_len + 1) * sizeof(WCHAR);
346 *len += (str_len + 1) * sizeof(WCHAR);
348 else
350 INT str_len;
351 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
352 attr_list->attr[i].length, NULL, 0);
353 *len += (str_len + 1) * sizeof(WCHAR);
355 break;
356 case kSecSecurityDomainItemAttr:
358 INT str_len;
359 TRACE("kSecSecurityDomainItemAttr: %.*s\n", (int)attr_list->attr[i].length,
360 (char *)attr_list->attr[i].data);
361 if (!attr_list->attr[i].data) continue;
362 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
363 attr_list->attr[i].length, NULL, 0);
364 domain = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
365 MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
366 attr_list->attr[i].length, domain, str_len);
367 domain[str_len] = '\0';
368 break;
370 case kSecCreationDateItemAttr:
371 TRACE("kSecCreationDateItemAttr: %.*s\n", (int)attr_list->attr[i].length,
372 (char *)attr_list->attr[i].data);
373 if (buffer)
375 LARGE_INTEGER win_time;
376 struct tm tm;
377 time_t time;
378 memset(&tm, 0, sizeof(tm));
379 strptime(attr_list->attr[i].data, "%Y%m%d%H%M%SZ", &tm);
380 time = mktime(&tm);
381 RtlSecondsSince1970ToTime(time, &win_time);
382 credential->LastWritten.dwLowDateTime = win_time.u.LowPart;
383 credential->LastWritten.dwHighDateTime = win_time.u.HighPart;
385 break;
389 if (user)
391 INT str_len;
392 if (buffer)
393 credential->UserName = (LPWSTR)buffer;
394 if (domain)
396 str_len = strlenW(domain);
397 *len += (str_len + 1) * sizeof(WCHAR);
398 if (buffer)
400 memcpy(credential->UserName, domain, str_len * sizeof(WCHAR));
401 /* FIXME: figure out when to use an '@' */
402 credential->UserName[str_len] = '\\';
403 buffer += (str_len + 1) * sizeof(WCHAR);
406 str_len = strlenW(user);
407 *len += (str_len + 1) * sizeof(WCHAR);
408 if (buffer)
410 memcpy(buffer, user, (str_len + 1) * sizeof(WCHAR));
411 buffer += (str_len + 1) * sizeof(WCHAR);
412 TRACE("UserName = %s\n", debugstr_w(credential->UserName));
415 HeapFree(GetProcessHeap(), 0, user);
416 HeapFree(GetProcessHeap(), 0, domain);
418 if (cred_blob)
420 if (buffer)
422 INT str_len;
423 credential->CredentialBlob = (BYTE *)buffer;
424 str_len = MultiByteToWideChar(CP_UTF8, 0, cred_blob, cred_blob_len,
425 (LPWSTR)buffer, 0xffff);
426 credential->CredentialBlobSize = str_len * sizeof(WCHAR);
427 *len += str_len * sizeof(WCHAR);
429 else
431 INT str_len;
432 str_len = MultiByteToWideChar(CP_UTF8, 0, cred_blob, cred_blob_len,
433 NULL, 0);
434 *len += str_len * sizeof(WCHAR);
437 SecKeychainItemFreeAttributesAndData(attr_list, cred_blob);
438 return ERROR_SUCCESS;
440 #endif
442 static DWORD write_credential_blob(HKEY hkey, LPCWSTR target_name, DWORD type,
443 const BYTE key_data[KEY_SIZE],
444 const BYTE *credential_blob, DWORD credential_blob_size)
446 LPBYTE encrypted_credential_blob;
447 struct ustring data;
448 struct ustring key;
449 DWORD ret;
451 key.Length = key.MaximumLength = KEY_SIZE;
452 key.Buffer = (unsigned char *)key_data;
454 encrypted_credential_blob = HeapAlloc(GetProcessHeap(), 0, credential_blob_size);
455 if (!encrypted_credential_blob) return ERROR_OUTOFMEMORY;
457 memcpy(encrypted_credential_blob, credential_blob, credential_blob_size);
458 data.Length = data.MaximumLength = credential_blob_size;
459 data.Buffer = encrypted_credential_blob;
460 SystemFunction032(&data, &key);
462 ret = RegSetValueExW(hkey, wszPasswordValue, 0, REG_BINARY, encrypted_credential_blob, credential_blob_size);
463 HeapFree(GetProcessHeap(), 0, encrypted_credential_blob);
465 return ret;
468 static DWORD registry_write_credential(HKEY hkey, const CREDENTIALW *credential,
469 const BYTE key_data[KEY_SIZE], BOOL preserve_blob)
471 DWORD ret;
472 FILETIME LastWritten;
474 GetSystemTimeAsFileTime(&LastWritten);
476 ret = RegSetValueExW(hkey, wszFlagsValue, 0, REG_DWORD, (const BYTE*)&credential->Flags,
477 sizeof(credential->Flags));
478 if (ret != ERROR_SUCCESS) return ret;
479 ret = RegSetValueExW(hkey, wszTypeValue, 0, REG_DWORD, (const BYTE*)&credential->Type,
480 sizeof(credential->Type));
481 if (ret != ERROR_SUCCESS) return ret;
482 ret = RegSetValueExW(hkey, NULL, 0, REG_SZ, (LPVOID)credential->TargetName,
483 sizeof(WCHAR)*(strlenW(credential->TargetName)+1));
484 if (ret != ERROR_SUCCESS) return ret;
485 if (credential->Comment)
487 ret = RegSetValueExW(hkey, wszCommentValue, 0, REG_SZ, (LPVOID)credential->Comment,
488 sizeof(WCHAR)*(strlenW(credential->Comment)+1));
489 if (ret != ERROR_SUCCESS) return ret;
491 ret = RegSetValueExW(hkey, wszLastWrittenValue, 0, REG_BINARY, (LPVOID)&LastWritten,
492 sizeof(LastWritten));
493 if (ret != ERROR_SUCCESS) return ret;
494 ret = RegSetValueExW(hkey, wszPersistValue, 0, REG_DWORD, (const BYTE*)&credential->Persist,
495 sizeof(credential->Persist));
496 if (ret != ERROR_SUCCESS) return ret;
497 /* FIXME: Attributes */
498 if (credential->TargetAlias)
500 ret = RegSetValueExW(hkey, wszTargetAliasValue, 0, REG_SZ, (LPVOID)credential->TargetAlias,
501 sizeof(WCHAR)*(strlenW(credential->TargetAlias)+1));
502 if (ret != ERROR_SUCCESS) return ret;
504 if (credential->UserName)
506 ret = RegSetValueExW(hkey, wszUserNameValue, 0, REG_SZ, (LPVOID)credential->UserName,
507 sizeof(WCHAR)*(strlenW(credential->UserName)+1));
508 if (ret != ERROR_SUCCESS) return ret;
510 if (!preserve_blob)
512 ret = write_credential_blob(hkey, credential->TargetName, credential->Type,
513 key_data, credential->CredentialBlob,
514 credential->CredentialBlobSize);
516 return ret;
519 #ifdef __APPLE__
520 static DWORD mac_write_credential(const CREDENTIALW *credential, BOOL preserve_blob)
522 OSStatus status;
523 SecKeychainItemRef keychain_item;
524 char *username;
525 char *domain = NULL;
526 char *password;
527 char *servername;
528 UInt32 userlen;
529 UInt32 domainlen = 0;
530 UInt32 pwlen;
531 UInt32 serverlen;
532 LPCWSTR p;
533 SecKeychainAttribute attrs[1];
534 SecKeychainAttributeList attr_list;
536 if (credential->Flags)
537 FIXME("Flags 0x%x not written\n", credential->Flags);
538 if (credential->Type != CRED_TYPE_DOMAIN_PASSWORD)
539 FIXME("credential type of %d not supported\n", credential->Type);
540 if (credential->Persist != CRED_PERSIST_LOCAL_MACHINE)
541 FIXME("persist value of %d not supported\n", credential->Persist);
542 if (credential->AttributeCount)
543 FIXME("custom attributes not supported\n");
545 p = strchrW(credential->UserName, '\\');
546 if (p)
548 domainlen = WideCharToMultiByte(CP_UTF8, 0, credential->UserName,
549 p - credential->UserName, NULL, 0, NULL, NULL);
550 domain = HeapAlloc(GetProcessHeap(), 0, (domainlen + 1) * sizeof(*domain));
551 WideCharToMultiByte(CP_UTF8, 0, credential->UserName, p - credential->UserName,
552 domain, domainlen, NULL, NULL);
553 domain[domainlen] = '\0';
554 p++;
556 else
557 p = credential->UserName;
558 userlen = WideCharToMultiByte(CP_UTF8, 0, p, -1, NULL, 0, NULL, NULL);
559 username = HeapAlloc(GetProcessHeap(), 0, userlen * sizeof(*username));
560 WideCharToMultiByte(CP_UTF8, 0, p, -1, username, userlen, NULL, NULL);
562 serverlen = WideCharToMultiByte(CP_UTF8, 0, credential->TargetName, -1, NULL, 0, NULL, NULL);
563 servername = HeapAlloc(GetProcessHeap(), 0, serverlen * sizeof(*servername));
564 WideCharToMultiByte(CP_UTF8, 0, credential->TargetName, -1, servername, serverlen, NULL, NULL);
565 pwlen = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)credential->CredentialBlob,
566 credential->CredentialBlobSize / sizeof(WCHAR), NULL, 0, NULL, NULL);
567 password = HeapAlloc(GetProcessHeap(), 0, pwlen * sizeof(*domain));
568 WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)credential->CredentialBlob,
569 credential->CredentialBlobSize / sizeof(WCHAR), password, pwlen, NULL, NULL);
571 TRACE("adding server %s, domain %s, username %s using Keychain\n", servername, domain, username);
572 status = SecKeychainAddInternetPassword(NULL, strlen(servername), servername,
573 strlen(domain), domain, strlen(username),
574 username, 0, NULL, 0,
575 0 /* no protocol */,
576 kSecAuthenticationTypeDefault,
577 strlen(password), password, &keychain_item);
578 if (status != noErr)
579 ERR("SecKeychainAddInternetPassword returned %ld\n", status);
580 if (status == errSecDuplicateItem)
582 SecKeychainItemRef keychain_item;
584 status = SecKeychainFindInternetPassword(NULL, strlen(servername), servername,
585 strlen(domain), domain,
586 strlen(username), username,
587 0, NULL /* any path */, 0,
588 0 /* any protocol */,
589 0 /* any authentication type */,
590 0, NULL, &keychain_item);
591 if (status != noErr)
592 ERR("SecKeychainFindInternetPassword returned %ld\n", status);
594 HeapFree(GetProcessHeap(), 0, domain);
595 HeapFree(GetProcessHeap(), 0, username);
596 HeapFree(GetProcessHeap(), 0, servername);
597 if (status != noErr)
599 HeapFree(GetProcessHeap(), 0, password);
600 return ERROR_GEN_FAILURE;
602 if (credential->Comment)
604 attr_list.count = 1;
605 attr_list.attr = attrs;
606 attrs[0].tag = kSecCommentItemAttr;
607 attrs[0].length = WideCharToMultiByte(CP_UTF8, 0, credential->Comment, -1, NULL, 0, NULL, NULL);
608 if (attrs[0].length) attrs[0].length--;
609 attrs[0].data = HeapAlloc(GetProcessHeap(), 0, attrs[0].length);
610 WideCharToMultiByte(CP_UTF8, 0, credential->Comment, -1, attrs[0].data, attrs[0].length, NULL, NULL);
612 else
614 attr_list.count = 0;
615 attr_list.attr = NULL;
617 status = SecKeychainItemModifyAttributesAndData(keychain_item, &attr_list,
618 preserve_blob ? 0 : strlen(password),
619 preserve_blob ? NULL : password);
620 if (credential->Comment)
621 HeapFree(GetProcessHeap(), 0, attrs[0].data);
622 HeapFree(GetProcessHeap(), 0, password);
623 /* FIXME: set TargetAlias attribute */
624 CFRelease(keychain_item);
625 if (status != noErr)
626 return ERROR_GEN_FAILURE;
627 return ERROR_SUCCESS;
629 #endif
631 static DWORD open_cred_mgr_key(HKEY *hkey, BOOL open_for_write)
633 return RegCreateKeyExW(HKEY_CURRENT_USER, wszCredentialManagerKey, 0,
634 NULL, REG_OPTION_NON_VOLATILE,
635 KEY_READ | (open_for_write ? KEY_WRITE : 0), NULL, hkey, NULL);
638 static DWORD get_cred_mgr_encryption_key(HKEY hkeyMgr, BYTE key_data[KEY_SIZE])
640 static const BYTE my_key_data[KEY_SIZE] = { 0 };
641 DWORD type;
642 DWORD count;
643 FILETIME ft;
644 ULONG seed;
645 ULONG value;
646 DWORD ret;
648 memcpy(key_data, my_key_data, KEY_SIZE);
650 count = KEY_SIZE;
651 ret = RegQueryValueExW(hkeyMgr, wszEncryptionKeyValue, NULL, &type, key_data,
652 &count);
653 if (ret == ERROR_SUCCESS)
655 if (type != REG_BINARY)
656 return ERROR_REGISTRY_CORRUPT;
657 else
658 return ERROR_SUCCESS;
660 if (ret != ERROR_FILE_NOT_FOUND)
661 return ret;
663 GetSystemTimeAsFileTime(&ft);
664 seed = ft.dwLowDateTime;
665 value = RtlUniform(&seed);
666 *(DWORD *)key_data = value;
667 seed = ft.dwHighDateTime;
668 value = RtlUniform(&seed);
669 *(DWORD *)(key_data + 4) = value;
671 ret = RegSetValueExW(hkeyMgr, wszEncryptionKeyValue, 0, REG_BINARY,
672 key_data, KEY_SIZE);
673 if (ret == ERROR_ACCESS_DENIED)
675 ret = open_cred_mgr_key(&hkeyMgr, TRUE);
676 if (ret == ERROR_SUCCESS)
678 ret = RegSetValueExW(hkeyMgr, wszEncryptionKeyValue, 0, REG_BINARY,
679 key_data, KEY_SIZE);
680 RegCloseKey(hkeyMgr);
683 return ret;
686 static LPWSTR get_key_name_for_target(LPCWSTR target_name, DWORD type)
688 static const WCHAR wszGenericPrefix[] = {'G','e','n','e','r','i','c',':',' ',0};
689 static const WCHAR wszDomPasswdPrefix[] = {'D','o','m','P','a','s','s','w','d',':',' ',0};
690 INT len;
691 LPCWSTR prefix = NULL;
692 LPWSTR key_name, p;
694 len = strlenW(target_name);
695 if (type == CRED_TYPE_GENERIC)
697 prefix = wszGenericPrefix;
698 len += sizeof(wszGenericPrefix)/sizeof(wszGenericPrefix[0]);
700 else
702 prefix = wszDomPasswdPrefix;
703 len += sizeof(wszDomPasswdPrefix)/sizeof(wszDomPasswdPrefix[0]);
706 key_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
707 if (!key_name) return NULL;
709 strcpyW(key_name, prefix);
710 strcatW(key_name, target_name);
712 for (p = key_name; *p; p++)
713 if (*p == '\\') *p = '_';
715 return key_name;
718 static BOOL credential_matches_filter(HKEY hkeyCred, LPCWSTR filter)
720 LPWSTR target_name;
721 DWORD ret;
722 DWORD type;
723 DWORD count;
724 LPCWSTR p;
726 if (!filter) return TRUE;
728 ret = RegQueryValueExW(hkeyCred, NULL, 0, &type, NULL, &count);
729 if (ret != ERROR_SUCCESS)
730 return FALSE;
731 else if (type != REG_SZ)
732 return FALSE;
734 target_name = HeapAlloc(GetProcessHeap(), 0, count);
735 if (!target_name)
736 return FALSE;
737 ret = RegQueryValueExW(hkeyCred, NULL, 0, &type, (LPVOID)target_name, &count);
738 if (ret != ERROR_SUCCESS || type != REG_SZ)
740 HeapFree(GetProcessHeap(), 0, target_name);
741 return FALSE;
744 TRACE("comparing filter %s to target name %s\n", debugstr_w(filter),
745 debugstr_w(target_name));
747 p = strchrW(filter, '*');
748 ret = CompareStringW(GetThreadLocale(), 0, filter,
749 (p && !p[1] ? p - filter : -1), target_name,
750 (p && !p[1] ? p - filter : -1)) == CSTR_EQUAL;
752 HeapFree(GetProcessHeap(), 0, target_name);
753 return ret;
756 static DWORD registry_enumerate_credentials(HKEY hkeyMgr, LPCWSTR filter,
757 LPWSTR target_name,
758 DWORD target_name_len, const BYTE key_data[KEY_SIZE],
759 PCREDENTIALW *credentials, char **buffer,
760 DWORD *len, DWORD *count)
762 DWORD i;
763 DWORD ret;
764 for (i = 0;; i++)
766 HKEY hkeyCred;
767 ret = RegEnumKeyW(hkeyMgr, i, target_name, target_name_len+1);
768 if (ret == ERROR_NO_MORE_ITEMS)
770 ret = ERROR_SUCCESS;
771 break;
773 else if (ret != ERROR_SUCCESS)
774 continue;
775 TRACE("target_name = %s\n", debugstr_w(target_name));
776 ret = RegOpenKeyExW(hkeyMgr, target_name, 0, KEY_QUERY_VALUE, &hkeyCred);
777 if (ret != ERROR_SUCCESS)
778 continue;
779 if (!credential_matches_filter(hkeyCred, filter))
781 RegCloseKey(hkeyCred);
782 continue;
784 if (buffer)
786 *len = sizeof(CREDENTIALW);
787 credentials[*count] = (PCREDENTIALW)*buffer;
789 else
790 *len += sizeof(CREDENTIALW);
791 ret = registry_read_credential(hkeyCred, buffer ? credentials[*count] : NULL,
792 key_data, buffer ? *buffer + sizeof(CREDENTIALW) : NULL,
793 len);
794 RegCloseKey(hkeyCred);
795 if (ret != ERROR_SUCCESS) break;
796 if (buffer) *buffer += *len;
797 (*count)++;
799 return ret;
802 #ifdef __APPLE__
803 static DWORD mac_enumerate_credentials(LPCWSTR filter, PCREDENTIALW *credentials,
804 char *buffer, DWORD *len, DWORD *count)
806 SecKeychainSearchRef search;
807 SecKeychainItemRef item;
808 OSStatus status;
809 Boolean saved_user_interaction_allowed;
810 DWORD ret;
812 SecKeychainGetUserInteractionAllowed(&saved_user_interaction_allowed);
813 SecKeychainSetUserInteractionAllowed(false);
815 status = SecKeychainSearchCreateFromAttributes(NULL, kSecInternetPasswordItemClass, NULL, &search);
816 if (status == noErr)
818 while (SecKeychainSearchCopyNext(search, &item) == noErr)
820 SecKeychainAttributeInfo info;
821 SecKeychainAttributeList *attr_list;
822 UInt32 info_tags[] = { kSecServerItemAttr };
823 info.count = sizeof(info_tags)/sizeof(info_tags[0]);
824 info.tag = info_tags;
825 info.format = NULL;
826 status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, NULL, NULL);
827 if (status != noErr)
829 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status);
830 continue;
832 if (buffer)
834 *len = sizeof(CREDENTIALW);
835 credentials[*count] = (PCREDENTIALW)buffer;
837 else
838 *len += sizeof(CREDENTIALW);
839 if (attr_list->count != 1 || attr_list->attr[0].tag != kSecServerItemAttr) continue;
840 TRACE("server item: %.*s\n", (int)attr_list->attr[0].length, (char *)attr_list->attr[0].data);
841 /* FIXME: filter based on attr_list->attr[0].data */
842 SecKeychainItemFreeAttributesAndData(attr_list, NULL);
843 ret = mac_read_credential_from_item(item, FALSE,
844 buffer ? credentials[*count] : NULL,
845 buffer ? buffer + sizeof(CREDENTIALW) : NULL,
846 len);
847 CFRelease(item);
848 if (ret == ERROR_SUCCESS)
850 (*count)++;
851 if (buffer) buffer += *len;
854 CFRelease(search);
856 else
857 ERR("SecKeychainSearchCreateFromAttributes returned status %ld\n", status);
858 SecKeychainSetUserInteractionAllowed(saved_user_interaction_allowed);
859 return ERROR_SUCCESS;
862 static DWORD mac_delete_credential(LPCWSTR TargetName)
864 OSStatus status;
865 SecKeychainSearchRef search;
866 status = SecKeychainSearchCreateFromAttributes(NULL, kSecInternetPasswordItemClass, NULL, &search);
867 if (status == noErr)
869 SecKeychainItemRef item;
870 while (SecKeychainSearchCopyNext(search, &item) == noErr)
872 SecKeychainAttributeInfo info;
873 SecKeychainAttributeList *attr_list;
874 UInt32 info_tags[] = { kSecServerItemAttr };
875 LPWSTR target_name;
876 INT str_len;
877 info.count = sizeof(info_tags)/sizeof(info_tags[0]);
878 info.tag = info_tags;
879 info.format = NULL;
880 status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, NULL, NULL);
881 if (status != noErr)
883 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status);
884 continue;
886 if (attr_list->count != 1 || attr_list->attr[0].tag != kSecServerItemAttr)
888 CFRelease(item);
889 continue;
891 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, NULL, 0);
892 target_name = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
893 MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, target_name, str_len);
894 /* nul terminate */
895 target_name[str_len] = '\0';
896 if (strcmpiW(TargetName, target_name))
898 CFRelease(item);
899 HeapFree(GetProcessHeap(), 0, target_name);
900 continue;
902 HeapFree(GetProcessHeap(), 0, target_name);
903 SecKeychainItemFreeAttributesAndData(attr_list, NULL);
904 SecKeychainItemDelete(item);
905 CFRelease(item);
906 CFRelease(search);
908 return ERROR_SUCCESS;
910 CFRelease(search);
912 return ERROR_NOT_FOUND;
914 #endif
916 /******************************************************************************
917 * convert_PCREDENTIALW_to_PCREDENTIALA [internal]
919 * convert a Credential struct from UNICODE to ANSI and return the needed size in Bytes
923 static INT convert_PCREDENTIALW_to_PCREDENTIALA(const CREDENTIALW *CredentialW, PCREDENTIALA CredentialA, DWORD len)
925 char *buffer;
926 INT string_len;
927 INT needed = sizeof(CREDENTIALA);
929 if (!CredentialA)
931 if (CredentialW->TargetName)
932 needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetName, -1, NULL, 0, NULL, NULL);
933 if (CredentialW->Comment)
934 needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->Comment, -1, NULL, 0, NULL, NULL);
935 needed += CredentialW->CredentialBlobSize;
936 if (CredentialW->TargetAlias)
937 needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetAlias, -1, NULL, 0, NULL, NULL);
938 if (CredentialW->UserName)
939 needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->UserName, -1, NULL, 0, NULL, NULL);
941 return needed;
945 buffer = (char *)CredentialA + sizeof(CREDENTIALA);
946 len -= sizeof(CREDENTIALA);
947 CredentialA->Flags = CredentialW->Flags;
948 CredentialA->Type = CredentialW->Type;
950 if (CredentialW->TargetName)
952 CredentialA->TargetName = buffer;
953 string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetName, -1, buffer, len, NULL, NULL);
954 buffer += string_len;
955 needed += string_len;
956 len -= string_len;
958 else
959 CredentialA->TargetName = NULL;
960 if (CredentialW->Comment)
962 CredentialA->Comment = buffer;
963 string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->Comment, -1, buffer, len, NULL, NULL);
964 buffer += string_len;
965 needed += string_len;
966 len -= string_len;
968 else
969 CredentialA->Comment = NULL;
970 CredentialA->LastWritten = CredentialW->LastWritten;
971 CredentialA->CredentialBlobSize = CredentialW->CredentialBlobSize;
972 if (CredentialW->CredentialBlobSize && (CredentialW->CredentialBlobSize <= len))
974 CredentialA->CredentialBlob =(LPBYTE)buffer;
975 memcpy(CredentialA->CredentialBlob, CredentialW->CredentialBlob,
976 CredentialW->CredentialBlobSize);
977 buffer += CredentialW->CredentialBlobSize;
978 needed += CredentialW->CredentialBlobSize;
979 len -= CredentialW->CredentialBlobSize;
981 else
982 CredentialA->CredentialBlob = NULL;
983 CredentialA->Persist = CredentialW->Persist;
984 CredentialA->AttributeCount = 0;
985 CredentialA->Attributes = NULL; /* FIXME */
986 if (CredentialW->TargetAlias)
988 CredentialA->TargetAlias = buffer;
989 string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetAlias, -1, buffer, len, NULL, NULL);
990 buffer += string_len;
991 needed += string_len;
992 len -= string_len;
994 else
995 CredentialA->TargetAlias = NULL;
996 if (CredentialW->UserName)
998 CredentialA->UserName = buffer;
999 string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->UserName, -1, buffer, len, NULL, NULL);
1000 needed += string_len;
1002 else
1003 CredentialA->UserName = NULL;
1005 return needed;
1008 /******************************************************************************
1009 * convert_PCREDENTIALA_to_PCREDENTIALW [internal]
1011 * convert a Credential struct from ANSI to UNICODE and return the needed size in Bytes
1014 static INT convert_PCREDENTIALA_to_PCREDENTIALW(const CREDENTIALA *CredentialA, PCREDENTIALW CredentialW, INT len)
1016 char *buffer;
1017 INT string_len;
1018 INT needed = sizeof(CREDENTIALW);
1020 if (!CredentialW)
1022 if (CredentialA->TargetName)
1023 needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetName, -1, NULL, 0);
1024 if (CredentialA->Comment)
1025 needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->Comment, -1, NULL, 0);
1026 needed += CredentialA->CredentialBlobSize;
1027 if (CredentialA->TargetAlias)
1028 needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetAlias, -1, NULL, 0);
1029 if (CredentialA->UserName)
1030 needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->UserName, -1, NULL, 0);
1032 return needed;
1035 buffer = (char *)CredentialW + sizeof(CREDENTIALW);
1036 len -= sizeof(CREDENTIALW);
1037 CredentialW->Flags = CredentialA->Flags;
1038 CredentialW->Type = CredentialA->Type;
1039 if (CredentialA->TargetName)
1041 CredentialW->TargetName = (LPWSTR)buffer;
1042 string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetName, -1, CredentialW->TargetName, len / sizeof(WCHAR));
1043 buffer += sizeof(WCHAR) * string_len;
1044 needed += sizeof(WCHAR) * string_len;
1045 len -= sizeof(WCHAR) * string_len;
1047 else
1048 CredentialW->TargetName = NULL;
1049 if (CredentialA->Comment)
1051 CredentialW->Comment = (LPWSTR)buffer;
1052 string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->Comment, -1, CredentialW->Comment, len / sizeof(WCHAR));
1053 buffer += sizeof(WCHAR) * string_len;
1054 needed += sizeof(WCHAR) * string_len;
1055 len -= sizeof(WCHAR) * string_len;
1057 else
1058 CredentialW->Comment = NULL;
1059 CredentialW->LastWritten = CredentialA->LastWritten;
1060 CredentialW->CredentialBlobSize = CredentialA->CredentialBlobSize;
1061 if (CredentialA->CredentialBlobSize)
1063 CredentialW->CredentialBlob =(LPBYTE)buffer;
1064 memcpy(CredentialW->CredentialBlob, CredentialA->CredentialBlob,
1065 CredentialA->CredentialBlobSize);
1066 buffer += CredentialA->CredentialBlobSize;
1067 needed += CredentialA->CredentialBlobSize;
1068 len -= CredentialA->CredentialBlobSize;
1070 else
1071 CredentialW->CredentialBlob = NULL;
1072 CredentialW->Persist = CredentialA->Persist;
1073 CredentialW->AttributeCount = 0;
1074 CredentialW->Attributes = NULL; /* FIXME */
1075 if (CredentialA->TargetAlias)
1077 CredentialW->TargetAlias = (LPWSTR)buffer;
1078 string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetAlias, -1, CredentialW->TargetAlias, len / sizeof(WCHAR));
1079 buffer += sizeof(WCHAR) * string_len;
1080 needed += sizeof(WCHAR) * string_len;
1081 len -= sizeof(WCHAR) * string_len;
1083 else
1084 CredentialW->TargetAlias = NULL;
1085 if (CredentialA->UserName)
1087 CredentialW->UserName = (LPWSTR)buffer;
1088 string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->UserName, -1, CredentialW->UserName, len / sizeof(WCHAR));
1089 needed += sizeof(WCHAR) * string_len;
1091 else
1092 CredentialW->UserName = NULL;
1094 return needed;
1097 /******************************************************************************
1098 * CredDeleteA [ADVAPI32.@]
1100 BOOL WINAPI CredDeleteA(LPCSTR TargetName, DWORD Type, DWORD Flags)
1102 LPWSTR TargetNameW;
1103 DWORD len;
1104 BOOL ret;
1106 TRACE("(%s, %d, 0x%x)\n", debugstr_a(TargetName), Type, Flags);
1108 if (!TargetName)
1110 SetLastError(ERROR_INVALID_PARAMETER);
1111 return FALSE;
1114 len = MultiByteToWideChar(CP_ACP, 0, TargetName, -1, NULL, 0);
1115 TargetNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1116 if (!TargetNameW)
1118 SetLastError(ERROR_OUTOFMEMORY);
1119 return FALSE;
1121 MultiByteToWideChar(CP_ACP, 0, TargetName, -1, TargetNameW, len);
1123 ret = CredDeleteW(TargetNameW, Type, Flags);
1125 HeapFree(GetProcessHeap(), 0, TargetNameW);
1127 return ret;
1130 /******************************************************************************
1131 * CredDeleteW [ADVAPI32.@]
1133 BOOL WINAPI CredDeleteW(LPCWSTR TargetName, DWORD Type, DWORD Flags)
1135 HKEY hkeyMgr;
1136 DWORD ret;
1137 LPWSTR key_name;
1139 TRACE("(%s, %d, 0x%x)\n", debugstr_w(TargetName), Type, Flags);
1141 if (!TargetName)
1143 SetLastError(ERROR_INVALID_PARAMETER);
1144 return FALSE;
1147 if (Type != CRED_TYPE_GENERIC && Type != CRED_TYPE_DOMAIN_PASSWORD)
1149 FIXME("unhandled type %d\n", Type);
1150 SetLastError(ERROR_INVALID_PARAMETER);
1151 return FALSE;
1154 if (Flags)
1156 FIXME("unhandled flags 0x%x\n", Flags);
1157 SetLastError(ERROR_INVALID_FLAGS);
1158 return FALSE;
1161 #ifdef __APPLE__
1162 if (Type == CRED_TYPE_DOMAIN_PASSWORD)
1164 ret = mac_delete_credential(TargetName);
1165 if (ret == ERROR_SUCCESS)
1166 return TRUE;
1168 #endif
1170 ret = open_cred_mgr_key(&hkeyMgr, TRUE);
1171 if (ret != ERROR_SUCCESS)
1173 WARN("couldn't open/create manager key, error %d\n", ret);
1174 SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1175 return FALSE;
1178 key_name = get_key_name_for_target(TargetName, Type);
1179 ret = RegDeleteKeyW(hkeyMgr, key_name);
1180 HeapFree(GetProcessHeap(), 0, key_name);
1181 RegCloseKey(hkeyMgr);
1182 if (ret != ERROR_SUCCESS)
1184 SetLastError(ERROR_NOT_FOUND);
1185 return FALSE;
1188 return TRUE;
1191 /******************************************************************************
1192 * CredEnumerateA [ADVAPI32.@]
1194 BOOL WINAPI CredEnumerateA(LPCSTR Filter, DWORD Flags, DWORD *Count,
1195 PCREDENTIALA **Credentials)
1197 LPWSTR FilterW;
1198 PCREDENTIALW *CredentialsW;
1199 DWORD i;
1200 INT len;
1201 INT needed;
1202 char *buffer;
1204 TRACE("(%s, 0x%x, %p, %p)\n", debugstr_a(Filter), Flags, Count, Credentials);
1206 if (Filter)
1208 len = MultiByteToWideChar(CP_ACP, 0, Filter, -1, NULL, 0);
1209 FilterW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1210 if (!FilterW)
1212 SetLastError(ERROR_OUTOFMEMORY);
1213 return FALSE;
1215 MultiByteToWideChar(CP_ACP, 0, Filter, -1, FilterW, len);
1217 else
1218 FilterW = NULL;
1220 if (!CredEnumerateW(FilterW, Flags, Count, &CredentialsW))
1222 HeapFree(GetProcessHeap(), 0, FilterW);
1223 return FALSE;
1225 HeapFree(GetProcessHeap(), 0, FilterW);
1227 len = *Count * sizeof(PCREDENTIALA);
1228 for (i = 0; i < *Count; i++)
1229 len += convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], NULL, 0);
1231 *Credentials = HeapAlloc(GetProcessHeap(), 0, len);
1232 if (!*Credentials)
1234 CredFree(CredentialsW);
1235 SetLastError(ERROR_OUTOFMEMORY);
1236 return FALSE;
1239 buffer = (char *)&(*Credentials)[*Count];
1240 len -= *Count * sizeof(PCREDENTIALA);
1241 for (i = 0; i < *Count; i++)
1243 (*Credentials)[i] = (PCREDENTIALA)buffer;
1244 needed = convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], (*Credentials)[i], len);
1245 buffer += needed;
1246 len -= needed;
1249 CredFree(CredentialsW);
1251 return TRUE;
1254 /******************************************************************************
1255 * CredEnumerateW [ADVAPI32.@]
1257 BOOL WINAPI CredEnumerateW(LPCWSTR Filter, DWORD Flags, DWORD *Count,
1258 PCREDENTIALW **Credentials)
1260 HKEY hkeyMgr;
1261 DWORD ret;
1262 LPWSTR target_name;
1263 DWORD target_name_len;
1264 DWORD len;
1265 char *buffer;
1266 BYTE key_data[KEY_SIZE];
1268 TRACE("(%s, 0x%x, %p, %p)\n", debugstr_w(Filter), Flags, Count, Credentials);
1270 if (Flags)
1272 SetLastError(ERROR_INVALID_FLAGS);
1273 return FALSE;
1276 ret = open_cred_mgr_key(&hkeyMgr, FALSE);
1277 if (ret != ERROR_SUCCESS)
1279 WARN("couldn't open/create manager key, error %d\n", ret);
1280 SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1281 return FALSE;
1284 ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
1285 if (ret != ERROR_SUCCESS)
1287 RegCloseKey(hkeyMgr);
1288 SetLastError(ret);
1289 return FALSE;
1292 ret = RegQueryInfoKeyW(hkeyMgr, NULL, NULL, NULL, NULL, &target_name_len, NULL, NULL, NULL, NULL, NULL, NULL);
1293 if (ret != ERROR_SUCCESS)
1295 RegCloseKey(hkeyMgr);
1296 SetLastError(ret);
1297 return FALSE;
1300 target_name = HeapAlloc(GetProcessHeap(), 0, (target_name_len+1)*sizeof(WCHAR));
1301 if (!target_name)
1303 RegCloseKey(hkeyMgr);
1304 SetLastError(ERROR_OUTOFMEMORY);
1305 return FALSE;
1308 *Count = 0;
1309 len = 0;
1310 ret = registry_enumerate_credentials(hkeyMgr, Filter, target_name, target_name_len,
1311 key_data, NULL, NULL, &len, Count);
1312 #ifdef __APPLE__
1313 if (ret == ERROR_SUCCESS)
1314 ret = mac_enumerate_credentials(Filter, NULL, NULL, &len, Count);
1315 #endif
1316 if (ret == ERROR_SUCCESS && *Count == 0)
1317 ret = ERROR_NOT_FOUND;
1318 if (ret != ERROR_SUCCESS)
1320 HeapFree(GetProcessHeap(), 0, target_name);
1321 RegCloseKey(hkeyMgr);
1322 SetLastError(ret);
1323 return FALSE;
1325 len += *Count * sizeof(PCREDENTIALW);
1327 if (ret == ERROR_SUCCESS)
1329 buffer = HeapAlloc(GetProcessHeap(), 0, len);
1330 *Credentials = (PCREDENTIALW *)buffer;
1331 if (buffer)
1333 buffer += *Count * sizeof(PCREDENTIALW);
1334 *Count = 0;
1335 ret = registry_enumerate_credentials(hkeyMgr, Filter, target_name,
1336 target_name_len, key_data,
1337 *Credentials, &buffer, &len,
1338 Count);
1339 #ifdef __APPLE__
1340 if (ret == ERROR_SUCCESS)
1341 ret = mac_enumerate_credentials(Filter, *Credentials,
1342 buffer, &len, Count);
1343 #endif
1345 else
1346 ret = ERROR_OUTOFMEMORY;
1349 HeapFree(GetProcessHeap(), 0, target_name);
1350 RegCloseKey(hkeyMgr);
1352 if (ret != ERROR_SUCCESS)
1354 SetLastError(ret);
1355 return FALSE;
1357 return TRUE;
1360 /******************************************************************************
1361 * CredFree [ADVAPI32.@]
1363 VOID WINAPI CredFree(PVOID Buffer)
1365 HeapFree(GetProcessHeap(), 0, Buffer);
1368 /******************************************************************************
1369 * CredReadA [ADVAPI32.@]
1371 BOOL WINAPI CredReadA(LPCSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALA *Credential)
1373 LPWSTR TargetNameW;
1374 PCREDENTIALW CredentialW;
1375 INT len;
1377 TRACE("(%s, %d, 0x%x, %p)\n", debugstr_a(TargetName), Type, Flags, Credential);
1379 if (!TargetName)
1381 SetLastError(ERROR_INVALID_PARAMETER);
1382 return FALSE;
1385 len = MultiByteToWideChar(CP_ACP, 0, TargetName, -1, NULL, 0);
1386 TargetNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1387 if (!TargetNameW)
1389 SetLastError(ERROR_OUTOFMEMORY);
1390 return FALSE;
1392 MultiByteToWideChar(CP_ACP, 0, TargetName, -1, TargetNameW, len);
1394 if (!CredReadW(TargetNameW, Type, Flags, &CredentialW))
1396 HeapFree(GetProcessHeap(), 0, TargetNameW);
1397 return FALSE;
1399 HeapFree(GetProcessHeap(), 0, TargetNameW);
1401 len = convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW, NULL, 0);
1402 *Credential = HeapAlloc(GetProcessHeap(), 0, len);
1403 if (!*Credential)
1405 SetLastError(ERROR_OUTOFMEMORY);
1406 return FALSE;
1408 convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW, *Credential, len);
1410 CredFree(CredentialW);
1412 return TRUE;
1415 /******************************************************************************
1416 * CredReadW [ADVAPI32.@]
1418 BOOL WINAPI CredReadW(LPCWSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALW *Credential)
1420 HKEY hkeyMgr;
1421 HKEY hkeyCred;
1422 DWORD ret;
1423 LPWSTR key_name;
1424 DWORD len;
1425 BYTE key_data[KEY_SIZE];
1427 TRACE("(%s, %d, 0x%x, %p)\n", debugstr_w(TargetName), Type, Flags, Credential);
1429 if (!TargetName)
1431 SetLastError(ERROR_INVALID_PARAMETER);
1432 return FALSE;
1435 if (Type != CRED_TYPE_GENERIC && Type != CRED_TYPE_DOMAIN_PASSWORD)
1437 FIXME("unhandled type %d\n", Type);
1438 SetLastError(ERROR_INVALID_PARAMETER);
1439 return FALSE;
1442 if (Flags)
1444 FIXME("unhandled flags 0x%x\n", Flags);
1445 SetLastError(ERROR_INVALID_FLAGS);
1446 return FALSE;
1449 #ifdef __APPLE__
1450 if (Type == CRED_TYPE_DOMAIN_PASSWORD)
1452 OSStatus status;
1453 SecKeychainSearchRef search;
1454 status = SecKeychainSearchCreateFromAttributes(NULL, kSecInternetPasswordItemClass, NULL, &search);
1455 if (status == noErr)
1457 SecKeychainItemRef item;
1458 while (SecKeychainSearchCopyNext(search, &item) == noErr)
1460 SecKeychainAttributeInfo info;
1461 SecKeychainAttributeList *attr_list;
1462 UInt32 info_tags[] = { kSecServerItemAttr };
1463 LPWSTR target_name;
1464 INT str_len;
1465 info.count = sizeof(info_tags)/sizeof(info_tags[0]);
1466 info.tag = info_tags;
1467 info.format = NULL;
1468 status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, NULL, NULL);
1469 len = sizeof(**Credential);
1470 if (status != noErr)
1472 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status);
1473 continue;
1475 if (attr_list->count != 1 || attr_list->attr[0].tag != kSecServerItemAttr)
1477 CFRelease(item);
1478 continue;
1480 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, NULL, 0);
1481 target_name = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
1482 MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, target_name, str_len);
1483 /* nul terminate */
1484 target_name[str_len] = '\0';
1485 if (strcmpiW(TargetName, target_name))
1487 CFRelease(item);
1488 HeapFree(GetProcessHeap(), 0, target_name);
1489 continue;
1491 HeapFree(GetProcessHeap(), 0, target_name);
1492 SecKeychainItemFreeAttributesAndData(attr_list, NULL);
1493 ret = mac_read_credential_from_item(item, TRUE, NULL, NULL, &len);
1494 if (ret == ERROR_SUCCESS)
1496 *Credential = HeapAlloc(GetProcessHeap(), 0, len);
1497 if (*Credential)
1499 len = sizeof(**Credential);
1500 ret = mac_read_credential_from_item(item, TRUE, *Credential,
1501 (char *)(*Credential + 1), &len);
1503 else
1504 ret = ERROR_OUTOFMEMORY;
1505 CFRelease(item);
1506 CFRelease(search);
1507 if (ret != ERROR_SUCCESS)
1509 SetLastError(ret);
1510 return FALSE;
1512 return TRUE;
1514 CFRelease(item);
1516 CFRelease(search);
1519 #endif
1521 ret = open_cred_mgr_key(&hkeyMgr, FALSE);
1522 if (ret != ERROR_SUCCESS)
1524 WARN("couldn't open/create manager key, error %d\n", ret);
1525 SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1526 return FALSE;
1529 ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
1530 if (ret != ERROR_SUCCESS)
1532 RegCloseKey(hkeyMgr);
1533 SetLastError(ret);
1534 return FALSE;
1537 key_name = get_key_name_for_target(TargetName, Type);
1538 ret = RegOpenKeyExW(hkeyMgr, key_name, 0, KEY_QUERY_VALUE, &hkeyCred);
1539 HeapFree(GetProcessHeap(), 0, key_name);
1540 if (ret != ERROR_SUCCESS)
1542 TRACE("credentials for target name %s not found\n", debugstr_w(TargetName));
1543 SetLastError(ERROR_NOT_FOUND);
1544 return FALSE;
1547 len = sizeof(**Credential);
1548 ret = registry_read_credential(hkeyCred, NULL, key_data, NULL, &len);
1549 if (ret == ERROR_SUCCESS)
1551 *Credential = HeapAlloc(GetProcessHeap(), 0, len);
1552 if (*Credential)
1554 len = sizeof(**Credential);
1555 ret = registry_read_credential(hkeyCred, *Credential, key_data,
1556 (char *)(*Credential + 1), &len);
1558 else
1559 ret = ERROR_OUTOFMEMORY;
1562 RegCloseKey(hkeyCred);
1563 RegCloseKey(hkeyMgr);
1565 if (ret != ERROR_SUCCESS)
1567 SetLastError(ret);
1568 return FALSE;
1570 return TRUE;
1573 /******************************************************************************
1574 * CredReadDomainCredentialsA [ADVAPI32.@]
1576 BOOL WINAPI CredReadDomainCredentialsA(PCREDENTIAL_TARGET_INFORMATIONA TargetInformation,
1577 DWORD Flags, DWORD *Size, PCREDENTIALA **Credentials)
1579 PCREDENTIAL_TARGET_INFORMATIONW TargetInformationW;
1580 INT len;
1581 DWORD i;
1582 WCHAR *buffer, *end;
1583 BOOL ret;
1584 PCREDENTIALW* CredentialsW;
1586 TRACE("(%p, 0x%x, %p, %p)\n", TargetInformation, Flags, Size, Credentials);
1588 /* follow Windows behavior - do not test for NULL, initialize early */
1589 *Size = 0;
1590 *Credentials = NULL;
1592 if (!TargetInformation)
1594 SetLastError(ERROR_INVALID_PARAMETER);
1595 return FALSE;
1598 len = sizeof(*TargetInformationW);
1599 if (TargetInformation->TargetName)
1600 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->TargetName, -1, NULL, 0) * sizeof(WCHAR);
1601 if (TargetInformation->NetbiosServerName)
1602 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosServerName, -1, NULL, 0) * sizeof(WCHAR);
1603 if (TargetInformation->DnsServerName)
1604 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsServerName, -1, NULL, 0) * sizeof(WCHAR);
1605 if (TargetInformation->NetbiosDomainName)
1606 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosDomainName, -1, NULL, 0) * sizeof(WCHAR);
1607 if (TargetInformation->DnsDomainName)
1608 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsDomainName, -1, NULL, 0) * sizeof(WCHAR);
1609 if (TargetInformation->DnsTreeName)
1610 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsTreeName, -1, NULL, 0) * sizeof(WCHAR);
1611 if (TargetInformation->PackageName)
1612 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->PackageName, -1, NULL, 0) * sizeof(WCHAR);
1614 TargetInformationW = HeapAlloc(GetProcessHeap(), 0, len);
1615 if (!TargetInformationW)
1617 SetLastError(ERROR_OUTOFMEMORY);
1618 return FALSE;
1620 buffer = (WCHAR*)(TargetInformationW + 1);
1621 end = (WCHAR *)((char *)TargetInformationW + len);
1623 if (TargetInformation->TargetName)
1625 TargetInformationW->TargetName = buffer;
1626 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->TargetName, -1,
1627 TargetInformationW->TargetName, end - buffer);
1628 } else
1629 TargetInformationW->TargetName = NULL;
1631 if (TargetInformation->NetbiosServerName)
1633 TargetInformationW->NetbiosServerName = buffer;
1634 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosServerName, -1,
1635 TargetInformationW->NetbiosServerName, end - buffer);
1636 } else
1637 TargetInformationW->NetbiosServerName = NULL;
1639 if (TargetInformation->DnsServerName)
1641 TargetInformationW->DnsServerName = buffer;
1642 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsServerName, -1,
1643 TargetInformationW->DnsServerName, end - buffer);
1644 } else
1645 TargetInformationW->DnsServerName = NULL;
1647 if (TargetInformation->NetbiosDomainName)
1649 TargetInformationW->NetbiosDomainName = buffer;
1650 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosDomainName, -1,
1651 TargetInformationW->NetbiosDomainName, end - buffer);
1652 } else
1653 TargetInformationW->NetbiosDomainName = NULL;
1655 if (TargetInformation->DnsDomainName)
1657 TargetInformationW->DnsDomainName = buffer;
1658 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsDomainName, -1,
1659 TargetInformationW->DnsDomainName, end - buffer);
1660 } else
1661 TargetInformationW->DnsDomainName = NULL;
1663 if (TargetInformation->DnsTreeName)
1665 TargetInformationW->DnsTreeName = buffer;
1666 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsTreeName, -1,
1667 TargetInformationW->DnsTreeName, end - buffer);
1668 } else
1669 TargetInformationW->DnsTreeName = NULL;
1671 if (TargetInformation->PackageName)
1673 TargetInformationW->PackageName = buffer;
1674 MultiByteToWideChar(CP_ACP, 0, TargetInformation->PackageName, -1,
1675 TargetInformationW->PackageName, end - buffer);
1676 } else
1677 TargetInformationW->PackageName = NULL;
1679 TargetInformationW->Flags = TargetInformation->Flags;
1680 TargetInformationW->CredTypeCount = TargetInformation->CredTypeCount;
1681 TargetInformationW->CredTypes = TargetInformation->CredTypes;
1683 ret = CredReadDomainCredentialsW(TargetInformationW, Flags, Size, &CredentialsW);
1685 HeapFree(GetProcessHeap(), 0, TargetInformationW);
1687 if (ret)
1689 char *buf;
1690 INT needed;
1692 len = *Size * sizeof(PCREDENTIALA);
1693 for (i = 0; i < *Size; i++)
1694 len += convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], NULL, 0);
1696 *Credentials = HeapAlloc(GetProcessHeap(), 0, len);
1697 if (!*Credentials)
1699 CredFree(CredentialsW);
1700 SetLastError(ERROR_OUTOFMEMORY);
1701 return FALSE;
1704 buf = (char *)&(*Credentials)[*Size];
1705 len -= *Size * sizeof(PCREDENTIALA);
1706 for (i = 0; i < *Size; i++)
1708 (*Credentials)[i] = (PCREDENTIALA)buf;
1709 needed = convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], (*Credentials)[i], len);
1710 buf += needed;
1711 len -= needed;
1714 CredFree(CredentialsW);
1716 return ret;
1719 /******************************************************************************
1720 * CredReadDomainCredentialsW [ADVAPI32.@]
1722 BOOL WINAPI CredReadDomainCredentialsW(PCREDENTIAL_TARGET_INFORMATIONW TargetInformation, DWORD Flags,
1723 DWORD *Size, PCREDENTIALW **Credentials)
1725 FIXME("(%p, 0x%x, %p, %p) stub\n", TargetInformation, Flags, Size, Credentials);
1727 /* follow Windows behavior - do not test for NULL, initialize early */
1728 *Size = 0;
1729 *Credentials = NULL;
1730 if (!TargetInformation)
1732 SetLastError(ERROR_INVALID_PARAMETER);
1733 return FALSE;
1736 SetLastError(ERROR_NOT_FOUND);
1737 return FALSE;
1740 /******************************************************************************
1741 * CredWriteA [ADVAPI32.@]
1743 BOOL WINAPI CredWriteA(PCREDENTIALA Credential, DWORD Flags)
1745 BOOL ret;
1746 INT len;
1747 PCREDENTIALW CredentialW;
1749 TRACE("(%p, 0x%x)\n", Credential, Flags);
1751 if (!Credential || !Credential->TargetName)
1753 SetLastError(ERROR_INVALID_PARAMETER);
1754 return FALSE;
1757 len = convert_PCREDENTIALA_to_PCREDENTIALW(Credential, NULL, 0);
1758 CredentialW = HeapAlloc(GetProcessHeap(), 0, len);
1759 if (!CredentialW)
1761 SetLastError(ERROR_OUTOFMEMORY);
1762 return FALSE;
1765 convert_PCREDENTIALA_to_PCREDENTIALW(Credential, CredentialW, len);
1767 ret = CredWriteW(CredentialW, Flags);
1769 HeapFree(GetProcessHeap(), 0, CredentialW);
1771 return ret;
1774 /******************************************************************************
1775 * CredWriteW [ADVAPI32.@]
1777 BOOL WINAPI CredWriteW(PCREDENTIALW Credential, DWORD Flags)
1779 HKEY hkeyMgr;
1780 HKEY hkeyCred;
1781 DWORD ret;
1782 LPWSTR key_name;
1783 BYTE key_data[KEY_SIZE];
1785 TRACE("(%p, 0x%x)\n", Credential, Flags);
1787 if (!Credential || !Credential->TargetName)
1789 SetLastError(ERROR_INVALID_PARAMETER);
1790 return FALSE;
1793 if (Flags & ~CRED_PRESERVE_CREDENTIAL_BLOB)
1795 FIXME("unhandled flags 0x%x\n", Flags);
1796 SetLastError(ERROR_INVALID_FLAGS);
1797 return FALSE;
1800 if (Credential->Type != CRED_TYPE_GENERIC && Credential->Type != CRED_TYPE_DOMAIN_PASSWORD)
1802 FIXME("unhandled type %d\n", Credential->Type);
1803 SetLastError(ERROR_INVALID_PARAMETER);
1804 return FALSE;
1807 TRACE("Credential->TargetName = %s\n", debugstr_w(Credential->TargetName));
1808 TRACE("Credential->UserName = %s\n", debugstr_w(Credential->UserName));
1810 if (Credential->Type == CRED_TYPE_DOMAIN_PASSWORD)
1812 if (!Credential->UserName ||
1813 (!strchrW(Credential->UserName, '\\') && !strchrW(Credential->UserName, '@')))
1815 ERR("bad username %s\n", debugstr_w(Credential->UserName));
1816 SetLastError(ERROR_BAD_USERNAME);
1817 return FALSE;
1821 #ifdef __APPLE__
1822 if (!Credential->AttributeCount &&
1823 Credential->Type == CRED_TYPE_DOMAIN_PASSWORD &&
1824 (Credential->Persist == CRED_PERSIST_LOCAL_MACHINE || Credential->Persist == CRED_PERSIST_ENTERPRISE))
1826 ret = mac_write_credential(Credential, Flags & CRED_PRESERVE_CREDENTIAL_BLOB);
1827 if (ret != ERROR_SUCCESS)
1829 SetLastError(ret);
1830 return FALSE;
1832 return TRUE;
1834 #endif
1836 ret = open_cred_mgr_key(&hkeyMgr, FALSE);
1837 if (ret != ERROR_SUCCESS)
1839 WARN("couldn't open/create manager key, error %d\n", ret);
1840 SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1841 return FALSE;
1844 ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
1845 if (ret != ERROR_SUCCESS)
1847 RegCloseKey(hkeyMgr);
1848 SetLastError(ret);
1849 return FALSE;
1852 key_name = get_key_name_for_target(Credential->TargetName, Credential->Type);
1853 ret = RegCreateKeyExW(hkeyMgr, key_name, 0, NULL,
1854 Credential->Persist == CRED_PERSIST_SESSION ? REG_OPTION_VOLATILE : REG_OPTION_NON_VOLATILE,
1855 KEY_READ|KEY_WRITE, NULL, &hkeyCred, NULL);
1856 HeapFree(GetProcessHeap(), 0, key_name);
1857 if (ret != ERROR_SUCCESS)
1859 TRACE("credentials for target name %s not found\n",
1860 debugstr_w(Credential->TargetName));
1861 SetLastError(ERROR_NOT_FOUND);
1862 return FALSE;
1865 ret = registry_write_credential(hkeyCred, Credential, key_data,
1866 Flags & CRED_PRESERVE_CREDENTIAL_BLOB);
1868 RegCloseKey(hkeyCred);
1869 RegCloseKey(hkeyMgr);
1871 if (ret != ERROR_SUCCESS)
1873 SetLastError(ret);
1874 return FALSE;
1876 return TRUE;
1879 /******************************************************************************
1880 * CredGetSessionTypes [ADVAPI32.@]
1882 WINADVAPI BOOL WINAPI CredGetSessionTypes(DWORD persistCount, LPDWORD persists)
1884 TRACE("(%u, %p)\n", persistCount, persists);
1886 memset(persists, CRED_PERSIST_NONE, persistCount*sizeof(*persists));
1887 if (CRED_TYPE_GENERIC < persistCount)
1889 persists[CRED_TYPE_GENERIC] = CRED_PERSIST_ENTERPRISE;
1891 if (CRED_TYPE_DOMAIN_PASSWORD < persistCount)
1893 persists[CRED_TYPE_DOMAIN_PASSWORD] = CRED_PERSIST_ENTERPRISE;
1896 return TRUE;
1899 /******************************************************************************
1900 * CredMarshalCredentialA [ADVAPI32.@]
1902 BOOL WINAPI CredMarshalCredentialA( CRED_MARSHAL_TYPE type, PVOID cred, LPSTR *out )
1904 BOOL ret;
1905 WCHAR *outW;
1907 TRACE("%u, %p, %p\n", type, cred, out);
1909 if ((ret = CredMarshalCredentialW( type, cred, &outW )))
1911 int len = WideCharToMultiByte( CP_ACP, 0, outW, -1, NULL, 0, NULL, NULL );
1912 if (!(*out = HeapAlloc( GetProcessHeap(), 0, len )))
1914 HeapFree( GetProcessHeap(), 0, outW );
1915 return FALSE;
1917 WideCharToMultiByte( CP_ACP, 0, outW, -1, *out, len, NULL, NULL );
1918 HeapFree( GetProcessHeap(), 0, outW );
1920 return ret;
1923 static UINT cred_encode( const char *bin, unsigned int len, WCHAR *cred )
1925 static char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#-";
1926 UINT n = 0, x;
1928 while (len > 0)
1930 cred[n++] = enc[bin[0] & 0x3f];
1931 x = (bin[0] & 0xc0) >> 6;
1932 if (len == 1)
1934 cred[n++] = enc[x];
1935 break;
1937 cred[n++] = enc[((bin[1] & 0xf) << 2) | x];
1938 x = (bin[1] & 0xf0) >> 4;
1939 if (len == 2)
1941 cred[n++] = enc[x];
1942 break;
1944 cred[n++] = enc[((bin[2] & 0x3) << 4) | x];
1945 cred[n++] = enc[(bin[2] & 0xfc) >> 2];
1946 bin += 3;
1947 len -= 3;
1949 return n;
1952 /******************************************************************************
1953 * CredMarshalCredentialW [ADVAPI32.@]
1955 BOOL WINAPI CredMarshalCredentialW( CRED_MARSHAL_TYPE type, PVOID cred, LPWSTR *out )
1957 CERT_CREDENTIAL_INFO *cert = cred;
1958 USERNAME_TARGET_CREDENTIAL_INFO *target = cred;
1959 DWORD len, size;
1960 WCHAR *p;
1962 TRACE("%u, %p, %p\n", type, cred, out);
1964 if (!cred || (type == CertCredential && cert->cbSize < sizeof(*cert)) ||
1965 (type != CertCredential && type != UsernameTargetCredential && type != BinaryBlobCredential) ||
1966 (type == UsernameTargetCredential && (!target->UserName || !target->UserName[0])))
1968 SetLastError( ERROR_INVALID_PARAMETER );
1969 return FALSE;
1971 switch (type)
1973 case CertCredential:
1975 char hash[CERT_HASH_LENGTH + 2];
1977 memcpy( hash, cert->rgbHashOfCert, sizeof(cert->rgbHashOfCert) );
1978 memset( hash + sizeof(cert->rgbHashOfCert), 0, sizeof(hash) - sizeof(cert->rgbHashOfCert) );
1980 size = sizeof(hash) * 4 / 3;
1981 if (!(p = HeapAlloc( GetProcessHeap(), 0, (size + 4) * sizeof(WCHAR) ))) return FALSE;
1982 p[0] = '@';
1983 p[1] = '@';
1984 p[2] = 'A' + type;
1985 len = cred_encode( (const char *)hash, sizeof(hash), p + 3 );
1986 p[len] = 0;
1987 break;
1989 case UsernameTargetCredential:
1991 len = strlenW( target->UserName );
1992 size = (sizeof(DWORD) + len * sizeof(WCHAR) + 2) * 4 / 3;
1993 if (!(p = HeapAlloc( GetProcessHeap(), 0, (size + 4) * sizeof(WCHAR) ))) return FALSE;
1994 p[0] = '@';
1995 p[1] = '@';
1996 p[2] = 'A' + type;
1997 size = len * sizeof(WCHAR);
1998 len = cred_encode( (const char *)&size, sizeof(DWORD), p + 3 );
1999 len += cred_encode( (const char *)target->UserName, size, p + 3 + len );
2000 p[len + 3] = 0;
2001 break;
2003 case BinaryBlobCredential:
2004 FIXME("BinaryBlobCredential not implemented\n");
2005 return FALSE;
2006 default:
2007 return FALSE;
2009 *out = p;
2010 return TRUE;
2013 /******************************************************************************
2014 * CredUnmarshalCredentialA [ADVAPI32.@]
2016 BOOL WINAPI CredUnmarshalCredentialA( LPCSTR cred, PCRED_MARSHAL_TYPE type, PVOID *out )
2018 BOOL ret;
2019 WCHAR *credW = NULL;
2021 TRACE("%s, %p, %p\n", debugstr_a(cred), type, out);
2023 if (cred)
2025 int len = MultiByteToWideChar( CP_ACP, 0, cred, -1, NULL, 0 );
2026 if (!(credW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
2027 MultiByteToWideChar( CP_ACP, 0, cred, -1, credW, len );
2029 ret = CredUnmarshalCredentialW( credW, type, out );
2030 HeapFree( GetProcessHeap(), 0, credW );
2031 return ret;
2034 static inline char char_decode( WCHAR c )
2036 if (c >= 'A' && c <= 'Z') return c - 'A';
2037 if (c >= 'a' && c <= 'z') return c - 'a' + 26;
2038 if (c >= '0' && c <= '9') return c - '0' + 52;
2039 if (c == '#') return 62;
2040 if (c == '-') return 63;
2041 return 64;
2044 static BOOL cred_decode( const WCHAR *cred, unsigned int len, char *buf )
2046 unsigned int i = 0;
2047 char c0, c1, c2, c3;
2048 const WCHAR *p = cred;
2050 while (len >= 4)
2052 if ((c0 = char_decode( p[0] )) > 63) return FALSE;
2053 if ((c1 = char_decode( p[1] )) > 63) return FALSE;
2054 if ((c2 = char_decode( p[2] )) > 63) return FALSE;
2055 if ((c3 = char_decode( p[3] )) > 63) return FALSE;
2057 buf[i + 0] = (c1 << 6) | c0;
2058 buf[i + 1] = (c2 << 4) | (c1 >> 2);
2059 buf[i + 2] = (c3 << 2) | (c2 >> 4);
2060 len -= 4;
2061 i += 3;
2062 p += 4;
2064 if (len == 3)
2066 if ((c0 = char_decode( p[0] )) > 63) return FALSE;
2067 if ((c1 = char_decode( p[1] )) > 63) return FALSE;
2068 if ((c2 = char_decode( p[2] )) > 63) return FALSE;
2070 buf[i + 0] = (c1 << 6) | c0;
2071 buf[i + 1] = (c2 << 4) | (c1 >> 2);
2072 buf[i + 2] = c2 >> 4;
2074 else if (len == 2)
2076 if ((c0 = char_decode( p[0] )) > 63) return FALSE;
2077 if ((c1 = char_decode( p[1] )) > 63) return FALSE;
2079 buf[i + 0] = (c1 << 6) | c0;
2080 buf[i + 1] = c1 >> 2;
2081 buf[i + 2] = 0;
2083 else if (len == 1)
2085 if ((c0 = char_decode( p[0] )) > 63) return FALSE;
2087 buf[i + 0] = c0;
2088 buf[i + 1] = 0;
2089 buf[i + 2] = 0;
2091 return TRUE;
2094 /******************************************************************************
2095 * CredUnmarshalCredentialW [ADVAPI32.@]
2097 BOOL WINAPI CredUnmarshalCredentialW( LPCWSTR cred, PCRED_MARSHAL_TYPE type, PVOID *out )
2099 unsigned int len, buflen, size;
2101 TRACE("%s, %p, %p\n", debugstr_w(cred), type, out);
2103 if (!cred || cred[0] != '@' || cred[1] != '@' || !cred[2] || !cred[3])
2105 SetLastError( ERROR_INVALID_PARAMETER );
2106 return FALSE;
2108 len = strlenW( cred + 3 );
2109 switch (cred[2] - 'A')
2111 case CertCredential:
2113 char hash[CERT_HASH_LENGTH + 2];
2114 CERT_CREDENTIAL_INFO *cert;
2116 if (len != 27 || !cred_decode( cred + 3, len, hash ))
2118 SetLastError( ERROR_INVALID_PARAMETER );
2119 return FALSE;
2121 if (!(cert = HeapAlloc( GetProcessHeap(), 0, sizeof(*cert) ))) return FALSE;
2122 memcpy( cert->rgbHashOfCert, hash, sizeof(cert->rgbHashOfCert) );
2123 cert->cbSize = sizeof(*cert);
2124 *type = CertCredential;
2125 *out = cert;
2126 break;
2128 case UsernameTargetCredential:
2130 USERNAME_TARGET_CREDENTIAL_INFO *target;
2132 if (len < 9 || !cred_decode( cred + 3, 6, (char *)&size ) || !size || size % sizeof(WCHAR))
2134 SetLastError( ERROR_INVALID_PARAMETER );
2135 return FALSE;
2137 buflen = sizeof(*target) + size + sizeof(WCHAR);
2138 if (!(target = HeapAlloc( GetProcessHeap(), 0, buflen ))) return FALSE;
2139 if (!cred_decode( cred + 9, len - 6, (char *)(target + 1) ))
2141 HeapFree( GetProcessHeap(), 0, target );
2142 return FALSE;
2144 target->UserName = (WCHAR *)(target + 1);
2145 target->UserName[size / sizeof(WCHAR)] = 0;
2146 *type = UsernameTargetCredential;
2147 *out = target;
2148 break;
2150 case BinaryBlobCredential:
2151 FIXME("BinaryBlobCredential not implemented\n");
2152 return FALSE;
2153 default:
2154 WARN("unhandled type %u\n", cred[2] - 'A');
2155 return FALSE;
2157 return TRUE;
2160 /******************************************************************************
2161 * CredIsMarshaledCredentialW [ADVAPI32.@]
2163 * Check, if the name parameter is a marshaled credential, hash or binary blob
2165 * PARAMS
2166 * name the name to check
2168 * RETURNS
2169 * TRUE: the name parameter is a marshaled credential, hash or binary blob
2170 * FALSE: the name is a plain username
2172 BOOL WINAPI CredIsMarshaledCredentialW(LPCWSTR name)
2174 TRACE("(%s)\n", debugstr_w(name));
2176 if (name && name[0] == '@' && name[1] == '@' && name[2] > 'A' && name[3])
2178 char hash[CERT_HASH_LENGTH + 2];
2179 int len = strlenW(name + 3 );
2180 DWORD size;
2182 if ((name[2] - 'A') == CertCredential && (len == 27) && cred_decode(name + 3, len, hash))
2183 return TRUE;
2185 if (((name[2] - 'A') == UsernameTargetCredential) &&
2186 (len >= 9) && cred_decode(name + 3, 6, (char *)&size) && size)
2187 return TRUE;
2189 if ((name[2] - 'A') == BinaryBlobCredential)
2190 FIXME("BinaryBlobCredential not checked\n");
2192 if ((name[2] - 'A') > BinaryBlobCredential)
2193 TRACE("unknown type: %d\n", (name[2] - 'A'));
2196 SetLastError(ERROR_INVALID_PARAMETER);
2197 return FALSE;
2200 /******************************************************************************
2201 * CredIsMarshaledCredentialA [ADVAPI32.@]
2203 * See CredIsMarshaledCredentialW
2206 BOOL WINAPI CredIsMarshaledCredentialA(LPCSTR name)
2208 LPWSTR nameW = NULL;
2209 BOOL res;
2210 int len;
2212 TRACE("(%s)\n", debugstr_a(name));
2214 if (name)
2216 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
2217 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2218 MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, len);
2221 res = CredIsMarshaledCredentialW(nameW);
2222 HeapFree(GetProcessHeap(), 0, nameW);
2223 return res;