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
31 # include <Security/SecKeychain.h>
32 # include <Security/SecKeychainItem.h>
33 # include <Security/SecKeychainSearch.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 */
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 wszTargetNameValue
[] = {'T','a','r','g','e','t','N','a','m','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
)
67 *credential_blob_size
= 0;
68 ret
= RegQueryValueExW(hkey
, wszPasswordValue
, 0, &type
, NULL
, credential_blob_size
);
69 if (ret
!= ERROR_SUCCESS
)
71 else if (type
!= REG_BINARY
)
72 return ERROR_REGISTRY_CORRUPT
;
78 ret
= RegQueryValueExW(hkey
, wszPasswordValue
, 0, &type
, (LPVOID
)credential_blob
,
79 credential_blob_size
);
80 if (ret
!= ERROR_SUCCESS
)
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
);
95 static DWORD
registry_read_credential(HKEY hkey
, PCREDENTIALW credential
,
96 const BYTE key_data
[KEY_SIZE
],
97 char *buffer
, DWORD
*len
)
103 ret
= RegQueryValueExW(hkey
, NULL
, 0, &type
, NULL
, &count
);
104 if (ret
!= ERROR_SUCCESS
)
106 else if (type
!= REG_SZ
)
107 return ERROR_REGISTRY_CORRUPT
;
111 credential
->TargetName
= (LPWSTR
)buffer
;
112 ret
= RegQueryValueExW(hkey
, NULL
, 0, &type
, (LPVOID
)credential
->TargetName
,
114 if (ret
!= ERROR_SUCCESS
|| type
!= REG_SZ
) return ret
;
118 ret
= RegQueryValueExW(hkey
, wszCommentValue
, 0, &type
, NULL
, &count
);
119 if (ret
!= ERROR_FILE_NOT_FOUND
&& ret
!= ERROR_SUCCESS
)
121 else if (type
!= REG_SZ
)
122 return ERROR_REGISTRY_CORRUPT
;
126 credential
->Comment
= (LPWSTR
)buffer
;
127 ret
= RegQueryValueExW(hkey
, wszCommentValue
, 0, &type
, (LPVOID
)credential
->Comment
,
129 if (ret
== ERROR_FILE_NOT_FOUND
)
130 credential
->Comment
= NULL
;
131 else if (ret
!= ERROR_SUCCESS
)
133 else if (type
!= REG_SZ
)
134 return ERROR_REGISTRY_CORRUPT
;
139 ret
= RegQueryValueExW(hkey
, wszTargetAliasValue
, 0, &type
, NULL
, &count
);
140 if (ret
!= ERROR_FILE_NOT_FOUND
&& ret
!= ERROR_SUCCESS
)
142 else if (type
!= REG_SZ
)
143 return ERROR_REGISTRY_CORRUPT
;
147 credential
->TargetAlias
= (LPWSTR
)buffer
;
148 ret
= RegQueryValueExW(hkey
, wszTargetAliasValue
, 0, &type
, (LPVOID
)credential
->TargetAlias
,
150 if (ret
== ERROR_FILE_NOT_FOUND
)
151 credential
->TargetAlias
= NULL
;
152 else if (ret
!= ERROR_SUCCESS
)
154 else if (type
!= REG_SZ
)
155 return ERROR_REGISTRY_CORRUPT
;
160 ret
= RegQueryValueExW(hkey
, wszUserNameValue
, 0, &type
, NULL
, &count
);
161 if (ret
!= ERROR_FILE_NOT_FOUND
&& ret
!= ERROR_SUCCESS
)
163 else if (type
!= REG_SZ
)
164 return ERROR_REGISTRY_CORRUPT
;
168 credential
->UserName
= (LPWSTR
)buffer
;
169 ret
= RegQueryValueExW(hkey
, wszUserNameValue
, 0, &type
, (LPVOID
)credential
->UserName
,
171 if (ret
== ERROR_FILE_NOT_FOUND
)
173 credential
->UserName
= NULL
;
176 else if (ret
!= ERROR_SUCCESS
)
178 else if (type
!= REG_SZ
)
179 return ERROR_REGISTRY_CORRUPT
;
184 ret
= read_credential_blob(hkey
, key_data
, NULL
, &count
);
185 if (ret
!= ERROR_FILE_NOT_FOUND
&& ret
!= ERROR_SUCCESS
)
190 credential
->CredentialBlob
= (LPBYTE
)buffer
;
191 ret
= read_credential_blob(hkey
, key_data
, credential
->CredentialBlob
, &count
);
192 if (ret
== ERROR_FILE_NOT_FOUND
)
194 credential
->CredentialBlob
= NULL
;
197 else if (ret
!= ERROR_SUCCESS
)
199 credential
->CredentialBlobSize
= count
;
203 /* FIXME: Attributes */
206 credential
->AttributeCount
= 0;
207 credential
->Attributes
= NULL
;
210 if (!credential
) return ERROR_SUCCESS
;
212 count
= sizeof(credential
->Flags
);
213 ret
= RegQueryValueExW(hkey
, wszFlagsValue
, NULL
, &type
, (LPVOID
)&credential
->Flags
,
215 if (ret
!= ERROR_SUCCESS
)
217 else if (type
!= REG_DWORD
)
218 return ERROR_REGISTRY_CORRUPT
;
219 count
= sizeof(credential
->Type
);
220 ret
= RegQueryValueExW(hkey
, wszTypeValue
, NULL
, &type
, (LPVOID
)&credential
->Type
,
222 if (ret
!= ERROR_SUCCESS
)
224 else if (type
!= REG_DWORD
)
225 return ERROR_REGISTRY_CORRUPT
;
227 count
= sizeof(credential
->LastWritten
);
228 ret
= RegQueryValueExW(hkey
, wszLastWrittenValue
, NULL
, &type
, (LPVOID
)&credential
->LastWritten
,
230 if (ret
!= ERROR_SUCCESS
)
232 else if (type
!= REG_BINARY
)
233 return ERROR_REGISTRY_CORRUPT
;
234 count
= sizeof(credential
->Persist
);
235 ret
= RegQueryValueExW(hkey
, wszPersistValue
, NULL
, &type
, (LPVOID
)&credential
->Persist
,
237 if (ret
== ERROR_SUCCESS
&& type
!= REG_DWORD
)
238 return ERROR_REGISTRY_CORRUPT
;
243 static DWORD
mac_read_credential_from_item(SecKeychainItemRef item
, BOOL require_password
,
244 PCREDENTIALW credential
, char *buffer
,
249 UInt32 cred_blob_len
;
251 LPWSTR domain
= NULL
;
253 BOOL user_name_present
= FALSE
;
254 SecKeychainAttributeInfo info
;
255 SecKeychainAttributeList
*attr_list
;
256 UInt32 info_tags
[] = { kSecServerItemAttr
, kSecSecurityDomainItemAttr
, kSecAccountItemAttr
,
257 kSecCommentItemAttr
, kSecCreationDateItemAttr
};
258 info
.count
= sizeof(info_tags
)/sizeof(info_tags
[0]);
259 info
.tag
= info_tags
;
261 status
= SecKeychainItemCopyAttributesAndData(item
, &info
, NULL
, &attr_list
, &cred_blob_len
, &cred_blob
);
262 if (status
== errSecAuthFailed
&& !require_password
)
266 status
= SecKeychainItemCopyAttributesAndData(item
, &info
, NULL
, &attr_list
, &cred_blob_len
, NULL
);
270 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status
);
271 return ERROR_NOT_FOUND
;
274 for (i
= 0; i
< attr_list
->count
; i
++)
275 if (attr_list
->attr
[i
].tag
== kSecAccountItemAttr
&& attr_list
->attr
[i
].data
)
277 user_name_present
= TRUE
;
280 if (!user_name_present
)
282 WARN("no kSecAccountItemAttr for item\n");
283 return ERROR_NOT_FOUND
;
288 credential
->Flags
= 0;
289 credential
->Type
= CRED_TYPE_DOMAIN_PASSWORD
;
290 credential
->TargetName
= NULL
;
291 credential
->Comment
= NULL
;
292 memset(&credential
->LastWritten
, 0, sizeof(credential
->LastWritten
));
293 credential
->CredentialBlobSize
= 0;
294 credential
->CredentialBlob
= NULL
;
295 credential
->Persist
= CRED_PERSIST_LOCAL_MACHINE
;
296 credential
->AttributeCount
= 0;
297 credential
->Attributes
= NULL
;
298 credential
->TargetAlias
= NULL
;
299 credential
->UserName
= NULL
;
301 for (i
= 0; i
< attr_list
->count
; i
++)
303 switch (attr_list
->attr
[i
].tag
)
305 case kSecServerItemAttr
:
306 TRACE("kSecServerItemAttr: %.*s\n", (int)attr_list
->attr
[i
].length
,
307 (char *)attr_list
->attr
[i
].data
);
308 if (!attr_list
->attr
[i
].data
) continue;
312 credential
->TargetName
= (LPWSTR
)buffer
;
313 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[i
].data
,
314 attr_list
->attr
[i
].length
, (LPWSTR
)buffer
, 0xffff);
315 credential
->TargetName
[str_len
] = '\0';
316 buffer
+= (str_len
+ 1) * sizeof(WCHAR
);
317 *len
+= (str_len
+ 1) * sizeof(WCHAR
);
322 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[i
].data
,
323 attr_list
->attr
[i
].length
, NULL
, 0);
324 *len
+= (str_len
+ 1) * sizeof(WCHAR
);
327 case kSecAccountItemAttr
:
330 TRACE("kSecAccountItemAttr: %.*s\n", (int)attr_list
->attr
[i
].length
,
331 (char *)attr_list
->attr
[i
].data
);
332 if (!attr_list
->attr
[i
].data
) continue;
333 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[i
].data
,
334 attr_list
->attr
[i
].length
, NULL
, 0);
335 user
= HeapAlloc(GetProcessHeap(), 0, (str_len
+ 1) * sizeof(WCHAR
));
336 MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[i
].data
,
337 attr_list
->attr
[i
].length
, user
, str_len
);
338 user
[str_len
] = '\0';
341 case kSecCommentItemAttr
:
342 TRACE("kSecCommentItemAttr: %.*s\n", (int)attr_list
->attr
[i
].length
,
343 (char *)attr_list
->attr
[i
].data
);
344 if (!attr_list
->attr
[i
].data
) continue;
348 credential
->Comment
= (LPWSTR
)buffer
;
349 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[i
].data
,
350 attr_list
->attr
[i
].length
, (LPWSTR
)buffer
, 0xffff);
351 credential
->Comment
[str_len
] = '\0';
352 buffer
+= (str_len
+ 1) * sizeof(WCHAR
);
353 *len
+= (str_len
+ 1) * sizeof(WCHAR
);
358 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[i
].data
,
359 attr_list
->attr
[i
].length
, NULL
, 0);
360 *len
+= (str_len
+ 1) * sizeof(WCHAR
);
363 case kSecSecurityDomainItemAttr
:
366 TRACE("kSecSecurityDomainItemAttr: %.*s\n", (int)attr_list
->attr
[i
].length
,
367 (char *)attr_list
->attr
[i
].data
);
368 if (!attr_list
->attr
[i
].data
) continue;
369 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[i
].data
,
370 attr_list
->attr
[i
].length
, NULL
, 0);
371 domain
= HeapAlloc(GetProcessHeap(), 0, (str_len
+ 1) * sizeof(WCHAR
));
372 MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[i
].data
,
373 attr_list
->attr
[i
].length
, domain
, str_len
);
374 domain
[str_len
] = '\0';
377 case kSecCreationDateItemAttr
:
378 TRACE("kSecCreationDateItemAttr: %.*s\n", (int)attr_list
->attr
[i
].length
,
379 (char *)attr_list
->attr
[i
].data
);
382 LARGE_INTEGER win_time
;
385 memset(&tm
, 0, sizeof(tm
));
386 strptime(attr_list
->attr
[i
].data
, "%Y%m%d%H%M%SZ", &tm
);
388 RtlSecondsSince1970ToTime(time
, &win_time
);
389 credential
->LastWritten
.dwLowDateTime
= win_time
.u
.LowPart
;
390 credential
->LastWritten
.dwHighDateTime
= win_time
.u
.HighPart
;
400 credential
->UserName
= (LPWSTR
)buffer
;
403 str_len
= strlenW(domain
);
404 *len
+= (str_len
+ 1) * sizeof(WCHAR
);
407 memcpy(credential
->UserName
, domain
, str_len
* sizeof(WCHAR
));
408 /* FIXME: figure out when to use an '@' */
409 credential
->UserName
[str_len
] = '\\';
410 buffer
+= (str_len
+ 1) * sizeof(WCHAR
);
413 str_len
= strlenW(user
);
414 *len
+= (str_len
+ 1) * sizeof(WCHAR
);
417 memcpy(buffer
, user
, (str_len
+ 1) * sizeof(WCHAR
));
418 buffer
+= (str_len
+ 1) * sizeof(WCHAR
);
419 TRACE("UserName = %s\n", debugstr_w(credential
->UserName
));
422 HeapFree(GetProcessHeap(), 0, user
);
423 HeapFree(GetProcessHeap(), 0, domain
);
430 credential
->CredentialBlob
= (BYTE
*)buffer
;
431 str_len
= MultiByteToWideChar(CP_UTF8
, 0, cred_blob
, cred_blob_len
,
432 (LPWSTR
)buffer
, 0xffff);
433 credential
->CredentialBlobSize
= str_len
* sizeof(WCHAR
);
434 buffer
+= str_len
* sizeof(WCHAR
);
435 *len
+= str_len
* sizeof(WCHAR
);
440 str_len
= MultiByteToWideChar(CP_UTF8
, 0, cred_blob
, cred_blob_len
,
442 *len
+= str_len
* sizeof(WCHAR
);
445 SecKeychainItemFreeAttributesAndData(attr_list
, cred_blob
);
446 return ERROR_SUCCESS
;
450 static DWORD
write_credential_blob(HKEY hkey
, LPCWSTR target_name
, DWORD type
,
451 const BYTE key_data
[KEY_SIZE
],
452 const BYTE
*credential_blob
, DWORD credential_blob_size
)
454 LPBYTE encrypted_credential_blob
;
459 key
.Length
= key
.MaximumLength
= KEY_SIZE
;
460 key
.Buffer
= (unsigned char *)key_data
;
462 encrypted_credential_blob
= HeapAlloc(GetProcessHeap(), 0, credential_blob_size
);
463 if (!encrypted_credential_blob
) return ERROR_OUTOFMEMORY
;
465 memcpy(encrypted_credential_blob
, credential_blob
, credential_blob_size
);
466 data
.Length
= data
.MaximumLength
= credential_blob_size
;
467 data
.Buffer
= encrypted_credential_blob
;
468 SystemFunction032(&data
, &key
);
470 ret
= RegSetValueExW(hkey
, wszPasswordValue
, 0, REG_BINARY
, (LPVOID
)encrypted_credential_blob
, credential_blob_size
);
471 HeapFree(GetProcessHeap(), 0, encrypted_credential_blob
);
476 static DWORD
registry_write_credential(HKEY hkey
, const CREDENTIALW
*credential
,
477 const BYTE key_data
[KEY_SIZE
], BOOL preserve_blob
)
480 FILETIME LastWritten
;
482 GetSystemTimeAsFileTime(&LastWritten
);
484 ret
= RegSetValueExW(hkey
, wszFlagsValue
, 0, REG_DWORD
, (LPVOID
)&credential
->Flags
,
485 sizeof(credential
->Flags
));
486 if (ret
!= ERROR_SUCCESS
) return ret
;
487 ret
= RegSetValueExW(hkey
, wszTypeValue
, 0, REG_DWORD
, (LPVOID
)&credential
->Type
,
488 sizeof(credential
->Type
));
489 if (ret
!= ERROR_SUCCESS
) return ret
;
490 ret
= RegSetValueExW(hkey
, NULL
, 0, REG_SZ
, (LPVOID
)credential
->TargetName
,
491 sizeof(WCHAR
)*(strlenW(credential
->TargetName
)+1));
492 if (ret
!= ERROR_SUCCESS
) return ret
;
493 if (credential
->Comment
)
495 ret
= RegSetValueExW(hkey
, wszCommentValue
, 0, REG_SZ
, (LPVOID
)credential
->Comment
,
496 sizeof(WCHAR
)*(strlenW(credential
->Comment
)+1));
497 if (ret
!= ERROR_SUCCESS
) return ret
;
499 ret
= RegSetValueExW(hkey
, wszLastWrittenValue
, 0, REG_BINARY
, (LPVOID
)&LastWritten
,
500 sizeof(LastWritten
));
501 if (ret
!= ERROR_SUCCESS
) return ret
;
502 ret
= RegSetValueExW(hkey
, wszPersistValue
, 0, REG_DWORD
, (LPVOID
)&credential
->Persist
,
503 sizeof(credential
->Persist
));
504 if (ret
!= ERROR_SUCCESS
) return ret
;
505 /* FIXME: Attributes */
506 if (credential
->TargetAlias
)
508 ret
= RegSetValueExW(hkey
, wszTargetAliasValue
, 0, REG_SZ
, (LPVOID
)credential
->TargetAlias
,
509 sizeof(WCHAR
)*(strlenW(credential
->TargetAlias
)+1));
510 if (ret
!= ERROR_SUCCESS
) return ret
;
512 if (credential
->UserName
)
514 ret
= RegSetValueExW(hkey
, wszUserNameValue
, 0, REG_SZ
, (LPVOID
)credential
->UserName
,
515 sizeof(WCHAR
)*(strlenW(credential
->UserName
)+1));
516 if (ret
!= ERROR_SUCCESS
) return ret
;
520 ret
= write_credential_blob(hkey
, credential
->TargetName
, credential
->Type
,
521 key_data
, credential
->CredentialBlob
,
522 credential
->CredentialBlobSize
);
528 static DWORD
mac_write_credential(const CREDENTIALW
*credential
, BOOL preserve_blob
)
531 SecKeychainItemRef keychain_item
;
537 UInt32 domainlen
= 0;
541 SecKeychainAttribute attrs
[1];
542 SecKeychainAttributeList attr_list
;
544 if (credential
->Flags
)
545 FIXME("Flags 0x%x not written\n", credential
->Flags
);
546 if (credential
->Type
!= CRED_TYPE_DOMAIN_PASSWORD
)
547 FIXME("credential type of %d not supported\n", credential
->Type
);
548 if (credential
->Persist
!= CRED_PERSIST_LOCAL_MACHINE
)
549 FIXME("persist value of %d not supported\n", credential
->Persist
);
550 if (credential
->AttributeCount
)
551 FIXME("custom attributes not supported\n");
553 p
= strchrW(credential
->UserName
, '\\');
556 domainlen
= WideCharToMultiByte(CP_UTF8
, 0, credential
->UserName
,
557 p
- credential
->UserName
, NULL
, 0, NULL
, NULL
);
558 domain
= HeapAlloc(GetProcessHeap(), 0, (domainlen
+ 1) * sizeof(*domain
));
559 WideCharToMultiByte(CP_UTF8
, 0, credential
->UserName
, p
- credential
->UserName
,
560 domain
, domainlen
, NULL
, NULL
);
561 domain
[domainlen
] = '\0';
565 p
= credential
->UserName
;
566 userlen
= WideCharToMultiByte(CP_UTF8
, 0, p
, -1, NULL
, 0, NULL
, NULL
);
567 username
= HeapAlloc(GetProcessHeap(), 0, userlen
* sizeof(*username
));
568 WideCharToMultiByte(CP_UTF8
, 0, p
, -1, username
, userlen
, NULL
, NULL
);
570 serverlen
= WideCharToMultiByte(CP_UTF8
, 0, credential
->TargetName
, -1, NULL
, 0, NULL
, NULL
);
571 servername
= HeapAlloc(GetProcessHeap(), 0, serverlen
* sizeof(*servername
));
572 WideCharToMultiByte(CP_UTF8
, 0, credential
->TargetName
, -1, servername
, serverlen
, NULL
, NULL
);
573 pwlen
= WideCharToMultiByte(CP_UTF8
, 0, (LPCWSTR
)credential
->CredentialBlob
,
574 credential
->CredentialBlobSize
/ sizeof(WCHAR
), NULL
, 0, NULL
, NULL
);
575 password
= HeapAlloc(GetProcessHeap(), 0, pwlen
* sizeof(*domain
));
576 WideCharToMultiByte(CP_UTF8
, 0, (LPCWSTR
)credential
->CredentialBlob
,
577 credential
->CredentialBlobSize
/ sizeof(WCHAR
), password
, pwlen
, NULL
, NULL
);
579 TRACE("adding server %s, domain %s, username %s using Keychain\n", servername
, domain
, username
);
580 status
= SecKeychainAddInternetPassword(NULL
, strlen(servername
), servername
,
581 strlen(domain
), domain
, strlen(username
),
582 username
, 0, NULL
, 0,
584 kSecAuthenticationTypeDefault
,
585 strlen(password
), password
, &keychain_item
);
587 ERR("SecKeychainAddInternetPassword returned %ld\n", status
);
588 if (status
== errSecDuplicateItem
)
590 SecKeychainItemRef keychain_item
;
592 status
= SecKeychainFindInternetPassword(NULL
, strlen(servername
), servername
,
593 strlen(domain
), domain
,
594 strlen(username
), username
,
595 0, NULL
/* any path */, 0,
596 0 /* any protocol */,
597 0 /* any authentication type */,
598 0, NULL
, &keychain_item
);
600 ERR("SecKeychainFindInternetPassword returned %ld\n", status
);
602 HeapFree(GetProcessHeap(), 0, domain
);
603 HeapFree(GetProcessHeap(), 0, username
);
604 HeapFree(GetProcessHeap(), 0, servername
);
607 HeapFree(GetProcessHeap(), 0, password
);
608 return ERROR_GEN_FAILURE
;
610 if (credential
->Comment
)
613 attr_list
.attr
= attrs
;
614 attrs
[0].tag
= kSecCommentItemAttr
;
615 attrs
[0].length
= WideCharToMultiByte(CP_UTF8
, 0, credential
->Comment
, -1, NULL
, 0, NULL
, NULL
);
616 if (attrs
[0].length
) attrs
[0].length
--;
617 attrs
[0].data
= HeapAlloc(GetProcessHeap(), 0, attrs
[0].length
);
618 WideCharToMultiByte(CP_UTF8
, 0, credential
->Comment
, -1, attrs
[0].data
, attrs
[0].length
, NULL
, NULL
);
623 attr_list
.attr
= NULL
;
625 status
= SecKeychainItemModifyAttributesAndData(keychain_item
, &attr_list
,
626 preserve_blob
? 0 : strlen(password
),
627 preserve_blob
? NULL
: password
);
628 if (credential
->Comment
)
629 HeapFree(GetProcessHeap(), 0, attrs
[0].data
);
630 HeapFree(GetProcessHeap(), 0, password
);
631 /* FIXME: set TargetAlias attribute */
632 CFRelease(keychain_item
);
633 return ERROR_SUCCESS
;
637 static DWORD
open_cred_mgr_key(HKEY
*hkey
, BOOL open_for_write
)
639 return RegCreateKeyExW(HKEY_CURRENT_USER
, wszCredentialManagerKey
, 0,
640 NULL
, REG_OPTION_NON_VOLATILE
,
641 KEY_READ
| (open_for_write
? KEY_WRITE
: 0), NULL
, hkey
, NULL
);
644 static DWORD
get_cred_mgr_encryption_key(HKEY hkeyMgr
, BYTE key_data
[KEY_SIZE
])
646 static const BYTE my_key_data
[KEY_SIZE
] = { 0 };
654 memcpy(key_data
, my_key_data
, KEY_SIZE
);
657 ret
= RegQueryValueExW(hkeyMgr
, wszEncryptionKeyValue
, NULL
, &type
, (LPVOID
)key_data
,
659 if (ret
== ERROR_SUCCESS
)
661 if (type
!= REG_BINARY
)
662 return ERROR_REGISTRY_CORRUPT
;
664 return ERROR_SUCCESS
;
666 if (ret
!= ERROR_FILE_NOT_FOUND
)
669 GetSystemTimeAsFileTime(&ft
);
670 seed
= ft
.dwLowDateTime
;
671 value
= RtlUniform(&seed
);
672 *(DWORD
*)key_data
= value
;
673 seed
= ft
.dwHighDateTime
;
674 value
= RtlUniform(&seed
);
675 *(DWORD
*)(key_data
+ 4) = value
;
677 ret
= RegSetValueExW(hkeyMgr
, wszEncryptionKeyValue
, 0, REG_BINARY
,
678 (LPVOID
)key_data
, KEY_SIZE
);
679 if (ret
== ERROR_ACCESS_DENIED
)
681 ret
= open_cred_mgr_key(&hkeyMgr
, TRUE
);
682 if (ret
== ERROR_SUCCESS
)
684 ret
= RegSetValueExW(hkeyMgr
, wszEncryptionKeyValue
, 0, REG_BINARY
,
685 (LPVOID
)key_data
, KEY_SIZE
);
686 RegCloseKey(hkeyMgr
);
692 static LPWSTR
get_key_name_for_target(LPCWSTR target_name
, DWORD type
)
694 static const WCHAR wszGenericPrefix
[] = {'G','e','n','e','r','i','c',':',' ',0};
695 static const WCHAR wszDomPasswdPrefix
[] = {'D','o','m','P','a','s','s','w','d',':',' ',0};
697 LPCWSTR prefix
= NULL
;
700 len
= strlenW(target_name
);
701 if (type
== CRED_TYPE_GENERIC
)
703 prefix
= wszGenericPrefix
;
704 len
+= sizeof(wszGenericPrefix
)/sizeof(wszGenericPrefix
[0]);
708 prefix
= wszDomPasswdPrefix
;
709 len
+= sizeof(wszDomPasswdPrefix
)/sizeof(wszDomPasswdPrefix
[0]);
712 key_name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
713 if (!key_name
) return NULL
;
715 strcpyW(key_name
, prefix
);
716 strcatW(key_name
, target_name
);
718 for (p
= key_name
; *p
; p
++)
719 if (*p
== '\\') *p
= '_';
724 static BOOL
credential_matches_filter(HKEY hkeyCred
, LPCWSTR filter
)
732 if (!filter
) return TRUE
;
734 ret
= RegQueryValueExW(hkeyCred
, NULL
, 0, &type
, NULL
, &count
);
735 if (ret
!= ERROR_SUCCESS
)
737 else if (type
!= REG_SZ
)
740 target_name
= HeapAlloc(GetProcessHeap(), 0, count
);
743 ret
= RegQueryValueExW(hkeyCred
, NULL
, 0, &type
, (LPVOID
)target_name
, &count
);
744 if (ret
!= ERROR_SUCCESS
|| type
!= REG_SZ
)
746 HeapFree(GetProcessHeap(), 0, target_name
);
750 TRACE("comparing filter %s to target name %s\n", debugstr_w(filter
),
751 debugstr_w(target_name
));
753 p
= strchrW(filter
, '*');
754 ret
= CompareStringW(GetThreadLocale(), 0, filter
,
755 (p
&& !p
[1] ? p
- filter
: -1), target_name
,
756 (p
&& !p
[1] ? p
- filter
: -1)) == CSTR_EQUAL
;
758 HeapFree(GetProcessHeap(), 0, target_name
);
762 static DWORD
registry_enumerate_credentials(HKEY hkeyMgr
, LPCWSTR filter
,
764 DWORD target_name_len
, BYTE key_data
[KEY_SIZE
],
765 PCREDENTIALW
*credentials
, char **buffer
,
766 DWORD
*len
, DWORD
*count
)
773 ret
= RegEnumKeyW(hkeyMgr
, i
, target_name
, target_name_len
+1);
774 if (ret
== ERROR_NO_MORE_ITEMS
)
779 else if (ret
!= ERROR_SUCCESS
)
784 TRACE("target_name = %s\n", debugstr_w(target_name
));
785 ret
= RegOpenKeyExW(hkeyMgr
, target_name
, 0, KEY_QUERY_VALUE
, &hkeyCred
);
786 if (ret
!= ERROR_SUCCESS
)
791 if (!credential_matches_filter(hkeyCred
, filter
))
793 RegCloseKey(hkeyCred
);
798 *len
= sizeof(CREDENTIALW
);
799 credentials
[*count
] = (PCREDENTIALW
)*buffer
;
802 *len
+= sizeof(CREDENTIALW
);
803 ret
= registry_read_credential(hkeyCred
, buffer
? credentials
[*count
] : NULL
,
804 key_data
, buffer
? *buffer
+ sizeof(CREDENTIALW
) : NULL
,
806 RegCloseKey(hkeyCred
);
807 if (ret
!= ERROR_SUCCESS
) break;
808 if (buffer
) *buffer
+= *len
;
815 static DWORD
mac_enumerate_credentials(LPCWSTR filter
, PCREDENTIALW
*credentials
,
816 char *buffer
, DWORD
*len
, DWORD
*count
)
818 SecKeychainSearchRef search
;
819 SecKeychainItemRef item
;
821 Boolean saved_user_interaction_allowed
;
824 SecKeychainGetUserInteractionAllowed(&saved_user_interaction_allowed
);
825 SecKeychainSetUserInteractionAllowed(false);
827 status
= SecKeychainSearchCreateFromAttributes(NULL
, kSecInternetPasswordItemClass
, NULL
, &search
);
830 while (SecKeychainSearchCopyNext(search
, &item
) == noErr
)
832 SecKeychainAttributeInfo info
;
833 SecKeychainAttributeList
*attr_list
;
834 UInt32 info_tags
[] = { kSecServerItemAttr
};
835 info
.count
= sizeof(info_tags
)/sizeof(info_tags
[0]);
836 info
.tag
= info_tags
;
838 status
= SecKeychainItemCopyAttributesAndData(item
, &info
, NULL
, &attr_list
, NULL
, NULL
);
841 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status
);
846 *len
= sizeof(CREDENTIALW
);
847 credentials
[*count
] = (PCREDENTIALW
)buffer
;
850 *len
+= sizeof(CREDENTIALW
);
851 if (attr_list
->count
!= 1 || attr_list
->attr
[0].tag
!= kSecServerItemAttr
) continue;
852 TRACE("server item: %.*s\n", (int)attr_list
->attr
[0].length
, (char *)attr_list
->attr
[0].data
);
853 /* FIXME: filter based on attr_list->attr[0].data */
854 SecKeychainItemFreeAttributesAndData(attr_list
, NULL
);
855 ret
= mac_read_credential_from_item(item
, FALSE
,
856 buffer
? credentials
[*count
] : NULL
,
857 buffer
? buffer
+ sizeof(CREDENTIALW
) : NULL
,
860 if (ret
== ERROR_SUCCESS
)
863 if (buffer
) buffer
+= *len
;
869 ERR("SecKeychainSearchCreateFromAttributes returned status %ld\n", status
);
870 SecKeychainSetUserInteractionAllowed(saved_user_interaction_allowed
);
871 return ERROR_SUCCESS
;
874 static DWORD
mac_delete_credential(LPCWSTR TargetName
)
877 SecKeychainSearchRef search
;
878 status
= SecKeychainSearchCreateFromAttributes(NULL
, kSecInternetPasswordItemClass
, NULL
, &search
);
881 SecKeychainItemRef item
;
882 while (SecKeychainSearchCopyNext(search
, &item
) == noErr
)
884 SecKeychainAttributeInfo info
;
885 SecKeychainAttributeList
*attr_list
;
886 UInt32 info_tags
[] = { kSecServerItemAttr
};
889 info
.count
= sizeof(info_tags
)/sizeof(info_tags
[0]);
890 info
.tag
= info_tags
;
892 status
= SecKeychainItemCopyAttributesAndData(item
, &info
, NULL
, &attr_list
, NULL
, NULL
);
895 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status
);
898 if (attr_list
->count
!= 1 || attr_list
->attr
[0].tag
!= kSecServerItemAttr
)
903 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[0].data
, attr_list
->attr
[0].length
, NULL
, 0);
904 target_name
= HeapAlloc(GetProcessHeap(), 0, (str_len
+ 1) * sizeof(WCHAR
));
905 MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[0].data
, attr_list
->attr
[0].length
, target_name
, str_len
);
907 target_name
[str_len
] = '\0';
908 if (strcmpiW(TargetName
, target_name
))
911 HeapFree(GetProcessHeap(), 0, target_name
);
914 HeapFree(GetProcessHeap(), 0, target_name
);
915 SecKeychainItemFreeAttributesAndData(attr_list
, NULL
);
916 SecKeychainItemDelete(item
);
920 return ERROR_SUCCESS
;
924 return ERROR_NOT_FOUND
;
928 static void convert_PCREDENTIALW_to_PCREDENTIALA(const CREDENTIALW
*CredentialW
, PCREDENTIALA CredentialA
, DWORD
*len
)
930 char *buffer
= (char *)CredentialA
+ sizeof(CREDENTIALA
);
933 *len
+= sizeof(CREDENTIALA
);
936 if (CredentialW
->TargetName
) *len
+= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->TargetName
, -1, NULL
, 0, NULL
, NULL
);
937 if (CredentialW
->Comment
) *len
+= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->Comment
, -1, NULL
, 0, NULL
, NULL
);
938 *len
+= CredentialW
->CredentialBlobSize
;
939 if (CredentialW
->TargetAlias
) *len
+= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->TargetAlias
, -1, NULL
, 0, NULL
, NULL
);
940 if (CredentialW
->UserName
) *len
+= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->UserName
, -1, NULL
, 0, NULL
, NULL
);
945 CredentialA
->Flags
= CredentialW
->Flags
;
946 CredentialA
->Type
= CredentialW
->Type
;
947 if (CredentialW
->TargetName
)
949 CredentialA
->TargetName
= buffer
;
950 string_len
= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->TargetName
, -1, CredentialA
->TargetName
, -1, NULL
, NULL
);
951 buffer
+= string_len
;
955 CredentialA
->TargetName
= NULL
;
956 if (CredentialW
->Comment
)
958 CredentialA
->Comment
= buffer
;
959 string_len
= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->Comment
, -1, CredentialA
->Comment
, -1, NULL
, NULL
);
960 buffer
+= string_len
;
964 CredentialA
->Comment
= NULL
;
965 CredentialA
->LastWritten
= CredentialW
->LastWritten
;
966 CredentialA
->CredentialBlobSize
= CredentialW
->CredentialBlobSize
;
967 if (CredentialW
->CredentialBlobSize
)
969 CredentialA
->CredentialBlob
=(LPBYTE
)buffer
;
970 memcpy(CredentialA
->CredentialBlob
, CredentialW
->CredentialBlob
,
971 CredentialW
->CredentialBlobSize
);
972 buffer
+= CredentialW
->CredentialBlobSize
;
973 *len
+= CredentialW
->CredentialBlobSize
;
976 CredentialA
->CredentialBlob
= NULL
;
977 CredentialA
->Persist
= CredentialW
->Persist
;
978 CredentialA
->AttributeCount
= 0;
979 CredentialA
->Attributes
= NULL
; /* FIXME */
980 if (CredentialW
->TargetAlias
)
982 CredentialA
->TargetAlias
= buffer
;
983 string_len
= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->TargetAlias
, -1, CredentialA
->TargetAlias
, -1, NULL
, NULL
);
984 buffer
+= string_len
;
988 CredentialA
->TargetAlias
= NULL
;
989 if (CredentialW
->UserName
)
991 CredentialA
->UserName
= buffer
;
992 string_len
= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->UserName
, -1, CredentialA
->UserName
, -1, NULL
, NULL
);
993 buffer
+= string_len
;
997 CredentialA
->UserName
= NULL
;
1000 static void convert_PCREDENTIALA_to_PCREDENTIALW(const CREDENTIALA
*CredentialA
, PCREDENTIALW CredentialW
, DWORD
*len
)
1002 char *buffer
= (char *)CredentialW
+ sizeof(CREDENTIALW
);
1005 *len
+= sizeof(CREDENTIALW
);
1008 if (CredentialA
->TargetName
) *len
+= sizeof(WCHAR
) * MultiByteToWideChar(CP_ACP
, 0, CredentialA
->TargetName
, -1, NULL
, 0);
1009 if (CredentialA
->Comment
) *len
+= sizeof(WCHAR
) * MultiByteToWideChar(CP_ACP
, 0, CredentialA
->Comment
, -1, NULL
, 0);
1010 *len
+= CredentialA
->CredentialBlobSize
;
1011 if (CredentialA
->TargetAlias
) *len
+= sizeof(WCHAR
) * MultiByteToWideChar(CP_ACP
, 0, CredentialA
->TargetAlias
, -1, NULL
, 0);
1012 if (CredentialA
->UserName
) *len
+= sizeof(WCHAR
) * MultiByteToWideChar(CP_ACP
, 0, CredentialA
->UserName
, -1, NULL
, 0);
1017 CredentialW
->Flags
= CredentialA
->Flags
;
1018 CredentialW
->Type
= CredentialA
->Type
;
1019 if (CredentialA
->TargetName
)
1021 CredentialW
->TargetName
= (LPWSTR
)buffer
;
1022 string_len
= MultiByteToWideChar(CP_ACP
, 0, CredentialA
->TargetName
, -1, CredentialW
->TargetName
, -1);
1023 buffer
+= sizeof(WCHAR
) * string_len
;
1024 *len
+= sizeof(WCHAR
) * string_len
;
1027 CredentialW
->TargetName
= NULL
;
1028 if (CredentialA
->Comment
)
1030 CredentialW
->Comment
= (LPWSTR
)buffer
;
1031 string_len
= MultiByteToWideChar(CP_ACP
, 0, CredentialA
->Comment
, -1, CredentialW
->Comment
, -1);
1032 buffer
+= sizeof(WCHAR
) * string_len
;
1033 *len
+= sizeof(WCHAR
) * string_len
;
1036 CredentialW
->Comment
= NULL
;
1037 CredentialW
->LastWritten
= CredentialA
->LastWritten
;
1038 CredentialW
->CredentialBlobSize
= CredentialA
->CredentialBlobSize
;
1039 if (CredentialA
->CredentialBlobSize
)
1041 CredentialW
->CredentialBlob
=(LPBYTE
)buffer
;
1042 memcpy(CredentialW
->CredentialBlob
, CredentialA
->CredentialBlob
,
1043 CredentialA
->CredentialBlobSize
);
1044 buffer
+= CredentialA
->CredentialBlobSize
;
1045 *len
+= CredentialA
->CredentialBlobSize
;
1048 CredentialW
->CredentialBlob
= NULL
;
1049 CredentialW
->Persist
= CredentialA
->Persist
;
1050 CredentialW
->AttributeCount
= 0;
1051 CredentialW
->Attributes
= NULL
; /* FIXME */
1052 if (CredentialA
->TargetAlias
)
1054 CredentialW
->TargetAlias
= (LPWSTR
)buffer
;
1055 string_len
= MultiByteToWideChar(CP_ACP
, 0, CredentialA
->TargetAlias
, -1, CredentialW
->TargetAlias
, -1);
1056 buffer
+= sizeof(WCHAR
) * string_len
;
1057 *len
+= sizeof(WCHAR
) * string_len
;
1060 CredentialW
->TargetAlias
= NULL
;
1061 if (CredentialA
->UserName
)
1063 CredentialW
->UserName
= (LPWSTR
)buffer
;
1064 string_len
= MultiByteToWideChar(CP_ACP
, 0, CredentialA
->UserName
, -1, CredentialW
->UserName
, -1);
1065 buffer
+= sizeof(WCHAR
) * string_len
;
1066 *len
+= sizeof(WCHAR
) * string_len
;
1069 CredentialW
->UserName
= NULL
;
1072 /******************************************************************************
1073 * CredDeleteA [ADVAPI32.@]
1075 BOOL WINAPI
CredDeleteA(LPCSTR TargetName
, DWORD Type
, DWORD Flags
)
1081 TRACE("(%s, %d, 0x%x)\n", debugstr_a(TargetName
), Type
, Flags
);
1085 SetLastError(ERROR_INVALID_PARAMETER
);
1089 len
= MultiByteToWideChar(CP_ACP
, 0, TargetName
, -1, NULL
, 0);
1090 TargetNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1093 SetLastError(ERROR_OUTOFMEMORY
);
1096 MultiByteToWideChar(CP_ACP
, 0, TargetName
, -1, TargetNameW
, len
);
1098 ret
= CredDeleteW(TargetNameW
, Type
, Flags
);
1100 HeapFree(GetProcessHeap(), 0, TargetNameW
);
1105 /******************************************************************************
1106 * CredDeleteW [ADVAPI32.@]
1108 BOOL WINAPI
CredDeleteW(LPCWSTR TargetName
, DWORD Type
, DWORD Flags
)
1114 TRACE("(%s, %d, 0x%x)\n", debugstr_w(TargetName
), Type
, Flags
);
1118 SetLastError(ERROR_INVALID_PARAMETER
);
1122 if (Type
!= CRED_TYPE_GENERIC
&& Type
!= CRED_TYPE_DOMAIN_PASSWORD
)
1124 FIXME("unhandled type %d\n", Type
);
1125 SetLastError(ERROR_INVALID_PARAMETER
);
1131 FIXME("unhandled flags 0x%x\n", Flags
);
1132 SetLastError(ERROR_INVALID_FLAGS
);
1137 if (Type
== CRED_TYPE_DOMAIN_PASSWORD
)
1139 ret
= mac_delete_credential(TargetName
);
1140 if (ret
== ERROR_SUCCESS
)
1145 ret
= open_cred_mgr_key(&hkeyMgr
, TRUE
);
1146 if (ret
!= ERROR_SUCCESS
)
1148 WARN("couldn't open/create manager key, error %d\n", ret
);
1149 SetLastError(ERROR_NO_SUCH_LOGON_SESSION
);
1153 key_name
= get_key_name_for_target(TargetName
, Type
);
1154 ret
= RegDeleteKeyW(hkeyMgr
, key_name
);
1155 HeapFree(GetProcessHeap(), 0, key_name
);
1156 RegCloseKey(hkeyMgr
);
1157 if (ret
!= ERROR_SUCCESS
)
1159 SetLastError(ERROR_NOT_FOUND
);
1166 /******************************************************************************
1167 * CredEnumerateA [ADVAPI32.@]
1169 BOOL WINAPI
CredEnumerateA(LPCSTR Filter
, DWORD Flags
, DWORD
*Count
,
1170 PCREDENTIALA
**Credentials
)
1173 PCREDENTIALW
*CredentialsW
;
1178 TRACE("(%s, 0x%x, %p, %p)\n", debugstr_a(Filter
), Flags
, Count
, Credentials
);
1182 len
= MultiByteToWideChar(CP_ACP
, 0, Filter
, -1, NULL
, 0);
1183 FilterW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1186 SetLastError(ERROR_OUTOFMEMORY
);
1189 MultiByteToWideChar(CP_ACP
, 0, Filter
, -1, FilterW
, len
);
1194 if (!CredEnumerateW(FilterW
, Flags
, Count
, &CredentialsW
))
1196 HeapFree(GetProcessHeap(), 0, FilterW
);
1199 HeapFree(GetProcessHeap(), 0, FilterW
);
1201 len
= *Count
* sizeof(PCREDENTIALA
);
1202 for (i
= 0; i
< *Count
; i
++)
1203 convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW
[i
], NULL
, &len
);
1205 *Credentials
= HeapAlloc(GetProcessHeap(), 0, len
);
1208 CredFree(CredentialsW
);
1209 SetLastError(ERROR_OUTOFMEMORY
);
1213 buffer
= (char *)&(*Credentials
)[*Count
];
1214 for (i
= 0; i
< *Count
; i
++)
1217 (*Credentials
)[i
] = (PCREDENTIALA
)buffer
;
1218 convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW
[i
], (*Credentials
)[i
], &len
);
1222 CredFree(CredentialsW
);
1227 /******************************************************************************
1228 * CredEnumerateW [ADVAPI32.@]
1230 BOOL WINAPI
CredEnumerateW(LPCWSTR Filter
, DWORD Flags
, DWORD
*Count
,
1231 PCREDENTIALW
**Credentials
)
1236 DWORD target_name_len
;
1239 BYTE key_data
[KEY_SIZE
];
1241 TRACE("(%s, 0x%x, %p, %p)\n", debugstr_w(Filter
), Flags
, Count
, Credentials
);
1245 SetLastError(ERROR_INVALID_FLAGS
);
1249 ret
= open_cred_mgr_key(&hkeyMgr
, FALSE
);
1250 if (ret
!= ERROR_SUCCESS
)
1252 WARN("couldn't open/create manager key, error %d\n", ret
);
1253 SetLastError(ERROR_NO_SUCH_LOGON_SESSION
);
1257 ret
= get_cred_mgr_encryption_key(hkeyMgr
, key_data
);
1258 if (ret
!= ERROR_SUCCESS
)
1260 RegCloseKey(hkeyMgr
);
1265 ret
= RegQueryInfoKeyW(hkeyMgr
, NULL
, NULL
, NULL
, NULL
, &target_name_len
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1266 if (ret
!= ERROR_SUCCESS
)
1268 RegCloseKey(hkeyMgr
);
1273 target_name
= HeapAlloc(GetProcessHeap(), 0, (target_name_len
+1)*sizeof(WCHAR
));
1276 RegCloseKey(hkeyMgr
);
1277 SetLastError(ERROR_OUTOFMEMORY
);
1283 ret
= registry_enumerate_credentials(hkeyMgr
, Filter
, target_name
, target_name_len
,
1284 key_data
, NULL
, NULL
, &len
, Count
);
1286 if (ret
== ERROR_SUCCESS
)
1287 ret
= mac_enumerate_credentials(Filter
, NULL
, NULL
, &len
, Count
);
1289 if (ret
== ERROR_SUCCESS
&& *Count
== 0)
1290 ret
= ERROR_NOT_FOUND
;
1291 if (ret
!= ERROR_SUCCESS
)
1293 HeapFree(GetProcessHeap(), 0, target_name
);
1294 RegCloseKey(hkeyMgr
);
1298 len
+= *Count
* sizeof(PCREDENTIALW
);
1300 if (ret
== ERROR_SUCCESS
)
1302 buffer
= HeapAlloc(GetProcessHeap(), 0, len
);
1303 *Credentials
= (PCREDENTIALW
*)buffer
;
1306 buffer
+= *Count
* sizeof(PCREDENTIALW
);
1308 ret
= registry_enumerate_credentials(hkeyMgr
, Filter
, target_name
,
1309 target_name_len
, key_data
,
1310 *Credentials
, &buffer
, &len
,
1313 if (ret
== ERROR_SUCCESS
)
1314 ret
= mac_enumerate_credentials(Filter
, *Credentials
,
1315 buffer
, &len
, Count
);
1319 ret
= ERROR_OUTOFMEMORY
;
1322 HeapFree(GetProcessHeap(), 0, target_name
);
1323 RegCloseKey(hkeyMgr
);
1325 if (ret
!= ERROR_SUCCESS
)
1333 /******************************************************************************
1334 * CredFree [ADVAPI32.@]
1336 VOID WINAPI
CredFree(PVOID Buffer
)
1338 HeapFree(GetProcessHeap(), 0, Buffer
);
1341 /******************************************************************************
1342 * CredReadA [ADVAPI32.@]
1344 BOOL WINAPI
CredReadA(LPCSTR TargetName
, DWORD Type
, DWORD Flags
, PCREDENTIALA
*Credential
)
1347 PCREDENTIALW CredentialW
;
1350 TRACE("(%s, %d, 0x%x, %p)\n", debugstr_a(TargetName
), Type
, Flags
, Credential
);
1354 SetLastError(ERROR_INVALID_PARAMETER
);
1358 len
= MultiByteToWideChar(CP_ACP
, 0, TargetName
, -1, NULL
, 0);
1359 TargetNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1362 SetLastError(ERROR_OUTOFMEMORY
);
1365 MultiByteToWideChar(CP_ACP
, 0, TargetName
, -1, TargetNameW
, len
);
1367 if (!CredReadW(TargetNameW
, Type
, Flags
, &CredentialW
))
1369 HeapFree(GetProcessHeap(), 0, TargetNameW
);
1372 HeapFree(GetProcessHeap(), 0, TargetNameW
);
1375 convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW
, NULL
, &len
);
1376 *Credential
= HeapAlloc(GetProcessHeap(), 0, len
);
1379 SetLastError(ERROR_OUTOFMEMORY
);
1383 convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW
, *Credential
, &len
);
1385 CredFree(CredentialW
);
1390 /******************************************************************************
1391 * CredReadW [ADVAPI32.@]
1393 BOOL WINAPI
CredReadW(LPCWSTR TargetName
, DWORD Type
, DWORD Flags
, PCREDENTIALW
*Credential
)
1400 BYTE key_data
[KEY_SIZE
];
1402 TRACE("(%s, %d, 0x%x, %p)\n", debugstr_w(TargetName
), Type
, Flags
, Credential
);
1406 SetLastError(ERROR_INVALID_PARAMETER
);
1410 if (Type
!= CRED_TYPE_GENERIC
&& Type
!= CRED_TYPE_DOMAIN_PASSWORD
)
1412 FIXME("unhandled type %d\n", Type
);
1413 SetLastError(ERROR_INVALID_PARAMETER
);
1419 FIXME("unhandled flags 0x%x\n", Flags
);
1420 SetLastError(ERROR_INVALID_FLAGS
);
1425 if (Type
== CRED_TYPE_DOMAIN_PASSWORD
)
1428 SecKeychainSearchRef search
;
1429 status
= SecKeychainSearchCreateFromAttributes(NULL
, kSecInternetPasswordItemClass
, NULL
, &search
);
1430 if (status
== noErr
)
1432 SecKeychainItemRef item
;
1433 while (SecKeychainSearchCopyNext(search
, &item
) == noErr
)
1435 SecKeychainAttributeInfo info
;
1436 SecKeychainAttributeList
*attr_list
;
1437 UInt32 info_tags
[] = { kSecServerItemAttr
};
1440 info
.count
= sizeof(info_tags
)/sizeof(info_tags
[0]);
1441 info
.tag
= info_tags
;
1443 status
= SecKeychainItemCopyAttributesAndData(item
, &info
, NULL
, &attr_list
, NULL
, NULL
);
1444 len
= sizeof(**Credential
);
1445 if (status
!= noErr
)
1447 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status
);
1450 if (attr_list
->count
!= 1 || attr_list
->attr
[0].tag
!= kSecServerItemAttr
)
1455 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[0].data
, attr_list
->attr
[0].length
, NULL
, 0);
1456 target_name
= HeapAlloc(GetProcessHeap(), 0, (str_len
+ 1) * sizeof(WCHAR
));
1457 MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[0].data
, attr_list
->attr
[0].length
, target_name
, str_len
);
1459 target_name
[str_len
] = '\0';
1460 if (strcmpiW(TargetName
, target_name
))
1463 HeapFree(GetProcessHeap(), 0, target_name
);
1466 HeapFree(GetProcessHeap(), 0, target_name
);
1467 SecKeychainItemFreeAttributesAndData(attr_list
, NULL
);
1468 ret
= mac_read_credential_from_item(item
, TRUE
, NULL
, NULL
, &len
);
1469 if (ret
== ERROR_SUCCESS
)
1471 *Credential
= HeapAlloc(GetProcessHeap(), 0, len
);
1474 len
= sizeof(**Credential
);
1475 ret
= mac_read_credential_from_item(item
, TRUE
, *Credential
,
1476 (char *)(*Credential
+ 1), &len
);
1479 ret
= ERROR_OUTOFMEMORY
;
1482 if (ret
!= ERROR_SUCCESS
)
1496 ret
= open_cred_mgr_key(&hkeyMgr
, FALSE
);
1497 if (ret
!= ERROR_SUCCESS
)
1499 WARN("couldn't open/create manager key, error %d\n", ret
);
1500 SetLastError(ERROR_NO_SUCH_LOGON_SESSION
);
1504 ret
= get_cred_mgr_encryption_key(hkeyMgr
, key_data
);
1505 if (ret
!= ERROR_SUCCESS
)
1507 RegCloseKey(hkeyMgr
);
1512 key_name
= get_key_name_for_target(TargetName
, Type
);
1513 ret
= RegOpenKeyExW(hkeyMgr
, key_name
, 0, KEY_QUERY_VALUE
, &hkeyCred
);
1514 HeapFree(GetProcessHeap(), 0, key_name
);
1515 if (ret
!= ERROR_SUCCESS
)
1517 TRACE("credentials for target name %s not found\n", debugstr_w(TargetName
));
1518 SetLastError(ERROR_NOT_FOUND
);
1522 len
= sizeof(**Credential
);
1523 ret
= registry_read_credential(hkeyCred
, NULL
, key_data
, NULL
, &len
);
1524 if (ret
== ERROR_SUCCESS
)
1526 *Credential
= HeapAlloc(GetProcessHeap(), 0, len
);
1529 len
= sizeof(**Credential
);
1530 ret
= registry_read_credential(hkeyCred
, *Credential
, key_data
,
1531 (char *)(*Credential
+ 1), &len
);
1534 ret
= ERROR_OUTOFMEMORY
;
1537 RegCloseKey(hkeyCred
);
1538 RegCloseKey(hkeyMgr
);
1540 if (ret
!= ERROR_SUCCESS
)
1548 /******************************************************************************
1549 * CredWriteA [ADVAPI32.@]
1551 BOOL WINAPI
CredWriteA(PCREDENTIALA Credential
, DWORD Flags
)
1555 PCREDENTIALW CredentialW
;
1557 TRACE("(%p, 0x%x)\n", Credential
, Flags
);
1559 if (!Credential
|| !Credential
->TargetName
)
1561 SetLastError(ERROR_INVALID_PARAMETER
);
1566 convert_PCREDENTIALA_to_PCREDENTIALW(Credential
, NULL
, &len
);
1567 CredentialW
= HeapAlloc(GetProcessHeap(), 0, len
);
1570 SetLastError(ERROR_OUTOFMEMORY
);
1574 convert_PCREDENTIALA_to_PCREDENTIALW(Credential
, CredentialW
, &len
);
1576 ret
= CredWriteW(CredentialW
, Flags
);
1578 HeapFree(GetProcessHeap(), 0, CredentialW
);
1583 /******************************************************************************
1584 * CredWriteW [ADVAPI32.@]
1586 BOOL WINAPI
CredWriteW(PCREDENTIALW Credential
, DWORD Flags
)
1592 BYTE key_data
[KEY_SIZE
];
1594 TRACE("(%p, 0x%x)\n", Credential
, Flags
);
1596 if (!Credential
|| !Credential
->TargetName
)
1598 SetLastError(ERROR_INVALID_PARAMETER
);
1602 if (Flags
& ~CRED_PRESERVE_CREDENTIAL_BLOB
)
1604 FIXME("unhandled flags 0x%x\n", Flags
);
1605 SetLastError(ERROR_INVALID_FLAGS
);
1609 if (Credential
->Type
!= CRED_TYPE_GENERIC
&& Credential
->Type
!= CRED_TYPE_DOMAIN_PASSWORD
)
1611 FIXME("unhandled type %d\n", Credential
->Type
);
1612 SetLastError(ERROR_INVALID_PARAMETER
);
1616 TRACE("Credential->TargetName = %s\n", debugstr_w(Credential
->TargetName
));
1617 TRACE("Credential->UserName = %s\n", debugstr_w(Credential
->UserName
));
1619 if (Credential
->Type
== CRED_TYPE_DOMAIN_PASSWORD
)
1621 if (!Credential
->UserName
||
1622 (!strchrW(Credential
->UserName
, '\\') && !strchrW(Credential
->UserName
, '@')))
1624 ERR("bad username %s\n", debugstr_w(Credential
->UserName
));
1625 SetLastError(ERROR_BAD_USERNAME
);
1631 if (!Credential
->AttributeCount
&&
1632 Credential
->Type
== CRED_TYPE_DOMAIN_PASSWORD
&&
1633 (Credential
->Persist
== CRED_PERSIST_LOCAL_MACHINE
|| Credential
->Persist
== CRED_PERSIST_ENTERPRISE
))
1635 ret
= mac_write_credential(Credential
, Flags
& CRED_PRESERVE_CREDENTIAL_BLOB
);
1636 if (ret
!= ERROR_SUCCESS
)
1645 ret
= open_cred_mgr_key(&hkeyMgr
, FALSE
);
1646 if (ret
!= ERROR_SUCCESS
)
1648 WARN("couldn't open/create manager key, error %d\n", ret
);
1649 SetLastError(ERROR_NO_SUCH_LOGON_SESSION
);
1653 ret
= get_cred_mgr_encryption_key(hkeyMgr
, key_data
);
1654 if (ret
!= ERROR_SUCCESS
)
1656 RegCloseKey(hkeyMgr
);
1661 key_name
= get_key_name_for_target(Credential
->TargetName
, Credential
->Type
);
1662 ret
= RegCreateKeyExW(hkeyMgr
, key_name
, 0, NULL
,
1663 Credential
->Persist
== CRED_PERSIST_SESSION
? REG_OPTION_VOLATILE
: REG_OPTION_NON_VOLATILE
,
1664 KEY_READ
|KEY_WRITE
, NULL
, &hkeyCred
, NULL
);
1665 HeapFree(GetProcessHeap(), 0, key_name
);
1666 if (ret
!= ERROR_SUCCESS
)
1668 TRACE("credentials for target name %s not found\n",
1669 debugstr_w(Credential
->TargetName
));
1670 SetLastError(ERROR_NOT_FOUND
);
1674 ret
= registry_write_credential(hkeyCred
, Credential
, key_data
,
1675 Flags
& CRED_PRESERVE_CREDENTIAL_BLOB
);
1677 RegCloseKey(hkeyCred
);
1678 RegCloseKey(hkeyMgr
);
1680 if (ret
!= ERROR_SUCCESS
)
1688 /******************************************************************************
1689 * CredGetSessionTypes [ADVAPI32.@]
1691 WINADVAPI BOOL WINAPI
CredGetSessionTypes(DWORD persistCount
, LPDWORD persists
)
1693 TRACE("(%u, %p)\n", persistCount
, persists
);
1695 memset(persists
, CRED_PERSIST_NONE
, persistCount
*sizeof(*persists
));
1696 if (CRED_TYPE_GENERIC
< persistCount
)
1698 persists
[CRED_TYPE_GENERIC
] = CRED_PERSIST_ENTERPRISE
;
1700 if (CRED_TYPE_DOMAIN_PASSWORD
< persistCount
)
1702 persists
[CRED_TYPE_DOMAIN_PASSWORD
] = CRED_PERSIST_ENTERPRISE
;