user32/tests: Add tests for MonitorFromRect.
[wine.git] / dlls / advapi32 / cred.c
blobb80601934c5ee9fa08bea300d36589b3efaad628
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>
23 #include <limits.h>
25 #ifdef __APPLE__
26 # include <Security/SecKeychain.h>
27 # include <Security/SecKeychainItem.h>
28 # include <Security/SecKeychainSearch.h>
29 #endif
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winreg.h"
34 #include "wincred.h"
35 #include "winternl.h"
37 #include "crypt.h"
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(cred);
44 /* the size of the ARC4 key used to encrypt the password data */
45 #define KEY_SIZE 8
47 static const WCHAR wszCredentialManagerKey[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
48 'C','r','e','d','e','n','t','i','a','l',' ','M','a','n','a','g','e','r',0};
49 static const WCHAR wszEncryptionKeyValue[] = {'E','n','c','r','y','p','t','i','o','n','K','e','y',0};
51 static const WCHAR wszFlagsValue[] = {'F','l','a','g','s',0};
52 static const WCHAR wszTypeValue[] = {'T','y','p','e',0};
53 static const WCHAR wszCommentValue[] = {'C','o','m','m','e','n','t',0};
54 static const WCHAR wszLastWrittenValue[] = {'L','a','s','t','W','r','i','t','t','e','n',0};
55 static const WCHAR wszPersistValue[] = {'P','e','r','s','i','s','t',0};
56 static const WCHAR wszTargetAliasValue[] = {'T','a','r','g','e','t','A','l','i','a','s',0};
57 static const WCHAR wszUserNameValue[] = {'U','s','e','r','N','a','m','e',0};
58 static const WCHAR wszPasswordValue[] = {'P','a','s','s','w','o','r','d',0};
60 static DWORD read_credential_blob(HKEY hkey, const BYTE key_data[KEY_SIZE],
61 LPBYTE credential_blob,
62 DWORD *credential_blob_size)
64 DWORD ret;
65 DWORD type;
67 *credential_blob_size = 0;
68 ret = RegQueryValueExW(hkey, wszPasswordValue, 0, &type, NULL, credential_blob_size);
69 if (ret != ERROR_SUCCESS)
70 return ret;
71 else if (type != REG_BINARY)
72 return ERROR_REGISTRY_CORRUPT;
73 if (credential_blob)
75 struct ustring data;
76 struct ustring key;
78 ret = RegQueryValueExW(hkey, wszPasswordValue, 0, &type, credential_blob,
79 credential_blob_size);
80 if (ret != ERROR_SUCCESS)
81 return ret;
82 else if (type != REG_BINARY)
83 return ERROR_REGISTRY_CORRUPT;
85 key.Length = key.MaximumLength = KEY_SIZE;
86 key.Buffer = (unsigned char *)key_data;
88 data.Length = data.MaximumLength = *credential_blob_size;
89 data.Buffer = credential_blob;
90 SystemFunction032(&data, &key);
92 return ERROR_SUCCESS;
95 static DWORD registry_read_credential(HKEY hkey, PCREDENTIALW credential,
96 const BYTE key_data[KEY_SIZE],
97 char *buffer, DWORD *len)
99 DWORD type;
100 DWORD ret;
101 DWORD count;
103 ret = RegQueryValueExW(hkey, NULL, 0, &type, NULL, &count);
104 if (ret != ERROR_SUCCESS)
105 return ret;
106 else if (type != REG_SZ)
107 return ERROR_REGISTRY_CORRUPT;
108 *len += count;
109 if (credential)
111 credential->TargetName = (LPWSTR)buffer;
112 ret = RegQueryValueExW(hkey, NULL, 0, &type, (LPVOID)credential->TargetName,
113 &count);
114 if (ret != ERROR_SUCCESS || type != REG_SZ) return ret;
115 buffer += count;
118 ret = RegQueryValueExW(hkey, wszCommentValue, 0, &type, NULL, &count);
119 if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
120 return ret;
121 else if (type != REG_SZ)
122 return ERROR_REGISTRY_CORRUPT;
123 *len += count;
124 if (credential)
126 credential->Comment = (LPWSTR)buffer;
127 ret = RegQueryValueExW(hkey, wszCommentValue, 0, &type, (LPVOID)credential->Comment,
128 &count);
129 if (ret == ERROR_FILE_NOT_FOUND)
130 credential->Comment = NULL;
131 else if (ret != ERROR_SUCCESS)
132 return ret;
133 else if (type != REG_SZ)
134 return ERROR_REGISTRY_CORRUPT;
135 else
136 buffer += count;
139 ret = RegQueryValueExW(hkey, wszTargetAliasValue, 0, &type, NULL, &count);
140 if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
141 return ret;
142 else if (type != REG_SZ)
143 return ERROR_REGISTRY_CORRUPT;
144 *len += count;
145 if (credential)
147 credential->TargetAlias = (LPWSTR)buffer;
148 ret = RegQueryValueExW(hkey, wszTargetAliasValue, 0, &type, (LPVOID)credential->TargetAlias,
149 &count);
150 if (ret == ERROR_FILE_NOT_FOUND)
151 credential->TargetAlias = NULL;
152 else if (ret != ERROR_SUCCESS)
153 return ret;
154 else if (type != REG_SZ)
155 return ERROR_REGISTRY_CORRUPT;
156 else
157 buffer += count;
160 ret = RegQueryValueExW(hkey, wszUserNameValue, 0, &type, NULL, &count);
161 if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
162 return ret;
163 else if (type != REG_SZ)
164 return ERROR_REGISTRY_CORRUPT;
165 *len += count;
166 if (credential)
168 credential->UserName = (LPWSTR)buffer;
169 ret = RegQueryValueExW(hkey, wszUserNameValue, 0, &type, (LPVOID)credential->UserName,
170 &count);
171 if (ret == ERROR_FILE_NOT_FOUND)
172 credential->UserName = NULL;
173 else if (ret != ERROR_SUCCESS)
174 return ret;
175 else if (type != REG_SZ)
176 return ERROR_REGISTRY_CORRUPT;
177 else
178 buffer += count;
181 ret = read_credential_blob(hkey, key_data, NULL, &count);
182 if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
183 return ret;
184 *len += count;
185 if (credential)
187 credential->CredentialBlob = (LPBYTE)buffer;
188 ret = read_credential_blob(hkey, key_data, credential->CredentialBlob, &count);
189 if (ret == ERROR_FILE_NOT_FOUND)
190 credential->CredentialBlob = NULL;
191 else if (ret != ERROR_SUCCESS)
192 return ret;
193 credential->CredentialBlobSize = count;
196 /* FIXME: Attributes */
197 if (credential)
199 credential->AttributeCount = 0;
200 credential->Attributes = NULL;
203 if (!credential) return ERROR_SUCCESS;
205 count = sizeof(credential->Flags);
206 ret = RegQueryValueExW(hkey, wszFlagsValue, NULL, &type, (LPVOID)&credential->Flags,
207 &count);
208 if (ret != ERROR_SUCCESS)
209 return ret;
210 else if (type != REG_DWORD)
211 return ERROR_REGISTRY_CORRUPT;
212 count = sizeof(credential->Type);
213 ret = RegQueryValueExW(hkey, wszTypeValue, NULL, &type, (LPVOID)&credential->Type,
214 &count);
215 if (ret != ERROR_SUCCESS)
216 return ret;
217 else if (type != REG_DWORD)
218 return ERROR_REGISTRY_CORRUPT;
220 count = sizeof(credential->LastWritten);
221 ret = RegQueryValueExW(hkey, wszLastWrittenValue, NULL, &type, (LPVOID)&credential->LastWritten,
222 &count);
223 if (ret != ERROR_SUCCESS)
224 return ret;
225 else if (type != REG_BINARY)
226 return ERROR_REGISTRY_CORRUPT;
227 count = sizeof(credential->Persist);
228 ret = RegQueryValueExW(hkey, wszPersistValue, NULL, &type, (LPVOID)&credential->Persist,
229 &count);
230 if (ret == ERROR_SUCCESS && type != REG_DWORD)
231 return ERROR_REGISTRY_CORRUPT;
232 return ret;
235 #ifdef __APPLE__
236 static DWORD mac_read_credential_from_item(SecKeychainItemRef item, BOOL require_password,
237 PCREDENTIALW credential, char *buffer,
238 DWORD *len)
240 OSStatus status;
241 UInt32 i;
242 UInt32 cred_blob_len;
243 void *cred_blob;
244 LPWSTR domain = NULL;
245 LPWSTR user = NULL;
246 BOOL user_name_present = FALSE;
247 SecKeychainAttributeInfo info;
248 SecKeychainAttributeList *attr_list;
249 UInt32 info_tags[] = { kSecServerItemAttr, kSecSecurityDomainItemAttr, kSecAccountItemAttr,
250 kSecCommentItemAttr, kSecCreationDateItemAttr };
251 info.count = sizeof(info_tags)/sizeof(info_tags[0]);
252 info.tag = info_tags;
253 info.format = NULL;
254 status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, &cred_blob_len, &cred_blob);
255 if (status == errSecAuthFailed && !require_password)
257 cred_blob_len = 0;
258 cred_blob = NULL;
259 status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, &cred_blob_len, NULL);
261 if (status != noErr)
263 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status);
264 return ERROR_NOT_FOUND;
267 for (i = 0; i < attr_list->count; i++)
268 if (attr_list->attr[i].tag == kSecAccountItemAttr && attr_list->attr[i].data)
270 user_name_present = TRUE;
271 break;
273 if (!user_name_present)
275 WARN("no kSecAccountItemAttr for item\n");
276 SecKeychainItemFreeAttributesAndData(attr_list, cred_blob);
277 return ERROR_NOT_FOUND;
280 if (buffer)
282 credential->Flags = 0;
283 credential->Type = CRED_TYPE_DOMAIN_PASSWORD;
284 credential->TargetName = NULL;
285 credential->Comment = NULL;
286 memset(&credential->LastWritten, 0, sizeof(credential->LastWritten));
287 credential->CredentialBlobSize = 0;
288 credential->CredentialBlob = NULL;
289 credential->Persist = CRED_PERSIST_LOCAL_MACHINE;
290 credential->AttributeCount = 0;
291 credential->Attributes = NULL;
292 credential->TargetAlias = NULL;
293 credential->UserName = NULL;
295 for (i = 0; i < attr_list->count; i++)
297 switch (attr_list->attr[i].tag)
299 case kSecServerItemAttr:
300 TRACE("kSecServerItemAttr: %.*s\n", (int)attr_list->attr[i].length,
301 (char *)attr_list->attr[i].data);
302 if (!attr_list->attr[i].data) continue;
303 if (buffer)
305 INT str_len;
306 credential->TargetName = (LPWSTR)buffer;
307 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
308 attr_list->attr[i].length, (LPWSTR)buffer, 0xffff);
309 credential->TargetName[str_len] = '\0';
310 buffer += (str_len + 1) * sizeof(WCHAR);
311 *len += (str_len + 1) * sizeof(WCHAR);
313 else
315 INT str_len;
316 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
317 attr_list->attr[i].length, NULL, 0);
318 *len += (str_len + 1) * sizeof(WCHAR);
320 break;
321 case kSecAccountItemAttr:
323 INT str_len;
324 TRACE("kSecAccountItemAttr: %.*s\n", (int)attr_list->attr[i].length,
325 (char *)attr_list->attr[i].data);
326 if (!attr_list->attr[i].data) continue;
327 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
328 attr_list->attr[i].length, NULL, 0);
329 user = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
330 MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
331 attr_list->attr[i].length, user, str_len);
332 user[str_len] = '\0';
333 break;
335 case kSecCommentItemAttr:
336 TRACE("kSecCommentItemAttr: %.*s\n", (int)attr_list->attr[i].length,
337 (char *)attr_list->attr[i].data);
338 if (!attr_list->attr[i].data) continue;
339 if (buffer)
341 INT str_len;
342 credential->Comment = (LPWSTR)buffer;
343 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
344 attr_list->attr[i].length, (LPWSTR)buffer, 0xffff);
345 credential->Comment[str_len] = '\0';
346 buffer += (str_len + 1) * sizeof(WCHAR);
347 *len += (str_len + 1) * sizeof(WCHAR);
349 else
351 INT str_len;
352 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
353 attr_list->attr[i].length, NULL, 0);
354 *len += (str_len + 1) * sizeof(WCHAR);
356 break;
357 case kSecSecurityDomainItemAttr:
359 INT str_len;
360 TRACE("kSecSecurityDomainItemAttr: %.*s\n", (int)attr_list->attr[i].length,
361 (char *)attr_list->attr[i].data);
362 if (!attr_list->attr[i].data) continue;
363 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
364 attr_list->attr[i].length, NULL, 0);
365 domain = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
366 MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
367 attr_list->attr[i].length, domain, str_len);
368 domain[str_len] = '\0';
369 break;
371 case kSecCreationDateItemAttr:
372 TRACE("kSecCreationDateItemAttr: %.*s\n", (int)attr_list->attr[i].length,
373 (char *)attr_list->attr[i].data);
374 if (buffer)
376 LARGE_INTEGER win_time;
377 struct tm tm;
378 time_t time;
379 memset(&tm, 0, sizeof(tm));
380 strptime(attr_list->attr[i].data, "%Y%m%d%H%M%SZ", &tm);
381 time = mktime(&tm);
382 RtlSecondsSince1970ToTime(time, &win_time);
383 credential->LastWritten.dwLowDateTime = win_time.u.LowPart;
384 credential->LastWritten.dwHighDateTime = win_time.u.HighPart;
386 break;
390 if (user)
392 INT str_len;
393 if (buffer)
394 credential->UserName = (LPWSTR)buffer;
395 if (domain)
397 str_len = strlenW(domain);
398 *len += (str_len + 1) * sizeof(WCHAR);
399 if (buffer)
401 memcpy(credential->UserName, domain, str_len * sizeof(WCHAR));
402 /* FIXME: figure out when to use an '@' */
403 credential->UserName[str_len] = '\\';
404 buffer += (str_len + 1) * sizeof(WCHAR);
407 str_len = strlenW(user);
408 *len += (str_len + 1) * sizeof(WCHAR);
409 if (buffer)
411 memcpy(buffer, user, (str_len + 1) * sizeof(WCHAR));
412 buffer += (str_len + 1) * sizeof(WCHAR);
413 TRACE("UserName = %s\n", debugstr_w(credential->UserName));
416 HeapFree(GetProcessHeap(), 0, user);
417 HeapFree(GetProcessHeap(), 0, domain);
419 if (cred_blob)
421 if (buffer)
423 INT str_len;
424 credential->CredentialBlob = (BYTE *)buffer;
425 str_len = MultiByteToWideChar(CP_UTF8, 0, cred_blob, cred_blob_len,
426 (LPWSTR)buffer, 0xffff);
427 credential->CredentialBlobSize = str_len * sizeof(WCHAR);
428 *len += str_len * sizeof(WCHAR);
430 else
432 INT str_len;
433 str_len = MultiByteToWideChar(CP_UTF8, 0, cred_blob, cred_blob_len,
434 NULL, 0);
435 *len += str_len * sizeof(WCHAR);
438 SecKeychainItemFreeAttributesAndData(attr_list, cred_blob);
439 return ERROR_SUCCESS;
441 #endif
443 static DWORD write_credential_blob(HKEY hkey, LPCWSTR target_name, DWORD type,
444 const BYTE key_data[KEY_SIZE],
445 const BYTE *credential_blob, DWORD credential_blob_size)
447 LPBYTE encrypted_credential_blob;
448 struct ustring data;
449 struct ustring key;
450 DWORD ret;
452 key.Length = key.MaximumLength = KEY_SIZE;
453 key.Buffer = (unsigned char *)key_data;
455 encrypted_credential_blob = HeapAlloc(GetProcessHeap(), 0, credential_blob_size);
456 if (!encrypted_credential_blob) return ERROR_OUTOFMEMORY;
458 memcpy(encrypted_credential_blob, credential_blob, credential_blob_size);
459 data.Length = data.MaximumLength = credential_blob_size;
460 data.Buffer = encrypted_credential_blob;
461 SystemFunction032(&data, &key);
463 ret = RegSetValueExW(hkey, wszPasswordValue, 0, REG_BINARY, encrypted_credential_blob, credential_blob_size);
464 HeapFree(GetProcessHeap(), 0, encrypted_credential_blob);
466 return ret;
469 static DWORD registry_write_credential(HKEY hkey, const CREDENTIALW *credential,
470 const BYTE key_data[KEY_SIZE], BOOL preserve_blob)
472 DWORD ret;
473 FILETIME LastWritten;
475 GetSystemTimeAsFileTime(&LastWritten);
477 ret = RegSetValueExW(hkey, wszFlagsValue, 0, REG_DWORD, (const BYTE*)&credential->Flags,
478 sizeof(credential->Flags));
479 if (ret != ERROR_SUCCESS) return ret;
480 ret = RegSetValueExW(hkey, wszTypeValue, 0, REG_DWORD, (const BYTE*)&credential->Type,
481 sizeof(credential->Type));
482 if (ret != ERROR_SUCCESS) return ret;
483 ret = RegSetValueExW(hkey, NULL, 0, REG_SZ, (LPVOID)credential->TargetName,
484 sizeof(WCHAR)*(strlenW(credential->TargetName)+1));
485 if (ret != ERROR_SUCCESS) return ret;
486 if (credential->Comment)
488 ret = RegSetValueExW(hkey, wszCommentValue, 0, REG_SZ, (LPVOID)credential->Comment,
489 sizeof(WCHAR)*(strlenW(credential->Comment)+1));
490 if (ret != ERROR_SUCCESS) return ret;
492 ret = RegSetValueExW(hkey, wszLastWrittenValue, 0, REG_BINARY, (LPVOID)&LastWritten,
493 sizeof(LastWritten));
494 if (ret != ERROR_SUCCESS) return ret;
495 ret = RegSetValueExW(hkey, wszPersistValue, 0, REG_DWORD, (const BYTE*)&credential->Persist,
496 sizeof(credential->Persist));
497 if (ret != ERROR_SUCCESS) return ret;
498 /* FIXME: Attributes */
499 if (credential->TargetAlias)
501 ret = RegSetValueExW(hkey, wszTargetAliasValue, 0, REG_SZ, (LPVOID)credential->TargetAlias,
502 sizeof(WCHAR)*(strlenW(credential->TargetAlias)+1));
503 if (ret != ERROR_SUCCESS) return ret;
505 if (credential->UserName)
507 ret = RegSetValueExW(hkey, wszUserNameValue, 0, REG_SZ, (LPVOID)credential->UserName,
508 sizeof(WCHAR)*(strlenW(credential->UserName)+1));
509 if (ret != ERROR_SUCCESS) return ret;
511 if (!preserve_blob)
513 ret = write_credential_blob(hkey, credential->TargetName, credential->Type,
514 key_data, credential->CredentialBlob,
515 credential->CredentialBlobSize);
517 return ret;
520 #ifdef __APPLE__
521 static DWORD mac_write_credential(const CREDENTIALW *credential, BOOL preserve_blob)
523 OSStatus status;
524 SecKeychainItemRef keychain_item;
525 char *username;
526 char *domain = NULL;
527 char *password;
528 char *servername;
529 UInt32 userlen;
530 UInt32 domainlen = 0;
531 UInt32 pwlen;
532 UInt32 serverlen;
533 LPCWSTR p;
534 SecKeychainAttribute attrs[1];
535 SecKeychainAttributeList attr_list;
537 if (credential->Flags)
538 FIXME("Flags 0x%x not written\n", credential->Flags);
539 if (credential->Type != CRED_TYPE_DOMAIN_PASSWORD)
540 FIXME("credential type of %d not supported\n", credential->Type);
541 if (credential->Persist != CRED_PERSIST_LOCAL_MACHINE)
542 FIXME("persist value of %d not supported\n", credential->Persist);
543 if (credential->AttributeCount)
544 FIXME("custom attributes not supported\n");
546 p = strchrW(credential->UserName, '\\');
547 if (p)
549 domainlen = WideCharToMultiByte(CP_UTF8, 0, credential->UserName,
550 p - credential->UserName, NULL, 0, NULL, NULL);
551 domain = HeapAlloc(GetProcessHeap(), 0, (domainlen + 1) * sizeof(*domain));
552 WideCharToMultiByte(CP_UTF8, 0, credential->UserName, p - credential->UserName,
553 domain, domainlen, NULL, NULL);
554 domain[domainlen] = '\0';
555 p++;
557 else
558 p = credential->UserName;
559 userlen = WideCharToMultiByte(CP_UTF8, 0, p, -1, NULL, 0, NULL, NULL);
560 username = HeapAlloc(GetProcessHeap(), 0, userlen * sizeof(*username));
561 WideCharToMultiByte(CP_UTF8, 0, p, -1, username, userlen, NULL, NULL);
563 serverlen = WideCharToMultiByte(CP_UTF8, 0, credential->TargetName, -1, NULL, 0, NULL, NULL);
564 servername = HeapAlloc(GetProcessHeap(), 0, serverlen * sizeof(*servername));
565 WideCharToMultiByte(CP_UTF8, 0, credential->TargetName, -1, servername, serverlen, NULL, NULL);
566 pwlen = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)credential->CredentialBlob,
567 credential->CredentialBlobSize / sizeof(WCHAR), NULL, 0, NULL, NULL);
568 password = HeapAlloc(GetProcessHeap(), 0, pwlen * sizeof(*domain));
569 WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)credential->CredentialBlob,
570 credential->CredentialBlobSize / sizeof(WCHAR), password, pwlen, NULL, NULL);
572 TRACE("adding server %s, domain %s, username %s using Keychain\n", servername, domain, username);
573 status = SecKeychainAddInternetPassword(NULL, strlen(servername), servername,
574 domain ? strlen(domain) : 0, domain, strlen(username),
575 username, 0, NULL, 0,
576 0 /* no protocol */,
577 kSecAuthenticationTypeDefault,
578 strlen(password), password, &keychain_item);
579 if (status != noErr)
580 ERR("SecKeychainAddInternetPassword returned %ld\n", status);
581 if (status == errSecDuplicateItem)
583 status = SecKeychainFindInternetPassword(NULL, strlen(servername), servername,
584 domain ? strlen(domain) : 0, domain,
585 strlen(username), username,
586 0, NULL /* any path */, 0,
587 0 /* any protocol */,
588 0 /* any authentication type */,
589 0, NULL, &keychain_item);
590 if (status != noErr)
591 ERR("SecKeychainFindInternetPassword returned %ld\n", status);
593 HeapFree(GetProcessHeap(), 0, domain);
594 HeapFree(GetProcessHeap(), 0, username);
595 HeapFree(GetProcessHeap(), 0, servername);
596 if (status != noErr)
598 HeapFree(GetProcessHeap(), 0, password);
599 return ERROR_GEN_FAILURE;
601 if (credential->Comment)
603 attr_list.count = 1;
604 attr_list.attr = attrs;
605 attrs[0].tag = kSecCommentItemAttr;
606 attrs[0].length = WideCharToMultiByte(CP_UTF8, 0, credential->Comment, -1, NULL, 0, NULL, NULL);
607 if (attrs[0].length) attrs[0].length--;
608 attrs[0].data = HeapAlloc(GetProcessHeap(), 0, attrs[0].length);
609 WideCharToMultiByte(CP_UTF8, 0, credential->Comment, -1, attrs[0].data, attrs[0].length, NULL, NULL);
611 else
613 attr_list.count = 0;
614 attr_list.attr = NULL;
616 status = SecKeychainItemModifyAttributesAndData(keychain_item, &attr_list,
617 preserve_blob ? 0 : strlen(password),
618 preserve_blob ? NULL : password);
619 if (credential->Comment)
620 HeapFree(GetProcessHeap(), 0, attrs[0].data);
621 HeapFree(GetProcessHeap(), 0, password);
622 /* FIXME: set TargetAlias attribute */
623 CFRelease(keychain_item);
624 if (status != noErr)
625 return ERROR_GEN_FAILURE;
626 return ERROR_SUCCESS;
628 #endif
630 static DWORD open_cred_mgr_key(HKEY *hkey, BOOL open_for_write)
632 return RegCreateKeyExW(HKEY_CURRENT_USER, wszCredentialManagerKey, 0,
633 NULL, REG_OPTION_NON_VOLATILE,
634 KEY_READ | (open_for_write ? KEY_WRITE : 0), NULL, hkey, NULL);
637 static DWORD get_cred_mgr_encryption_key(HKEY hkeyMgr, BYTE key_data[KEY_SIZE])
639 static const BYTE my_key_data[KEY_SIZE] = { 0 };
640 DWORD type;
641 DWORD count;
642 FILETIME ft;
643 ULONG seed;
644 ULONG value;
645 DWORD ret;
647 memcpy(key_data, my_key_data, KEY_SIZE);
649 count = KEY_SIZE;
650 ret = RegQueryValueExW(hkeyMgr, wszEncryptionKeyValue, NULL, &type, key_data,
651 &count);
652 if (ret == ERROR_SUCCESS)
654 if (type != REG_BINARY)
655 return ERROR_REGISTRY_CORRUPT;
656 else
657 return ERROR_SUCCESS;
659 if (ret != ERROR_FILE_NOT_FOUND)
660 return ret;
662 GetSystemTimeAsFileTime(&ft);
663 seed = ft.dwLowDateTime;
664 value = RtlUniform(&seed);
665 *(DWORD *)key_data = value;
666 seed = ft.dwHighDateTime;
667 value = RtlUniform(&seed);
668 *(DWORD *)(key_data + 4) = value;
670 ret = RegSetValueExW(hkeyMgr, wszEncryptionKeyValue, 0, REG_BINARY,
671 key_data, KEY_SIZE);
672 if (ret == ERROR_ACCESS_DENIED)
674 ret = open_cred_mgr_key(&hkeyMgr, TRUE);
675 if (ret == ERROR_SUCCESS)
677 ret = RegSetValueExW(hkeyMgr, wszEncryptionKeyValue, 0, REG_BINARY,
678 key_data, KEY_SIZE);
679 RegCloseKey(hkeyMgr);
682 return ret;
685 static LPWSTR get_key_name_for_target(LPCWSTR target_name, DWORD type)
687 static const WCHAR wszGenericPrefix[] = {'G','e','n','e','r','i','c',':',' ',0};
688 static const WCHAR wszDomPasswdPrefix[] = {'D','o','m','P','a','s','s','w','d',':',' ',0};
689 INT len;
690 LPCWSTR prefix = NULL;
691 LPWSTR key_name, p;
693 len = strlenW(target_name);
694 if (type == CRED_TYPE_GENERIC)
696 prefix = wszGenericPrefix;
697 len += sizeof(wszGenericPrefix)/sizeof(wszGenericPrefix[0]);
699 else
701 prefix = wszDomPasswdPrefix;
702 len += sizeof(wszDomPasswdPrefix)/sizeof(wszDomPasswdPrefix[0]);
705 key_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
706 if (!key_name) return NULL;
708 strcpyW(key_name, prefix);
709 strcatW(key_name, target_name);
711 for (p = key_name; *p; p++)
712 if (*p == '\\') *p = '_';
714 return key_name;
717 static BOOL registry_credential_matches_filter(HKEY hkeyCred, LPCWSTR filter)
719 LPWSTR target_name;
720 DWORD ret;
721 DWORD type;
722 DWORD count;
723 LPCWSTR p;
725 if (!filter) return TRUE;
727 ret = RegQueryValueExW(hkeyCred, NULL, 0, &type, NULL, &count);
728 if (ret != ERROR_SUCCESS)
729 return FALSE;
730 else if (type != REG_SZ)
731 return FALSE;
733 target_name = HeapAlloc(GetProcessHeap(), 0, count);
734 if (!target_name)
735 return FALSE;
736 ret = RegQueryValueExW(hkeyCred, NULL, 0, &type, (LPVOID)target_name, &count);
737 if (ret != ERROR_SUCCESS || type != REG_SZ)
739 HeapFree(GetProcessHeap(), 0, target_name);
740 return FALSE;
743 TRACE("comparing filter %s to target name %s\n", debugstr_w(filter),
744 debugstr_w(target_name));
746 p = strchrW(filter, '*');
747 ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, filter,
748 (p && !p[1] ? p - filter : -1), target_name,
749 (p && !p[1] ? p - filter : -1)) == CSTR_EQUAL;
751 HeapFree(GetProcessHeap(), 0, target_name);
752 return ret;
755 static DWORD registry_enumerate_credentials(HKEY hkeyMgr, LPCWSTR filter,
756 LPWSTR target_name,
757 DWORD target_name_len, const BYTE key_data[KEY_SIZE],
758 PCREDENTIALW *credentials, char **buffer,
759 DWORD *len, DWORD *count)
761 DWORD i;
762 DWORD ret;
763 for (i = 0;; i++)
765 HKEY hkeyCred;
766 ret = RegEnumKeyW(hkeyMgr, i, target_name, target_name_len+1);
767 if (ret == ERROR_NO_MORE_ITEMS)
769 ret = ERROR_SUCCESS;
770 break;
772 else if (ret != ERROR_SUCCESS)
773 continue;
774 TRACE("target_name = %s\n", debugstr_w(target_name));
775 ret = RegOpenKeyExW(hkeyMgr, target_name, 0, KEY_QUERY_VALUE, &hkeyCred);
776 if (ret != ERROR_SUCCESS)
777 continue;
778 if (!registry_credential_matches_filter(hkeyCred, filter))
780 RegCloseKey(hkeyCred);
781 continue;
783 if (buffer)
785 *len = sizeof(CREDENTIALW);
786 credentials[*count] = (PCREDENTIALW)*buffer;
788 else
789 *len += sizeof(CREDENTIALW);
790 ret = registry_read_credential(hkeyCred, buffer ? credentials[*count] : NULL,
791 key_data, buffer ? *buffer + sizeof(CREDENTIALW) : NULL,
792 len);
793 RegCloseKey(hkeyCred);
794 if (ret != ERROR_SUCCESS) break;
795 if (buffer) *buffer += *len;
796 (*count)++;
798 return ret;
801 #ifdef __APPLE__
802 static BOOL mac_credential_matches_filter(void *data, UInt32 data_len, const WCHAR *filter)
804 int len;
805 WCHAR *target_name;
806 const WCHAR *p;
807 BOOL ret;
809 if (!filter) return TRUE;
811 len = MultiByteToWideChar(CP_UTF8, 0, data, data_len, NULL, 0);
812 if (!(target_name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)))) return FALSE;
813 MultiByteToWideChar(CP_UTF8, 0, data, data_len, target_name, len);
814 target_name[len] = 0;
816 TRACE("comparing filter %s to target name %s\n", debugstr_w(filter), debugstr_w(target_name));
818 p = strchrW(filter, '*');
819 ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, filter,
820 (p && !p[1] ? p - filter : -1), target_name,
821 (p && !p[1] ? p - filter : -1)) == CSTR_EQUAL;
822 HeapFree(GetProcessHeap(), 0, target_name);
823 return ret;
826 static DWORD mac_enumerate_credentials(LPCWSTR filter, PCREDENTIALW *credentials,
827 char *buffer, DWORD *len, DWORD *count)
829 SecKeychainSearchRef search;
830 SecKeychainItemRef item;
831 OSStatus status;
832 Boolean saved_user_interaction_allowed;
833 DWORD ret;
835 SecKeychainGetUserInteractionAllowed(&saved_user_interaction_allowed);
836 SecKeychainSetUserInteractionAllowed(false);
838 status = SecKeychainSearchCreateFromAttributes(NULL, kSecInternetPasswordItemClass, NULL, &search);
839 if (status == noErr)
841 while (SecKeychainSearchCopyNext(search, &item) == noErr)
843 SecKeychainAttributeInfo info;
844 SecKeychainAttributeList *attr_list;
845 UInt32 info_tags[] = { kSecServerItemAttr };
846 BOOL match;
848 info.count = sizeof(info_tags)/sizeof(info_tags[0]);
849 info.tag = info_tags;
850 info.format = NULL;
851 status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, NULL, NULL);
852 if (status != noErr)
854 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status);
855 continue;
857 if (buffer)
859 *len = sizeof(CREDENTIALW);
860 credentials[*count] = (PCREDENTIALW)buffer;
862 else
863 *len += sizeof(CREDENTIALW);
864 if (attr_list->count != 1 || attr_list->attr[0].tag != kSecServerItemAttr)
866 SecKeychainItemFreeAttributesAndData(attr_list, NULL);
867 continue;
869 TRACE("server item: %.*s\n", (int)attr_list->attr[0].length, (char *)attr_list->attr[0].data);
870 match = mac_credential_matches_filter(attr_list->attr[0].data, attr_list->attr[0].length, filter);
871 SecKeychainItemFreeAttributesAndData(attr_list, NULL);
872 if (!match) continue;
873 ret = mac_read_credential_from_item(item, FALSE,
874 buffer ? credentials[*count] : NULL,
875 buffer ? buffer + sizeof(CREDENTIALW) : NULL,
876 len);
877 CFRelease(item);
878 if (ret == ERROR_SUCCESS)
880 (*count)++;
881 if (buffer) buffer += *len;
884 CFRelease(search);
886 else
887 ERR("SecKeychainSearchCreateFromAttributes returned status %ld\n", status);
888 SecKeychainSetUserInteractionAllowed(saved_user_interaction_allowed);
889 return ERROR_SUCCESS;
892 static DWORD mac_delete_credential(LPCWSTR TargetName)
894 OSStatus status;
895 SecKeychainSearchRef search;
896 status = SecKeychainSearchCreateFromAttributes(NULL, kSecInternetPasswordItemClass, NULL, &search);
897 if (status == noErr)
899 SecKeychainItemRef item;
900 while (SecKeychainSearchCopyNext(search, &item) == noErr)
902 SecKeychainAttributeInfo info;
903 SecKeychainAttributeList *attr_list;
904 UInt32 info_tags[] = { kSecServerItemAttr };
905 LPWSTR target_name;
906 INT str_len;
907 info.count = sizeof(info_tags)/sizeof(info_tags[0]);
908 info.tag = info_tags;
909 info.format = NULL;
910 status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, NULL, NULL);
911 if (status != noErr)
913 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status);
914 continue;
916 if (attr_list->count != 1 || attr_list->attr[0].tag != kSecServerItemAttr)
918 CFRelease(item);
919 continue;
921 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, NULL, 0);
922 target_name = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
923 MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, target_name, str_len);
924 /* nul terminate */
925 target_name[str_len] = '\0';
926 if (strcmpiW(TargetName, target_name))
928 CFRelease(item);
929 HeapFree(GetProcessHeap(), 0, target_name);
930 continue;
932 HeapFree(GetProcessHeap(), 0, target_name);
933 SecKeychainItemFreeAttributesAndData(attr_list, NULL);
934 SecKeychainItemDelete(item);
935 CFRelease(item);
936 CFRelease(search);
938 return ERROR_SUCCESS;
940 CFRelease(search);
942 return ERROR_NOT_FOUND;
944 #endif
946 /******************************************************************************
947 * convert_PCREDENTIALW_to_PCREDENTIALA [internal]
949 * convert a Credential struct from UNICODE to ANSI and return the needed size in Bytes
953 static INT convert_PCREDENTIALW_to_PCREDENTIALA(const CREDENTIALW *CredentialW, PCREDENTIALA CredentialA, DWORD len)
955 char *buffer;
956 INT string_len;
957 INT needed = sizeof(CREDENTIALA);
959 if (!CredentialA)
961 if (CredentialW->TargetName)
962 needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetName, -1, NULL, 0, NULL, NULL);
963 if (CredentialW->Comment)
964 needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->Comment, -1, NULL, 0, NULL, NULL);
965 needed += CredentialW->CredentialBlobSize;
966 if (CredentialW->TargetAlias)
967 needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetAlias, -1, NULL, 0, NULL, NULL);
968 if (CredentialW->UserName)
969 needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->UserName, -1, NULL, 0, NULL, NULL);
971 return needed;
975 buffer = (char *)CredentialA + sizeof(CREDENTIALA);
976 len -= sizeof(CREDENTIALA);
977 CredentialA->Flags = CredentialW->Flags;
978 CredentialA->Type = CredentialW->Type;
980 if (CredentialW->TargetName)
982 CredentialA->TargetName = buffer;
983 string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetName, -1, buffer, len, NULL, NULL);
984 buffer += string_len;
985 needed += string_len;
986 len -= string_len;
988 else
989 CredentialA->TargetName = NULL;
990 if (CredentialW->Comment)
992 CredentialA->Comment = buffer;
993 string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->Comment, -1, buffer, len, NULL, NULL);
994 buffer += string_len;
995 needed += string_len;
996 len -= string_len;
998 else
999 CredentialA->Comment = NULL;
1000 CredentialA->LastWritten = CredentialW->LastWritten;
1001 CredentialA->CredentialBlobSize = CredentialW->CredentialBlobSize;
1002 if (CredentialW->CredentialBlobSize && (CredentialW->CredentialBlobSize <= len))
1004 CredentialA->CredentialBlob =(LPBYTE)buffer;
1005 memcpy(CredentialA->CredentialBlob, CredentialW->CredentialBlob,
1006 CredentialW->CredentialBlobSize);
1007 buffer += CredentialW->CredentialBlobSize;
1008 needed += CredentialW->CredentialBlobSize;
1009 len -= CredentialW->CredentialBlobSize;
1011 else
1012 CredentialA->CredentialBlob = NULL;
1013 CredentialA->Persist = CredentialW->Persist;
1014 CredentialA->AttributeCount = 0;
1015 CredentialA->Attributes = NULL; /* FIXME */
1016 if (CredentialW->TargetAlias)
1018 CredentialA->TargetAlias = buffer;
1019 string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetAlias, -1, buffer, len, NULL, NULL);
1020 buffer += string_len;
1021 needed += string_len;
1022 len -= string_len;
1024 else
1025 CredentialA->TargetAlias = NULL;
1026 if (CredentialW->UserName)
1028 CredentialA->UserName = buffer;
1029 string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->UserName, -1, buffer, len, NULL, NULL);
1030 needed += string_len;
1032 else
1033 CredentialA->UserName = NULL;
1035 return needed;
1038 /******************************************************************************
1039 * convert_PCREDENTIALA_to_PCREDENTIALW [internal]
1041 * convert a Credential struct from ANSI to UNICODE and return the needed size in Bytes
1044 static INT convert_PCREDENTIALA_to_PCREDENTIALW(const CREDENTIALA *CredentialA, PCREDENTIALW CredentialW, INT len)
1046 char *buffer;
1047 INT string_len;
1048 INT needed = sizeof(CREDENTIALW);
1050 if (!CredentialW)
1052 if (CredentialA->TargetName)
1053 needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetName, -1, NULL, 0);
1054 if (CredentialA->Comment)
1055 needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->Comment, -1, NULL, 0);
1056 needed += CredentialA->CredentialBlobSize;
1057 if (CredentialA->TargetAlias)
1058 needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetAlias, -1, NULL, 0);
1059 if (CredentialA->UserName)
1060 needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->UserName, -1, NULL, 0);
1062 return needed;
1065 buffer = (char *)CredentialW + sizeof(CREDENTIALW);
1066 len -= sizeof(CREDENTIALW);
1067 CredentialW->Flags = CredentialA->Flags;
1068 CredentialW->Type = CredentialA->Type;
1069 if (CredentialA->TargetName)
1071 CredentialW->TargetName = (LPWSTR)buffer;
1072 string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetName, -1, CredentialW->TargetName, len / sizeof(WCHAR));
1073 buffer += sizeof(WCHAR) * string_len;
1074 needed += sizeof(WCHAR) * string_len;
1075 len -= sizeof(WCHAR) * string_len;
1077 else
1078 CredentialW->TargetName = NULL;
1079 if (CredentialA->Comment)
1081 CredentialW->Comment = (LPWSTR)buffer;
1082 string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->Comment, -1, CredentialW->Comment, len / sizeof(WCHAR));
1083 buffer += sizeof(WCHAR) * string_len;
1084 needed += sizeof(WCHAR) * string_len;
1085 len -= sizeof(WCHAR) * string_len;
1087 else
1088 CredentialW->Comment = NULL;
1089 CredentialW->LastWritten = CredentialA->LastWritten;
1090 CredentialW->CredentialBlobSize = CredentialA->CredentialBlobSize;
1091 if (CredentialA->CredentialBlobSize)
1093 CredentialW->CredentialBlob =(LPBYTE)buffer;
1094 memcpy(CredentialW->CredentialBlob, CredentialA->CredentialBlob,
1095 CredentialA->CredentialBlobSize);
1096 buffer += CredentialA->CredentialBlobSize;
1097 needed += CredentialA->CredentialBlobSize;
1098 len -= CredentialA->CredentialBlobSize;
1100 else
1101 CredentialW->CredentialBlob = NULL;
1102 CredentialW->Persist = CredentialA->Persist;
1103 CredentialW->AttributeCount = 0;
1104 CredentialW->Attributes = NULL; /* FIXME */
1105 if (CredentialA->TargetAlias)
1107 CredentialW->TargetAlias = (LPWSTR)buffer;
1108 string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetAlias, -1, CredentialW->TargetAlias, len / sizeof(WCHAR));
1109 buffer += sizeof(WCHAR) * string_len;
1110 needed += sizeof(WCHAR) * string_len;
1111 len -= sizeof(WCHAR) * string_len;
1113 else
1114 CredentialW->TargetAlias = NULL;
1115 if (CredentialA->UserName)
1117 CredentialW->UserName = (LPWSTR)buffer;
1118 string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->UserName, -1, CredentialW->UserName, len / sizeof(WCHAR));
1119 needed += sizeof(WCHAR) * string_len;
1121 else
1122 CredentialW->UserName = NULL;
1124 return needed;
1127 /******************************************************************************
1128 * CredDeleteA [ADVAPI32.@]
1130 BOOL WINAPI CredDeleteA(LPCSTR TargetName, DWORD Type, DWORD Flags)
1132 LPWSTR TargetNameW;
1133 DWORD len;
1134 BOOL ret;
1136 TRACE("(%s, %d, 0x%x)\n", debugstr_a(TargetName), Type, Flags);
1138 if (!TargetName)
1140 SetLastError(ERROR_INVALID_PARAMETER);
1141 return FALSE;
1144 len = MultiByteToWideChar(CP_ACP, 0, TargetName, -1, NULL, 0);
1145 TargetNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1146 if (!TargetNameW)
1148 SetLastError(ERROR_OUTOFMEMORY);
1149 return FALSE;
1151 MultiByteToWideChar(CP_ACP, 0, TargetName, -1, TargetNameW, len);
1153 ret = CredDeleteW(TargetNameW, Type, Flags);
1155 HeapFree(GetProcessHeap(), 0, TargetNameW);
1157 return ret;
1160 /******************************************************************************
1161 * CredDeleteW [ADVAPI32.@]
1163 BOOL WINAPI CredDeleteW(LPCWSTR TargetName, DWORD Type, DWORD Flags)
1165 HKEY hkeyMgr;
1166 DWORD ret;
1167 LPWSTR key_name;
1169 TRACE("(%s, %d, 0x%x)\n", debugstr_w(TargetName), Type, Flags);
1171 if (!TargetName)
1173 SetLastError(ERROR_INVALID_PARAMETER);
1174 return FALSE;
1177 if (Type != CRED_TYPE_GENERIC && Type != CRED_TYPE_DOMAIN_PASSWORD)
1179 FIXME("unhandled type %d\n", Type);
1180 SetLastError(ERROR_INVALID_PARAMETER);
1181 return FALSE;
1184 if (Flags)
1186 FIXME("unhandled flags 0x%x\n", Flags);
1187 SetLastError(ERROR_INVALID_FLAGS);
1188 return FALSE;
1191 #ifdef __APPLE__
1192 if (Type == CRED_TYPE_DOMAIN_PASSWORD)
1194 ret = mac_delete_credential(TargetName);
1195 if (ret == ERROR_SUCCESS)
1196 return TRUE;
1198 #endif
1200 ret = open_cred_mgr_key(&hkeyMgr, TRUE);
1201 if (ret != ERROR_SUCCESS)
1203 WARN("couldn't open/create manager key, error %d\n", ret);
1204 SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1205 return FALSE;
1208 key_name = get_key_name_for_target(TargetName, Type);
1209 ret = RegDeleteKeyW(hkeyMgr, key_name);
1210 HeapFree(GetProcessHeap(), 0, key_name);
1211 RegCloseKey(hkeyMgr);
1212 if (ret != ERROR_SUCCESS)
1214 SetLastError(ERROR_NOT_FOUND);
1215 return FALSE;
1218 return TRUE;
1221 /******************************************************************************
1222 * CredEnumerateA [ADVAPI32.@]
1224 BOOL WINAPI CredEnumerateA(LPCSTR Filter, DWORD Flags, DWORD *Count,
1225 PCREDENTIALA **Credentials)
1227 LPWSTR FilterW;
1228 PCREDENTIALW *CredentialsW;
1229 DWORD i;
1230 INT len;
1231 INT needed;
1232 char *buffer;
1234 TRACE("(%s, 0x%x, %p, %p)\n", debugstr_a(Filter), Flags, Count, Credentials);
1236 if (Filter)
1238 len = MultiByteToWideChar(CP_ACP, 0, Filter, -1, NULL, 0);
1239 FilterW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1240 if (!FilterW)
1242 SetLastError(ERROR_OUTOFMEMORY);
1243 return FALSE;
1245 MultiByteToWideChar(CP_ACP, 0, Filter, -1, FilterW, len);
1247 else
1248 FilterW = NULL;
1250 if (!CredEnumerateW(FilterW, Flags, Count, &CredentialsW))
1252 HeapFree(GetProcessHeap(), 0, FilterW);
1253 return FALSE;
1255 HeapFree(GetProcessHeap(), 0, FilterW);
1257 len = *Count * sizeof(PCREDENTIALA);
1258 for (i = 0; i < *Count; i++)
1259 len += convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], NULL, 0);
1261 *Credentials = HeapAlloc(GetProcessHeap(), 0, len);
1262 if (!*Credentials)
1264 CredFree(CredentialsW);
1265 SetLastError(ERROR_OUTOFMEMORY);
1266 return FALSE;
1269 buffer = (char *)&(*Credentials)[*Count];
1270 len -= *Count * sizeof(PCREDENTIALA);
1271 for (i = 0; i < *Count; i++)
1273 (*Credentials)[i] = (PCREDENTIALA)buffer;
1274 needed = convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], (*Credentials)[i], len);
1275 buffer += needed;
1276 len -= needed;
1279 CredFree(CredentialsW);
1281 return TRUE;
1284 /******************************************************************************
1285 * CredEnumerateW [ADVAPI32.@]
1287 BOOL WINAPI CredEnumerateW(LPCWSTR Filter, DWORD Flags, DWORD *Count,
1288 PCREDENTIALW **Credentials)
1290 HKEY hkeyMgr;
1291 DWORD ret;
1292 LPWSTR target_name;
1293 DWORD target_name_len;
1294 DWORD len;
1295 char *buffer;
1296 BYTE key_data[KEY_SIZE];
1298 TRACE("(%s, 0x%x, %p, %p)\n", debugstr_w(Filter), Flags, Count, Credentials);
1300 if (Flags)
1302 SetLastError(ERROR_INVALID_FLAGS);
1303 return FALSE;
1306 ret = open_cred_mgr_key(&hkeyMgr, FALSE);
1307 if (ret != ERROR_SUCCESS)
1309 WARN("couldn't open/create manager key, error %d\n", ret);
1310 SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1311 return FALSE;
1314 ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
1315 if (ret != ERROR_SUCCESS)
1317 RegCloseKey(hkeyMgr);
1318 SetLastError(ret);
1319 return FALSE;
1322 ret = RegQueryInfoKeyW(hkeyMgr, NULL, NULL, NULL, NULL, &target_name_len, NULL, NULL, NULL, NULL, NULL, NULL);
1323 if (ret != ERROR_SUCCESS)
1325 RegCloseKey(hkeyMgr);
1326 SetLastError(ret);
1327 return FALSE;
1330 target_name = HeapAlloc(GetProcessHeap(), 0, (target_name_len+1)*sizeof(WCHAR));
1331 if (!target_name)
1333 RegCloseKey(hkeyMgr);
1334 SetLastError(ERROR_OUTOFMEMORY);
1335 return FALSE;
1338 *Count = 0;
1339 len = 0;
1340 ret = registry_enumerate_credentials(hkeyMgr, Filter, target_name, target_name_len,
1341 key_data, NULL, NULL, &len, Count);
1342 #ifdef __APPLE__
1343 if (ret == ERROR_SUCCESS)
1344 ret = mac_enumerate_credentials(Filter, NULL, NULL, &len, Count);
1345 #endif
1346 if (ret == ERROR_SUCCESS && *Count == 0)
1347 ret = ERROR_NOT_FOUND;
1348 if (ret != ERROR_SUCCESS)
1350 HeapFree(GetProcessHeap(), 0, target_name);
1351 RegCloseKey(hkeyMgr);
1352 SetLastError(ret);
1353 return FALSE;
1355 len += *Count * sizeof(PCREDENTIALW);
1357 if (ret == ERROR_SUCCESS)
1359 buffer = HeapAlloc(GetProcessHeap(), 0, len);
1360 *Credentials = (PCREDENTIALW *)buffer;
1361 if (buffer)
1363 buffer += *Count * sizeof(PCREDENTIALW);
1364 *Count = 0;
1365 ret = registry_enumerate_credentials(hkeyMgr, Filter, target_name,
1366 target_name_len, key_data,
1367 *Credentials, &buffer, &len,
1368 Count);
1369 #ifdef __APPLE__
1370 if (ret == ERROR_SUCCESS)
1371 ret = mac_enumerate_credentials(Filter, *Credentials,
1372 buffer, &len, Count);
1373 #endif
1375 else
1376 ret = ERROR_OUTOFMEMORY;
1379 HeapFree(GetProcessHeap(), 0, target_name);
1380 RegCloseKey(hkeyMgr);
1382 if (ret != ERROR_SUCCESS)
1384 SetLastError(ret);
1385 return FALSE;
1387 return TRUE;
1390 /******************************************************************************
1391 * CredFree [ADVAPI32.@]
1393 VOID WINAPI CredFree(PVOID Buffer)
1395 HeapFree(GetProcessHeap(), 0, Buffer);
1398 /******************************************************************************
1399 * CredReadA [ADVAPI32.@]
1401 BOOL WINAPI CredReadA(LPCSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALA *Credential)
1403 LPWSTR TargetNameW;
1404 PCREDENTIALW CredentialW;
1405 INT len;
1407 TRACE("(%s, %d, 0x%x, %p)\n", debugstr_a(TargetName), Type, Flags, Credential);
1409 if (!TargetName)
1411 SetLastError(ERROR_INVALID_PARAMETER);
1412 return FALSE;
1415 len = MultiByteToWideChar(CP_ACP, 0, TargetName, -1, NULL, 0);
1416 TargetNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1417 if (!TargetNameW)
1419 SetLastError(ERROR_OUTOFMEMORY);
1420 return FALSE;
1422 MultiByteToWideChar(CP_ACP, 0, TargetName, -1, TargetNameW, len);
1424 if (!CredReadW(TargetNameW, Type, Flags, &CredentialW))
1426 HeapFree(GetProcessHeap(), 0, TargetNameW);
1427 return FALSE;
1429 HeapFree(GetProcessHeap(), 0, TargetNameW);
1431 len = convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW, NULL, 0);
1432 *Credential = HeapAlloc(GetProcessHeap(), 0, len);
1433 if (!*Credential)
1435 SetLastError(ERROR_OUTOFMEMORY);
1436 return FALSE;
1438 convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW, *Credential, len);
1440 CredFree(CredentialW);
1442 return TRUE;
1445 /******************************************************************************
1446 * CredReadW [ADVAPI32.@]
1448 BOOL WINAPI CredReadW(LPCWSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALW *Credential)
1450 HKEY hkeyMgr;
1451 HKEY hkeyCred;
1452 DWORD ret;
1453 LPWSTR key_name;
1454 DWORD len;
1455 BYTE key_data[KEY_SIZE];
1457 TRACE("(%s, %d, 0x%x, %p)\n", debugstr_w(TargetName), Type, Flags, Credential);
1459 if (!TargetName)
1461 SetLastError(ERROR_INVALID_PARAMETER);
1462 return FALSE;
1465 if (Type != CRED_TYPE_GENERIC && Type != CRED_TYPE_DOMAIN_PASSWORD)
1467 FIXME("unhandled type %d\n", Type);
1468 SetLastError(ERROR_INVALID_PARAMETER);
1469 return FALSE;
1472 if (Flags)
1474 FIXME("unhandled flags 0x%x\n", Flags);
1475 SetLastError(ERROR_INVALID_FLAGS);
1476 return FALSE;
1479 #ifdef __APPLE__
1480 if (Type == CRED_TYPE_DOMAIN_PASSWORD)
1482 OSStatus status;
1483 SecKeychainSearchRef search;
1484 status = SecKeychainSearchCreateFromAttributes(NULL, kSecInternetPasswordItemClass, NULL, &search);
1485 if (status == noErr)
1487 SecKeychainItemRef item;
1488 while (SecKeychainSearchCopyNext(search, &item) == noErr)
1490 SecKeychainAttributeInfo info;
1491 SecKeychainAttributeList *attr_list;
1492 UInt32 info_tags[] = { kSecServerItemAttr };
1493 LPWSTR target_name;
1494 INT str_len;
1495 info.count = sizeof(info_tags)/sizeof(info_tags[0]);
1496 info.tag = info_tags;
1497 info.format = NULL;
1498 status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, NULL, NULL);
1499 len = sizeof(**Credential);
1500 if (status != noErr)
1502 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status);
1503 continue;
1505 if (attr_list->count != 1 || attr_list->attr[0].tag != kSecServerItemAttr)
1507 CFRelease(item);
1508 continue;
1510 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, NULL, 0);
1511 target_name = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
1512 MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, target_name, str_len);
1513 /* nul terminate */
1514 target_name[str_len] = '\0';
1515 if (strcmpiW(TargetName, target_name))
1517 CFRelease(item);
1518 HeapFree(GetProcessHeap(), 0, target_name);
1519 continue;
1521 HeapFree(GetProcessHeap(), 0, target_name);
1522 SecKeychainItemFreeAttributesAndData(attr_list, NULL);
1523 ret = mac_read_credential_from_item(item, TRUE, NULL, NULL, &len);
1524 if (ret == ERROR_SUCCESS)
1526 *Credential = HeapAlloc(GetProcessHeap(), 0, len);
1527 if (*Credential)
1529 len = sizeof(**Credential);
1530 ret = mac_read_credential_from_item(item, TRUE, *Credential,
1531 (char *)(*Credential + 1), &len);
1533 else
1534 ret = ERROR_OUTOFMEMORY;
1535 CFRelease(item);
1536 CFRelease(search);
1537 if (ret != ERROR_SUCCESS)
1539 SetLastError(ret);
1540 return FALSE;
1542 return TRUE;
1544 CFRelease(item);
1546 CFRelease(search);
1549 #endif
1551 ret = open_cred_mgr_key(&hkeyMgr, FALSE);
1552 if (ret != ERROR_SUCCESS)
1554 WARN("couldn't open/create manager key, error %d\n", ret);
1555 SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1556 return FALSE;
1559 ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
1560 if (ret != ERROR_SUCCESS)
1562 RegCloseKey(hkeyMgr);
1563 SetLastError(ret);
1564 return FALSE;
1567 key_name = get_key_name_for_target(TargetName, Type);
1568 ret = RegOpenKeyExW(hkeyMgr, key_name, 0, KEY_QUERY_VALUE, &hkeyCred);
1569 HeapFree(GetProcessHeap(), 0, key_name);
1570 if (ret != ERROR_SUCCESS)
1572 TRACE("credentials for target name %s not found\n", debugstr_w(TargetName));
1573 SetLastError(ERROR_NOT_FOUND);
1574 return FALSE;
1577 len = sizeof(**Credential);
1578 ret = registry_read_credential(hkeyCred, NULL, key_data, NULL, &len);
1579 if (ret == ERROR_SUCCESS)
1581 *Credential = HeapAlloc(GetProcessHeap(), 0, len);
1582 if (*Credential)
1584 len = sizeof(**Credential);
1585 ret = registry_read_credential(hkeyCred, *Credential, key_data,
1586 (char *)(*Credential + 1), &len);
1588 else
1589 ret = ERROR_OUTOFMEMORY;
1592 RegCloseKey(hkeyCred);
1593 RegCloseKey(hkeyMgr);
1595 if (ret != ERROR_SUCCESS)
1597 SetLastError(ret);
1598 return FALSE;
1600 return TRUE;
1603 /******************************************************************************
1604 * CredReadDomainCredentialsA [ADVAPI32.@]
1606 BOOL WINAPI CredReadDomainCredentialsA(PCREDENTIAL_TARGET_INFORMATIONA TargetInformation,
1607 DWORD Flags, DWORD *Size, PCREDENTIALA **Credentials)
1609 PCREDENTIAL_TARGET_INFORMATIONW TargetInformationW;
1610 INT len;
1611 DWORD i;
1612 WCHAR *buffer, *end;
1613 BOOL ret;
1614 PCREDENTIALW* CredentialsW;
1616 TRACE("(%p, 0x%x, %p, %p)\n", TargetInformation, Flags, Size, Credentials);
1618 /* follow Windows behavior - do not test for NULL, initialize early */
1619 *Size = 0;
1620 *Credentials = NULL;
1622 if (!TargetInformation)
1624 SetLastError(ERROR_INVALID_PARAMETER);
1625 return FALSE;
1628 len = sizeof(*TargetInformationW);
1629 if (TargetInformation->TargetName)
1630 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->TargetName, -1, NULL, 0) * sizeof(WCHAR);
1631 if (TargetInformation->NetbiosServerName)
1632 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosServerName, -1, NULL, 0) * sizeof(WCHAR);
1633 if (TargetInformation->DnsServerName)
1634 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsServerName, -1, NULL, 0) * sizeof(WCHAR);
1635 if (TargetInformation->NetbiosDomainName)
1636 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosDomainName, -1, NULL, 0) * sizeof(WCHAR);
1637 if (TargetInformation->DnsDomainName)
1638 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsDomainName, -1, NULL, 0) * sizeof(WCHAR);
1639 if (TargetInformation->DnsTreeName)
1640 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsTreeName, -1, NULL, 0) * sizeof(WCHAR);
1641 if (TargetInformation->PackageName)
1642 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->PackageName, -1, NULL, 0) * sizeof(WCHAR);
1644 TargetInformationW = HeapAlloc(GetProcessHeap(), 0, len);
1645 if (!TargetInformationW)
1647 SetLastError(ERROR_OUTOFMEMORY);
1648 return FALSE;
1650 buffer = (WCHAR*)(TargetInformationW + 1);
1651 end = (WCHAR *)((char *)TargetInformationW + len);
1653 if (TargetInformation->TargetName)
1655 TargetInformationW->TargetName = buffer;
1656 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->TargetName, -1,
1657 TargetInformationW->TargetName, end - buffer);
1658 } else
1659 TargetInformationW->TargetName = NULL;
1661 if (TargetInformation->NetbiosServerName)
1663 TargetInformationW->NetbiosServerName = buffer;
1664 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosServerName, -1,
1665 TargetInformationW->NetbiosServerName, end - buffer);
1666 } else
1667 TargetInformationW->NetbiosServerName = NULL;
1669 if (TargetInformation->DnsServerName)
1671 TargetInformationW->DnsServerName = buffer;
1672 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsServerName, -1,
1673 TargetInformationW->DnsServerName, end - buffer);
1674 } else
1675 TargetInformationW->DnsServerName = NULL;
1677 if (TargetInformation->NetbiosDomainName)
1679 TargetInformationW->NetbiosDomainName = buffer;
1680 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosDomainName, -1,
1681 TargetInformationW->NetbiosDomainName, end - buffer);
1682 } else
1683 TargetInformationW->NetbiosDomainName = NULL;
1685 if (TargetInformation->DnsDomainName)
1687 TargetInformationW->DnsDomainName = buffer;
1688 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsDomainName, -1,
1689 TargetInformationW->DnsDomainName, end - buffer);
1690 } else
1691 TargetInformationW->DnsDomainName = NULL;
1693 if (TargetInformation->DnsTreeName)
1695 TargetInformationW->DnsTreeName = buffer;
1696 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsTreeName, -1,
1697 TargetInformationW->DnsTreeName, end - buffer);
1698 } else
1699 TargetInformationW->DnsTreeName = NULL;
1701 if (TargetInformation->PackageName)
1703 TargetInformationW->PackageName = buffer;
1704 MultiByteToWideChar(CP_ACP, 0, TargetInformation->PackageName, -1,
1705 TargetInformationW->PackageName, end - buffer);
1706 } else
1707 TargetInformationW->PackageName = NULL;
1709 TargetInformationW->Flags = TargetInformation->Flags;
1710 TargetInformationW->CredTypeCount = TargetInformation->CredTypeCount;
1711 TargetInformationW->CredTypes = TargetInformation->CredTypes;
1713 ret = CredReadDomainCredentialsW(TargetInformationW, Flags, Size, &CredentialsW);
1715 HeapFree(GetProcessHeap(), 0, TargetInformationW);
1717 if (ret)
1719 char *buf;
1720 INT needed;
1722 len = *Size * sizeof(PCREDENTIALA);
1723 for (i = 0; i < *Size; i++)
1724 len += convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], NULL, 0);
1726 *Credentials = HeapAlloc(GetProcessHeap(), 0, len);
1727 if (!*Credentials)
1729 CredFree(CredentialsW);
1730 SetLastError(ERROR_OUTOFMEMORY);
1731 return FALSE;
1734 buf = (char *)&(*Credentials)[*Size];
1735 len -= *Size * sizeof(PCREDENTIALA);
1736 for (i = 0; i < *Size; i++)
1738 (*Credentials)[i] = (PCREDENTIALA)buf;
1739 needed = convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], (*Credentials)[i], len);
1740 buf += needed;
1741 len -= needed;
1744 CredFree(CredentialsW);
1746 return ret;
1749 /******************************************************************************
1750 * CredReadDomainCredentialsW [ADVAPI32.@]
1752 BOOL WINAPI CredReadDomainCredentialsW(PCREDENTIAL_TARGET_INFORMATIONW TargetInformation, DWORD Flags,
1753 DWORD *Size, PCREDENTIALW **Credentials)
1755 FIXME("(%p, 0x%x, %p, %p) stub\n", TargetInformation, Flags, Size, Credentials);
1757 /* follow Windows behavior - do not test for NULL, initialize early */
1758 *Size = 0;
1759 *Credentials = NULL;
1760 if (!TargetInformation)
1762 SetLastError(ERROR_INVALID_PARAMETER);
1763 return FALSE;
1766 SetLastError(ERROR_NOT_FOUND);
1767 return FALSE;
1770 /******************************************************************************
1771 * CredWriteA [ADVAPI32.@]
1773 BOOL WINAPI CredWriteA(PCREDENTIALA Credential, DWORD Flags)
1775 BOOL ret;
1776 INT len;
1777 PCREDENTIALW CredentialW;
1779 TRACE("(%p, 0x%x)\n", Credential, Flags);
1781 if (!Credential || !Credential->TargetName)
1783 SetLastError(ERROR_INVALID_PARAMETER);
1784 return FALSE;
1787 len = convert_PCREDENTIALA_to_PCREDENTIALW(Credential, NULL, 0);
1788 CredentialW = HeapAlloc(GetProcessHeap(), 0, len);
1789 if (!CredentialW)
1791 SetLastError(ERROR_OUTOFMEMORY);
1792 return FALSE;
1795 convert_PCREDENTIALA_to_PCREDENTIALW(Credential, CredentialW, len);
1797 ret = CredWriteW(CredentialW, Flags);
1799 HeapFree(GetProcessHeap(), 0, CredentialW);
1801 return ret;
1804 /******************************************************************************
1805 * CredWriteW [ADVAPI32.@]
1807 BOOL WINAPI CredWriteW(PCREDENTIALW Credential, DWORD Flags)
1809 HKEY hkeyMgr;
1810 HKEY hkeyCred;
1811 DWORD ret;
1812 LPWSTR key_name;
1813 BYTE key_data[KEY_SIZE];
1815 TRACE("(%p, 0x%x)\n", Credential, Flags);
1817 if (!Credential || !Credential->TargetName)
1819 SetLastError(ERROR_INVALID_PARAMETER);
1820 return FALSE;
1823 if (Flags & ~CRED_PRESERVE_CREDENTIAL_BLOB)
1825 FIXME("unhandled flags 0x%x\n", Flags);
1826 SetLastError(ERROR_INVALID_FLAGS);
1827 return FALSE;
1830 if (Credential->Type != CRED_TYPE_GENERIC && Credential->Type != CRED_TYPE_DOMAIN_PASSWORD)
1832 FIXME("unhandled type %d\n", Credential->Type);
1833 SetLastError(ERROR_INVALID_PARAMETER);
1834 return FALSE;
1837 TRACE("Credential->Flags = 0x%08x\n", Credential->Flags);
1838 TRACE("Credential->Type = %u\n", Credential->Type);
1839 TRACE("Credential->TargetName = %s\n", debugstr_w(Credential->TargetName));
1840 TRACE("Credential->Comment = %s\n", debugstr_w(Credential->Comment));
1841 TRACE("Credential->Persist = %u\n", Credential->Persist);
1842 TRACE("Credential->TargetAlias = %s\n", debugstr_w(Credential->TargetAlias));
1843 TRACE("Credential->UserName = %s\n", debugstr_w(Credential->UserName));
1845 if (Credential->Type == CRED_TYPE_DOMAIN_PASSWORD)
1847 if (!Credential->UserName ||
1848 (Credential->Persist == CRED_PERSIST_ENTERPRISE &&
1849 (!strchrW(Credential->UserName, '\\') && !strchrW(Credential->UserName, '@'))))
1851 ERR("bad username %s\n", debugstr_w(Credential->UserName));
1852 SetLastError(ERROR_BAD_USERNAME);
1853 return FALSE;
1857 #ifdef __APPLE__
1858 if (!Credential->AttributeCount &&
1859 Credential->Type == CRED_TYPE_DOMAIN_PASSWORD &&
1860 (Credential->Persist == CRED_PERSIST_LOCAL_MACHINE || Credential->Persist == CRED_PERSIST_ENTERPRISE))
1862 ret = mac_write_credential(Credential, Flags & CRED_PRESERVE_CREDENTIAL_BLOB);
1863 if (ret != ERROR_SUCCESS)
1865 SetLastError(ret);
1866 return FALSE;
1868 return TRUE;
1870 #endif
1872 ret = open_cred_mgr_key(&hkeyMgr, FALSE);
1873 if (ret != ERROR_SUCCESS)
1875 WARN("couldn't open/create manager key, error %d\n", ret);
1876 SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1877 return FALSE;
1880 ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
1881 if (ret != ERROR_SUCCESS)
1883 RegCloseKey(hkeyMgr);
1884 SetLastError(ret);
1885 return FALSE;
1888 key_name = get_key_name_for_target(Credential->TargetName, Credential->Type);
1889 ret = RegCreateKeyExW(hkeyMgr, key_name, 0, NULL,
1890 Credential->Persist == CRED_PERSIST_SESSION ? REG_OPTION_VOLATILE : REG_OPTION_NON_VOLATILE,
1891 KEY_READ|KEY_WRITE, NULL, &hkeyCred, NULL);
1892 HeapFree(GetProcessHeap(), 0, key_name);
1893 if (ret != ERROR_SUCCESS)
1895 TRACE("credentials for target name %s not found\n",
1896 debugstr_w(Credential->TargetName));
1897 SetLastError(ERROR_NOT_FOUND);
1898 return FALSE;
1901 ret = registry_write_credential(hkeyCred, Credential, key_data,
1902 Flags & CRED_PRESERVE_CREDENTIAL_BLOB);
1904 RegCloseKey(hkeyCred);
1905 RegCloseKey(hkeyMgr);
1907 if (ret != ERROR_SUCCESS)
1909 SetLastError(ret);
1910 return FALSE;
1912 return TRUE;
1915 /******************************************************************************
1916 * CredGetSessionTypes [ADVAPI32.@]
1918 WINADVAPI BOOL WINAPI CredGetSessionTypes(DWORD persistCount, LPDWORD persists)
1920 TRACE("(%u, %p)\n", persistCount, persists);
1922 memset(persists, CRED_PERSIST_NONE, persistCount*sizeof(*persists));
1923 if (CRED_TYPE_GENERIC < persistCount)
1925 persists[CRED_TYPE_GENERIC] = CRED_PERSIST_ENTERPRISE;
1927 if (CRED_TYPE_DOMAIN_PASSWORD < persistCount)
1929 persists[CRED_TYPE_DOMAIN_PASSWORD] = CRED_PERSIST_ENTERPRISE;
1932 return TRUE;
1935 /******************************************************************************
1936 * CredMarshalCredentialA [ADVAPI32.@]
1938 BOOL WINAPI CredMarshalCredentialA( CRED_MARSHAL_TYPE type, PVOID cred, LPSTR *out )
1940 BOOL ret;
1941 WCHAR *outW;
1943 TRACE("%u, %p, %p\n", type, cred, out);
1945 if ((ret = CredMarshalCredentialW( type, cred, &outW )))
1947 int len = WideCharToMultiByte( CP_ACP, 0, outW, -1, NULL, 0, NULL, NULL );
1948 if (!(*out = HeapAlloc( GetProcessHeap(), 0, len )))
1950 HeapFree( GetProcessHeap(), 0, outW );
1951 return FALSE;
1953 WideCharToMultiByte( CP_ACP, 0, outW, -1, *out, len, NULL, NULL );
1954 HeapFree( GetProcessHeap(), 0, outW );
1956 return ret;
1959 static UINT cred_encode( const char *bin, unsigned int len, WCHAR *cred )
1961 static const char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#-";
1962 UINT n = 0, x;
1964 while (len > 0)
1966 cred[n++] = enc[bin[0] & 0x3f];
1967 x = (bin[0] & 0xc0) >> 6;
1968 if (len == 1)
1970 cred[n++] = enc[x];
1971 break;
1973 cred[n++] = enc[((bin[1] & 0xf) << 2) | x];
1974 x = (bin[1] & 0xf0) >> 4;
1975 if (len == 2)
1977 cred[n++] = enc[x];
1978 break;
1980 cred[n++] = enc[((bin[2] & 0x3) << 4) | x];
1981 cred[n++] = enc[(bin[2] & 0xfc) >> 2];
1982 bin += 3;
1983 len -= 3;
1985 return n;
1988 /******************************************************************************
1989 * CredMarshalCredentialW [ADVAPI32.@]
1991 BOOL WINAPI CredMarshalCredentialW( CRED_MARSHAL_TYPE type, PVOID cred, LPWSTR *out )
1993 CERT_CREDENTIAL_INFO *cert = cred;
1994 USERNAME_TARGET_CREDENTIAL_INFO *target = cred;
1995 DWORD len, size;
1996 WCHAR *p;
1998 TRACE("%u, %p, %p\n", type, cred, out);
2000 if (!cred || (type == CertCredential && cert->cbSize < sizeof(*cert)) ||
2001 (type != CertCredential && type != UsernameTargetCredential && type != BinaryBlobCredential) ||
2002 (type == UsernameTargetCredential && (!target->UserName || !target->UserName[0])))
2004 SetLastError( ERROR_INVALID_PARAMETER );
2005 return FALSE;
2007 switch (type)
2009 case CertCredential:
2011 char hash[CERT_HASH_LENGTH + 2];
2013 memcpy( hash, cert->rgbHashOfCert, sizeof(cert->rgbHashOfCert) );
2014 memset( hash + sizeof(cert->rgbHashOfCert), 0, sizeof(hash) - sizeof(cert->rgbHashOfCert) );
2016 size = sizeof(hash) * 4 / 3;
2017 if (!(p = HeapAlloc( GetProcessHeap(), 0, (size + 4) * sizeof(WCHAR) ))) return FALSE;
2018 p[0] = '@';
2019 p[1] = '@';
2020 p[2] = 'A' + type;
2021 len = cred_encode( (const char *)hash, sizeof(hash), p + 3 );
2022 p[len] = 0;
2023 break;
2025 case UsernameTargetCredential:
2027 len = strlenW( target->UserName );
2028 size = (sizeof(DWORD) + len * sizeof(WCHAR) + 2) * 4 / 3;
2029 if (!(p = HeapAlloc( GetProcessHeap(), 0, (size + 4) * sizeof(WCHAR) ))) return FALSE;
2030 p[0] = '@';
2031 p[1] = '@';
2032 p[2] = 'A' + type;
2033 size = len * sizeof(WCHAR);
2034 len = cred_encode( (const char *)&size, sizeof(DWORD), p + 3 );
2035 len += cred_encode( (const char *)target->UserName, size, p + 3 + len );
2036 p[len + 3] = 0;
2037 break;
2039 case BinaryBlobCredential:
2040 FIXME("BinaryBlobCredential not implemented\n");
2041 return FALSE;
2042 default:
2043 return FALSE;
2045 *out = p;
2046 return TRUE;
2049 /******************************************************************************
2050 * CredUnmarshalCredentialA [ADVAPI32.@]
2052 BOOL WINAPI CredUnmarshalCredentialA( LPCSTR cred, PCRED_MARSHAL_TYPE type, PVOID *out )
2054 BOOL ret;
2055 WCHAR *credW = NULL;
2057 TRACE("%s, %p, %p\n", debugstr_a(cred), type, out);
2059 if (cred)
2061 int len = MultiByteToWideChar( CP_ACP, 0, cred, -1, NULL, 0 );
2062 if (!(credW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
2063 MultiByteToWideChar( CP_ACP, 0, cred, -1, credW, len );
2065 ret = CredUnmarshalCredentialW( credW, type, out );
2066 HeapFree( GetProcessHeap(), 0, credW );
2067 return ret;
2070 static inline char char_decode( WCHAR c )
2072 if (c >= 'A' && c <= 'Z') return c - 'A';
2073 if (c >= 'a' && c <= 'z') return c - 'a' + 26;
2074 if (c >= '0' && c <= '9') return c - '0' + 52;
2075 if (c == '#') return 62;
2076 if (c == '-') return 63;
2077 return 64;
2080 static BOOL cred_decode( const WCHAR *cred, unsigned int len, char *buf )
2082 unsigned int i = 0;
2083 char c0, c1, c2, c3;
2084 const WCHAR *p = cred;
2086 while (len >= 4)
2088 if ((c0 = char_decode( p[0] )) > 63) return FALSE;
2089 if ((c1 = char_decode( p[1] )) > 63) return FALSE;
2090 if ((c2 = char_decode( p[2] )) > 63) return FALSE;
2091 if ((c3 = char_decode( p[3] )) > 63) return FALSE;
2093 buf[i + 0] = (c1 << 6) | c0;
2094 buf[i + 1] = (c2 << 4) | (c1 >> 2);
2095 buf[i + 2] = (c3 << 2) | (c2 >> 4);
2096 len -= 4;
2097 i += 3;
2098 p += 4;
2100 if (len == 3)
2102 if ((c0 = char_decode( p[0] )) > 63) return FALSE;
2103 if ((c1 = char_decode( p[1] )) > 63) return FALSE;
2104 if ((c2 = char_decode( p[2] )) > 63) return FALSE;
2106 buf[i + 0] = (c1 << 6) | c0;
2107 buf[i + 1] = (c2 << 4) | (c1 >> 2);
2108 buf[i + 2] = c2 >> 4;
2110 else if (len == 2)
2112 if ((c0 = char_decode( p[0] )) > 63) return FALSE;
2113 if ((c1 = char_decode( p[1] )) > 63) return FALSE;
2115 buf[i + 0] = (c1 << 6) | c0;
2116 buf[i + 1] = c1 >> 2;
2117 buf[i + 2] = 0;
2119 else if (len == 1)
2121 if ((c0 = char_decode( p[0] )) > 63) return FALSE;
2123 buf[i + 0] = c0;
2124 buf[i + 1] = 0;
2125 buf[i + 2] = 0;
2127 return TRUE;
2130 /******************************************************************************
2131 * CredUnmarshalCredentialW [ADVAPI32.@]
2133 BOOL WINAPI CredUnmarshalCredentialW( LPCWSTR cred, PCRED_MARSHAL_TYPE type, PVOID *out )
2135 unsigned int len, buflen;
2137 TRACE("%s, %p, %p\n", debugstr_w(cred), type, out);
2139 if (!cred || cred[0] != '@' || cred[1] != '@' || !cred[2] || !cred[3])
2141 SetLastError( ERROR_INVALID_PARAMETER );
2142 return FALSE;
2144 len = strlenW( cred + 3 );
2145 switch (cred[2] - 'A')
2147 case CertCredential:
2149 char hash[CERT_HASH_LENGTH + 2];
2150 CERT_CREDENTIAL_INFO *cert;
2152 if (len != 27 || !cred_decode( cred + 3, len, hash ))
2154 SetLastError( ERROR_INVALID_PARAMETER );
2155 return FALSE;
2157 if (!(cert = HeapAlloc( GetProcessHeap(), 0, sizeof(*cert) ))) return FALSE;
2158 memcpy( cert->rgbHashOfCert, hash, sizeof(cert->rgbHashOfCert) );
2159 cert->cbSize = sizeof(*cert);
2160 *type = CertCredential;
2161 *out = cert;
2162 break;
2164 case UsernameTargetCredential:
2166 USERNAME_TARGET_CREDENTIAL_INFO *target;
2167 ULONGLONG size = 0;
2169 if (len < 9 || !cred_decode( cred + 3, 6, (char *)&size ) ||
2170 !size || size % sizeof(WCHAR) || size > INT_MAX)
2172 SetLastError( ERROR_INVALID_PARAMETER );
2173 return FALSE;
2175 buflen = sizeof(*target) + size + sizeof(WCHAR);
2176 if (!(target = HeapAlloc( GetProcessHeap(), 0, buflen ))) return FALSE;
2177 if (!cred_decode( cred + 9, len - 6, (char *)(target + 1) ))
2179 HeapFree( GetProcessHeap(), 0, target );
2180 return FALSE;
2182 target->UserName = (WCHAR *)(target + 1);
2183 target->UserName[size / sizeof(WCHAR)] = 0;
2184 *type = UsernameTargetCredential;
2185 *out = target;
2186 break;
2188 case BinaryBlobCredential:
2189 FIXME("BinaryBlobCredential not implemented\n");
2190 return FALSE;
2191 default:
2192 WARN("unhandled type %u\n", cred[2] - 'A');
2193 return FALSE;
2195 return TRUE;
2198 /******************************************************************************
2199 * CredIsMarshaledCredentialW [ADVAPI32.@]
2201 * Check, if the name parameter is a marshaled credential, hash or binary blob
2203 * PARAMS
2204 * name the name to check
2206 * RETURNS
2207 * TRUE: the name parameter is a marshaled credential, hash or binary blob
2208 * FALSE: the name is a plain username
2210 BOOL WINAPI CredIsMarshaledCredentialW(LPCWSTR name)
2212 TRACE("(%s)\n", debugstr_w(name));
2214 if (name && name[0] == '@' && name[1] == '@' && name[2] > 'A' && name[3])
2216 char hash[CERT_HASH_LENGTH + 2];
2217 int len = strlenW(name + 3 );
2218 DWORD size;
2220 if ((name[2] - 'A') == CertCredential && (len == 27) && cred_decode(name + 3, len, hash))
2221 return TRUE;
2223 if (((name[2] - 'A') == UsernameTargetCredential) &&
2224 (len >= 9) && cred_decode(name + 3, 6, (char *)&size) && size)
2225 return TRUE;
2227 if ((name[2] - 'A') == BinaryBlobCredential)
2228 FIXME("BinaryBlobCredential not checked\n");
2230 if ((name[2] - 'A') > BinaryBlobCredential)
2231 TRACE("unknown type: %d\n", (name[2] - 'A'));
2234 SetLastError(ERROR_INVALID_PARAMETER);
2235 return FALSE;
2238 /******************************************************************************
2239 * CredIsMarshaledCredentialA [ADVAPI32.@]
2241 * See CredIsMarshaledCredentialW
2244 BOOL WINAPI CredIsMarshaledCredentialA(LPCSTR name)
2246 LPWSTR nameW = NULL;
2247 BOOL res;
2248 int len;
2250 TRACE("(%s)\n", debugstr_a(name));
2252 if (name)
2254 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
2255 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2256 MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, len);
2259 res = CredIsMarshaledCredentialW(nameW);
2260 HeapFree(GetProcessHeap(), 0, nameW);
2261 return res;