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
26 # include <Security/SecKeychain.h>
27 # include <Security/SecKeychainItem.h>
28 # include <Security/SecKeychainSearch.h>
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 #include "advapi32_misc.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(cred
);
46 /* the size of the ARC4 key used to encrypt the password data */
49 static const WCHAR wszCredentialManagerKey
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
50 'C','r','e','d','e','n','t','i','a','l',' ','M','a','n','a','g','e','r',0};
51 static const WCHAR wszEncryptionKeyValue
[] = {'E','n','c','r','y','p','t','i','o','n','K','e','y',0};
53 static const WCHAR wszFlagsValue
[] = {'F','l','a','g','s',0};
54 static const WCHAR wszTypeValue
[] = {'T','y','p','e',0};
55 static const WCHAR wszCommentValue
[] = {'C','o','m','m','e','n','t',0};
56 static const WCHAR wszLastWrittenValue
[] = {'L','a','s','t','W','r','i','t','t','e','n',0};
57 static const WCHAR wszPersistValue
[] = {'P','e','r','s','i','s','t',0};
58 static const WCHAR wszTargetAliasValue
[] = {'T','a','r','g','e','t','A','l','i','a','s',0};
59 static const WCHAR wszUserNameValue
[] = {'U','s','e','r','N','a','m','e',0};
60 static const WCHAR wszPasswordValue
[] = {'P','a','s','s','w','o','r','d',0};
62 static DWORD
read_credential_blob(HKEY hkey
, const BYTE key_data
[KEY_SIZE
],
63 LPBYTE credential_blob
,
64 DWORD
*credential_blob_size
)
69 *credential_blob_size
= 0;
70 ret
= RegQueryValueExW(hkey
, wszPasswordValue
, 0, &type
, NULL
, credential_blob_size
);
71 if (ret
!= ERROR_SUCCESS
)
73 else if (type
!= REG_BINARY
)
74 return ERROR_REGISTRY_CORRUPT
;
80 ret
= RegQueryValueExW(hkey
, wszPasswordValue
, 0, &type
, credential_blob
,
81 credential_blob_size
);
82 if (ret
!= ERROR_SUCCESS
)
84 else if (type
!= REG_BINARY
)
85 return ERROR_REGISTRY_CORRUPT
;
87 key
.Length
= key
.MaximumLength
= KEY_SIZE
;
88 key
.Buffer
= (unsigned char *)key_data
;
90 data
.Length
= data
.MaximumLength
= *credential_blob_size
;
91 data
.Buffer
= credential_blob
;
92 SystemFunction032(&data
, &key
);
97 static DWORD
registry_read_credential(HKEY hkey
, PCREDENTIALW credential
,
98 const BYTE key_data
[KEY_SIZE
],
99 char *buffer
, DWORD
*len
)
105 ret
= RegQueryValueExW(hkey
, NULL
, 0, &type
, NULL
, &count
);
106 if (ret
!= ERROR_SUCCESS
)
108 else if (type
!= REG_SZ
)
109 return ERROR_REGISTRY_CORRUPT
;
113 credential
->TargetName
= (LPWSTR
)buffer
;
114 ret
= RegQueryValueExW(hkey
, NULL
, 0, &type
, (LPVOID
)credential
->TargetName
,
116 if (ret
!= ERROR_SUCCESS
|| type
!= REG_SZ
) return ret
;
120 ret
= RegQueryValueExW(hkey
, wszCommentValue
, 0, &type
, NULL
, &count
);
121 if (ret
!= ERROR_FILE_NOT_FOUND
&& ret
!= ERROR_SUCCESS
)
123 else if (type
!= REG_SZ
)
124 return ERROR_REGISTRY_CORRUPT
;
128 credential
->Comment
= (LPWSTR
)buffer
;
129 ret
= RegQueryValueExW(hkey
, wszCommentValue
, 0, &type
, (LPVOID
)credential
->Comment
,
131 if (ret
== ERROR_FILE_NOT_FOUND
)
132 credential
->Comment
= NULL
;
133 else if (ret
!= ERROR_SUCCESS
)
135 else if (type
!= REG_SZ
)
136 return ERROR_REGISTRY_CORRUPT
;
141 ret
= RegQueryValueExW(hkey
, wszTargetAliasValue
, 0, &type
, NULL
, &count
);
142 if (ret
!= ERROR_FILE_NOT_FOUND
&& ret
!= ERROR_SUCCESS
)
144 else if (type
!= REG_SZ
)
145 return ERROR_REGISTRY_CORRUPT
;
149 credential
->TargetAlias
= (LPWSTR
)buffer
;
150 ret
= RegQueryValueExW(hkey
, wszTargetAliasValue
, 0, &type
, (LPVOID
)credential
->TargetAlias
,
152 if (ret
== ERROR_FILE_NOT_FOUND
)
153 credential
->TargetAlias
= NULL
;
154 else if (ret
!= ERROR_SUCCESS
)
156 else if (type
!= REG_SZ
)
157 return ERROR_REGISTRY_CORRUPT
;
162 ret
= RegQueryValueExW(hkey
, wszUserNameValue
, 0, &type
, NULL
, &count
);
163 if (ret
!= ERROR_FILE_NOT_FOUND
&& ret
!= ERROR_SUCCESS
)
165 else if (type
!= REG_SZ
)
166 return ERROR_REGISTRY_CORRUPT
;
170 credential
->UserName
= (LPWSTR
)buffer
;
171 ret
= RegQueryValueExW(hkey
, wszUserNameValue
, 0, &type
, (LPVOID
)credential
->UserName
,
173 if (ret
== ERROR_FILE_NOT_FOUND
)
174 credential
->UserName
= NULL
;
175 else if (ret
!= ERROR_SUCCESS
)
177 else if (type
!= REG_SZ
)
178 return ERROR_REGISTRY_CORRUPT
;
183 ret
= read_credential_blob(hkey
, key_data
, NULL
, &count
);
184 if (ret
!= ERROR_FILE_NOT_FOUND
&& ret
!= ERROR_SUCCESS
)
189 credential
->CredentialBlob
= (LPBYTE
)buffer
;
190 ret
= read_credential_blob(hkey
, key_data
, credential
->CredentialBlob
, &count
);
191 if (ret
== ERROR_FILE_NOT_FOUND
)
192 credential
->CredentialBlob
= NULL
;
193 else if (ret
!= ERROR_SUCCESS
)
195 credential
->CredentialBlobSize
= count
;
198 /* FIXME: Attributes */
201 credential
->AttributeCount
= 0;
202 credential
->Attributes
= NULL
;
205 if (!credential
) return ERROR_SUCCESS
;
207 count
= sizeof(credential
->Flags
);
208 ret
= RegQueryValueExW(hkey
, wszFlagsValue
, NULL
, &type
, (LPVOID
)&credential
->Flags
,
210 if (ret
!= ERROR_SUCCESS
)
212 else if (type
!= REG_DWORD
)
213 return ERROR_REGISTRY_CORRUPT
;
214 count
= sizeof(credential
->Type
);
215 ret
= RegQueryValueExW(hkey
, wszTypeValue
, NULL
, &type
, (LPVOID
)&credential
->Type
,
217 if (ret
!= ERROR_SUCCESS
)
219 else if (type
!= REG_DWORD
)
220 return ERROR_REGISTRY_CORRUPT
;
222 count
= sizeof(credential
->LastWritten
);
223 ret
= RegQueryValueExW(hkey
, wszLastWrittenValue
, NULL
, &type
, (LPVOID
)&credential
->LastWritten
,
225 if (ret
!= ERROR_SUCCESS
)
227 else if (type
!= REG_BINARY
)
228 return ERROR_REGISTRY_CORRUPT
;
229 count
= sizeof(credential
->Persist
);
230 ret
= RegQueryValueExW(hkey
, wszPersistValue
, NULL
, &type
, (LPVOID
)&credential
->Persist
,
232 if (ret
== ERROR_SUCCESS
&& type
!= REG_DWORD
)
233 return ERROR_REGISTRY_CORRUPT
;
238 static DWORD
mac_read_credential_from_item(SecKeychainItemRef item
, BOOL require_password
,
239 PCREDENTIALW credential
, char *buffer
,
243 UInt32 i
, cred_blob_len
;
246 BOOL user_name_present
= FALSE
;
247 SecKeychainAttributeInfo info
;
248 SecKeychainAttributeList
*attr_list
;
249 UInt32 info_tags
[] = { kSecServiceItemAttr
, kSecAccountItemAttr
,
250 kSecCommentItemAttr
, kSecCreationDateItemAttr
};
251 info
.count
= sizeof(info_tags
)/sizeof(info_tags
[0]);
252 info
.tag
= info_tags
;
254 status
= SecKeychainItemCopyAttributesAndData(item
, &info
, NULL
, &attr_list
, &cred_blob_len
, &cred_blob
);
255 if (status
== errSecAuthFailed
&& !require_password
)
259 status
= SecKeychainItemCopyAttributesAndData(item
, &info
, NULL
, &attr_list
, &cred_blob_len
, NULL
);
263 WARN("SecKeychainItemCopyAttributesAndData returned status %d\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
;
273 if (!user_name_present
)
275 WARN("no kSecAccountItemAttr for item\n");
276 SecKeychainItemFreeAttributesAndData(attr_list
, cred_blob
);
277 return ERROR_NOT_FOUND
;
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 kSecServiceItemAttr
:
300 TRACE("kSecServiceItemAttr: %.*s\n", (int)attr_list
->attr
[i
].length
,
301 (char *)attr_list
->attr
[i
].data
);
302 if (!attr_list
->attr
[i
].data
) continue;
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
);
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
);
321 case kSecAccountItemAttr
:
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
= heap_alloc((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';
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;
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
);
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
);
357 case kSecCreationDateItemAttr
:
358 TRACE("kSecCreationDateItemAttr: %.*s\n", (int)attr_list
->attr
[i
].length
,
359 (char *)attr_list
->attr
[i
].data
);
360 if (!attr_list
->attr
[i
].data
) continue;
363 LARGE_INTEGER win_time
;
366 memset(&tm
, 0, sizeof(tm
));
367 strptime(attr_list
->attr
[i
].data
, "%Y%m%d%H%M%SZ", &tm
);
369 RtlSecondsSince1970ToTime(time
, &win_time
);
370 credential
->LastWritten
.dwLowDateTime
= win_time
.u
.LowPart
;
371 credential
->LastWritten
.dwHighDateTime
= win_time
.u
.HighPart
;
375 FIXME("unhandled attribute %u\n", (unsigned)attr_list
->attr
[i
].tag
);
384 credential
->UserName
= (LPWSTR
)buffer
;
385 str_len
= strlenW(user
);
386 *len
+= (str_len
+ 1) * sizeof(WCHAR
);
389 memcpy(buffer
, user
, (str_len
+ 1) * sizeof(WCHAR
));
390 buffer
+= (str_len
+ 1) * sizeof(WCHAR
);
391 TRACE("UserName = %s\n", debugstr_w(credential
->UserName
));
401 credential
->CredentialBlob
= (BYTE
*)buffer
;
402 str_len
= MultiByteToWideChar(CP_UTF8
, 0, cred_blob
, cred_blob_len
,
403 (LPWSTR
)buffer
, 0xffff);
404 credential
->CredentialBlobSize
= str_len
* sizeof(WCHAR
);
405 *len
+= str_len
* sizeof(WCHAR
);
410 str_len
= MultiByteToWideChar(CP_UTF8
, 0, cred_blob
, cred_blob_len
,
412 *len
+= str_len
* sizeof(WCHAR
);
415 SecKeychainItemFreeAttributesAndData(attr_list
, cred_blob
);
416 return ERROR_SUCCESS
;
420 static DWORD
write_credential_blob(HKEY hkey
, LPCWSTR target_name
, DWORD type
,
421 const BYTE key_data
[KEY_SIZE
],
422 const BYTE
*credential_blob
, DWORD credential_blob_size
)
424 LPBYTE encrypted_credential_blob
;
429 key
.Length
= key
.MaximumLength
= KEY_SIZE
;
430 key
.Buffer
= (unsigned char *)key_data
;
432 encrypted_credential_blob
= heap_alloc(credential_blob_size
);
433 if (!encrypted_credential_blob
) return ERROR_OUTOFMEMORY
;
435 memcpy(encrypted_credential_blob
, credential_blob
, credential_blob_size
);
436 data
.Length
= data
.MaximumLength
= credential_blob_size
;
437 data
.Buffer
= encrypted_credential_blob
;
438 SystemFunction032(&data
, &key
);
440 ret
= RegSetValueExW(hkey
, wszPasswordValue
, 0, REG_BINARY
, encrypted_credential_blob
, credential_blob_size
);
441 heap_free(encrypted_credential_blob
);
446 static DWORD
registry_write_credential(HKEY hkey
, const CREDENTIALW
*credential
,
447 const BYTE key_data
[KEY_SIZE
], BOOL preserve_blob
)
450 FILETIME LastWritten
;
452 GetSystemTimeAsFileTime(&LastWritten
);
454 ret
= RegSetValueExW(hkey
, wszFlagsValue
, 0, REG_DWORD
, (const BYTE
*)&credential
->Flags
,
455 sizeof(credential
->Flags
));
456 if (ret
!= ERROR_SUCCESS
) return ret
;
457 ret
= RegSetValueExW(hkey
, wszTypeValue
, 0, REG_DWORD
, (const BYTE
*)&credential
->Type
,
458 sizeof(credential
->Type
));
459 if (ret
!= ERROR_SUCCESS
) return ret
;
460 ret
= RegSetValueExW(hkey
, NULL
, 0, REG_SZ
, (LPVOID
)credential
->TargetName
,
461 sizeof(WCHAR
)*(strlenW(credential
->TargetName
)+1));
462 if (ret
!= ERROR_SUCCESS
) return ret
;
463 if (credential
->Comment
)
465 ret
= RegSetValueExW(hkey
, wszCommentValue
, 0, REG_SZ
, (LPVOID
)credential
->Comment
,
466 sizeof(WCHAR
)*(strlenW(credential
->Comment
)+1));
467 if (ret
!= ERROR_SUCCESS
) return ret
;
469 ret
= RegSetValueExW(hkey
, wszLastWrittenValue
, 0, REG_BINARY
, (LPVOID
)&LastWritten
,
470 sizeof(LastWritten
));
471 if (ret
!= ERROR_SUCCESS
) return ret
;
472 ret
= RegSetValueExW(hkey
, wszPersistValue
, 0, REG_DWORD
, (const BYTE
*)&credential
->Persist
,
473 sizeof(credential
->Persist
));
474 if (ret
!= ERROR_SUCCESS
) return ret
;
475 /* FIXME: Attributes */
476 if (credential
->TargetAlias
)
478 ret
= RegSetValueExW(hkey
, wszTargetAliasValue
, 0, REG_SZ
, (LPVOID
)credential
->TargetAlias
,
479 sizeof(WCHAR
)*(strlenW(credential
->TargetAlias
)+1));
480 if (ret
!= ERROR_SUCCESS
) return ret
;
482 if (credential
->UserName
)
484 ret
= RegSetValueExW(hkey
, wszUserNameValue
, 0, REG_SZ
, (LPVOID
)credential
->UserName
,
485 sizeof(WCHAR
)*(strlenW(credential
->UserName
)+1));
486 if (ret
!= ERROR_SUCCESS
) return ret
;
490 ret
= write_credential_blob(hkey
, credential
->TargetName
, credential
->Type
,
491 key_data
, credential
->CredentialBlob
,
492 credential
->CredentialBlobSize
);
498 static DWORD
mac_write_credential(const CREDENTIALW
*credential
, BOOL preserve_blob
)
501 SecKeychainItemRef keychain_item
;
502 char *username
, *password
, *servername
;
503 UInt32 userlen
, pwlen
, serverlen
;
504 SecKeychainAttribute attrs
[1];
505 SecKeychainAttributeList attr_list
;
507 if (credential
->Flags
)
508 FIXME("Flags 0x%x not written\n", credential
->Flags
);
509 if (credential
->Type
!= CRED_TYPE_DOMAIN_PASSWORD
)
510 FIXME("credential type of %d not supported\n", credential
->Type
);
511 if (credential
->Persist
!= CRED_PERSIST_LOCAL_MACHINE
)
512 FIXME("persist value of %d not supported\n", credential
->Persist
);
513 if (credential
->AttributeCount
)
514 FIXME("custom attributes not supported\n");
516 userlen
= WideCharToMultiByte(CP_UTF8
, 0, credential
->UserName
, -1, NULL
, 0, NULL
, NULL
);
517 username
= heap_alloc(userlen
* sizeof(*username
));
518 WideCharToMultiByte(CP_UTF8
, 0, credential
->UserName
, -1, username
, userlen
, NULL
, NULL
);
520 serverlen
= WideCharToMultiByte(CP_UTF8
, 0, credential
->TargetName
, -1, NULL
, 0, NULL
, NULL
);
521 servername
= heap_alloc(serverlen
* sizeof(*servername
));
522 WideCharToMultiByte(CP_UTF8
, 0, credential
->TargetName
, -1, servername
, serverlen
, NULL
, NULL
);
523 pwlen
= WideCharToMultiByte(CP_UTF8
, 0, (LPCWSTR
)credential
->CredentialBlob
,
524 credential
->CredentialBlobSize
/ sizeof(WCHAR
), NULL
, 0, NULL
, NULL
);
525 password
= heap_alloc(pwlen
* sizeof(*password
));
526 WideCharToMultiByte(CP_UTF8
, 0, (LPCWSTR
)credential
->CredentialBlob
,
527 credential
->CredentialBlobSize
/ sizeof(WCHAR
), password
, pwlen
, NULL
, NULL
);
529 TRACE("adding server %s, username %s using Keychain\n", servername
, username
);
530 status
= SecKeychainAddGenericPassword(NULL
, strlen(servername
), servername
, strlen(username
),
531 username
, strlen(password
), password
, &keychain_item
);
533 ERR("SecKeychainAddGenericPassword returned %d\n", status
);
534 if (status
== errSecDuplicateItem
)
536 status
= SecKeychainFindGenericPassword(NULL
, strlen(servername
), servername
, strlen(username
),
537 username
, NULL
, NULL
, &keychain_item
);
539 ERR("SecKeychainFindGenericPassword returned %d\n", status
);
542 heap_free(servername
);
546 return ERROR_GEN_FAILURE
;
548 if (credential
->Comment
)
551 attr_list
.attr
= attrs
;
552 attrs
[0].tag
= kSecCommentItemAttr
;
553 attrs
[0].length
= WideCharToMultiByte(CP_UTF8
, 0, credential
->Comment
, -1, NULL
, 0, NULL
, NULL
);
554 if (attrs
[0].length
) attrs
[0].length
--;
555 attrs
[0].data
= heap_alloc(attrs
[0].length
);
556 WideCharToMultiByte(CP_UTF8
, 0, credential
->Comment
, -1, attrs
[0].data
, attrs
[0].length
, NULL
, NULL
);
561 attr_list
.attr
= NULL
;
563 status
= SecKeychainItemModifyAttributesAndData(keychain_item
, &attr_list
,
564 preserve_blob
? 0 : strlen(password
),
565 preserve_blob
? NULL
: password
);
566 if (credential
->Comment
)
567 heap_free(attrs
[0].data
);
569 /* FIXME: set TargetAlias attribute */
570 CFRelease(keychain_item
);
572 return ERROR_GEN_FAILURE
;
573 return ERROR_SUCCESS
;
577 static DWORD
open_cred_mgr_key(HKEY
*hkey
, BOOL open_for_write
)
579 return RegCreateKeyExW(HKEY_CURRENT_USER
, wszCredentialManagerKey
, 0,
580 NULL
, REG_OPTION_NON_VOLATILE
,
581 KEY_READ
| (open_for_write
? KEY_WRITE
: 0), NULL
, hkey
, NULL
);
584 static DWORD
get_cred_mgr_encryption_key(HKEY hkeyMgr
, BYTE key_data
[KEY_SIZE
])
586 static const BYTE my_key_data
[KEY_SIZE
] = { 0 };
594 memcpy(key_data
, my_key_data
, KEY_SIZE
);
597 ret
= RegQueryValueExW(hkeyMgr
, wszEncryptionKeyValue
, NULL
, &type
, key_data
,
599 if (ret
== ERROR_SUCCESS
)
601 if (type
!= REG_BINARY
)
602 return ERROR_REGISTRY_CORRUPT
;
604 return ERROR_SUCCESS
;
606 if (ret
!= ERROR_FILE_NOT_FOUND
)
609 GetSystemTimeAsFileTime(&ft
);
610 seed
= ft
.dwLowDateTime
;
611 value
= RtlUniform(&seed
);
612 *(DWORD
*)key_data
= value
;
613 seed
= ft
.dwHighDateTime
;
614 value
= RtlUniform(&seed
);
615 *(DWORD
*)(key_data
+ 4) = value
;
617 ret
= RegSetValueExW(hkeyMgr
, wszEncryptionKeyValue
, 0, REG_BINARY
,
619 if (ret
== ERROR_ACCESS_DENIED
)
621 ret
= open_cred_mgr_key(&hkeyMgr
, TRUE
);
622 if (ret
== ERROR_SUCCESS
)
624 ret
= RegSetValueExW(hkeyMgr
, wszEncryptionKeyValue
, 0, REG_BINARY
,
626 RegCloseKey(hkeyMgr
);
632 static LPWSTR
get_key_name_for_target(LPCWSTR target_name
, DWORD type
)
634 static const WCHAR wszGenericPrefix
[] = {'G','e','n','e','r','i','c',':',' ',0};
635 static const WCHAR wszDomPasswdPrefix
[] = {'D','o','m','P','a','s','s','w','d',':',' ',0};
637 LPCWSTR prefix
= NULL
;
640 len
= strlenW(target_name
);
641 if (type
== CRED_TYPE_GENERIC
)
643 prefix
= wszGenericPrefix
;
644 len
+= sizeof(wszGenericPrefix
)/sizeof(wszGenericPrefix
[0]);
648 prefix
= wszDomPasswdPrefix
;
649 len
+= sizeof(wszDomPasswdPrefix
)/sizeof(wszDomPasswdPrefix
[0]);
652 key_name
= heap_alloc(len
* sizeof(WCHAR
));
653 if (!key_name
) return NULL
;
655 strcpyW(key_name
, prefix
);
656 strcatW(key_name
, target_name
);
658 for (p
= key_name
; *p
; p
++)
659 if (*p
== '\\') *p
= '_';
664 static BOOL
registry_credential_matches_filter(HKEY hkeyCred
, LPCWSTR filter
)
672 if (!filter
) return TRUE
;
674 ret
= RegQueryValueExW(hkeyCred
, NULL
, 0, &type
, NULL
, &count
);
675 if (ret
!= ERROR_SUCCESS
)
677 else if (type
!= REG_SZ
)
680 target_name
= heap_alloc(count
);
683 ret
= RegQueryValueExW(hkeyCred
, NULL
, 0, &type
, (LPVOID
)target_name
, &count
);
684 if (ret
!= ERROR_SUCCESS
|| type
!= REG_SZ
)
686 heap_free(target_name
);
690 TRACE("comparing filter %s to target name %s\n", debugstr_w(filter
),
691 debugstr_w(target_name
));
693 p
= strchrW(filter
, '*');
694 ret
= CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, filter
,
695 (p
&& !p
[1] ? p
- filter
: -1), target_name
,
696 (p
&& !p
[1] ? p
- filter
: -1)) == CSTR_EQUAL
;
698 heap_free(target_name
);
702 static DWORD
registry_enumerate_credentials(HKEY hkeyMgr
, LPCWSTR filter
,
704 DWORD target_name_len
, const BYTE key_data
[KEY_SIZE
],
705 PCREDENTIALW
*credentials
, char **buffer
,
706 DWORD
*len
, DWORD
*count
)
713 ret
= RegEnumKeyW(hkeyMgr
, i
, target_name
, target_name_len
+1);
714 if (ret
== ERROR_NO_MORE_ITEMS
)
719 else if (ret
!= ERROR_SUCCESS
)
721 TRACE("target_name = %s\n", debugstr_w(target_name
));
722 ret
= RegOpenKeyExW(hkeyMgr
, target_name
, 0, KEY_QUERY_VALUE
, &hkeyCred
);
723 if (ret
!= ERROR_SUCCESS
)
725 if (!registry_credential_matches_filter(hkeyCred
, filter
))
727 RegCloseKey(hkeyCred
);
732 *len
= sizeof(CREDENTIALW
);
733 credentials
[*count
] = (PCREDENTIALW
)*buffer
;
736 *len
+= sizeof(CREDENTIALW
);
737 ret
= registry_read_credential(hkeyCred
, buffer
? credentials
[*count
] : NULL
,
738 key_data
, buffer
? *buffer
+ sizeof(CREDENTIALW
) : NULL
,
740 RegCloseKey(hkeyCred
);
741 if (ret
!= ERROR_SUCCESS
) break;
742 if (buffer
) *buffer
+= *len
;
749 static BOOL
mac_credential_matches_filter(void *data
, UInt32 data_len
, const WCHAR
*filter
)
756 if (!filter
) return TRUE
;
758 len
= MultiByteToWideChar(CP_UTF8
, 0, data
, data_len
, NULL
, 0);
759 if (!(target_name
= heap_alloc((len
+ 1) * sizeof(WCHAR
)))) return FALSE
;
760 MultiByteToWideChar(CP_UTF8
, 0, data
, data_len
, target_name
, len
);
761 target_name
[len
] = 0;
763 TRACE("comparing filter %s to target name %s\n", debugstr_w(filter
), debugstr_w(target_name
));
765 p
= strchrW(filter
, '*');
766 ret
= CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, filter
,
767 (p
&& !p
[1] ? p
- filter
: -1), target_name
,
768 (p
&& !p
[1] ? p
- filter
: -1)) == CSTR_EQUAL
;
769 heap_free(target_name
);
773 static DWORD
mac_enumerate_credentials(LPCWSTR filter
, PCREDENTIALW
*credentials
,
774 char *buffer
, DWORD
*len
, DWORD
*count
)
776 SecKeychainSearchRef search
;
777 SecKeychainItemRef item
;
779 Boolean saved_user_interaction_allowed
;
782 SecKeychainGetUserInteractionAllowed(&saved_user_interaction_allowed
);
783 SecKeychainSetUserInteractionAllowed(false);
785 status
= SecKeychainSearchCreateFromAttributes(NULL
, kSecGenericPasswordItemClass
, NULL
, &search
);
788 while (SecKeychainSearchCopyNext(search
, &item
) == noErr
)
790 SecKeychainAttributeInfo info
;
791 SecKeychainAttributeList
*attr_list
;
792 UInt32 info_tags
[] = { kSecServiceItemAttr
};
795 info
.count
= sizeof(info_tags
)/sizeof(info_tags
[0]);
796 info
.tag
= info_tags
;
798 status
= SecKeychainItemCopyAttributesAndData(item
, &info
, NULL
, &attr_list
, NULL
, NULL
);
801 WARN("SecKeychainItemCopyAttributesAndData returned status %d\n", status
);
806 *len
= sizeof(CREDENTIALW
);
807 credentials
[*count
] = (PCREDENTIALW
)buffer
;
810 *len
+= sizeof(CREDENTIALW
);
811 if (attr_list
->count
!= 1 || attr_list
->attr
[0].tag
!= kSecServiceItemAttr
)
813 SecKeychainItemFreeAttributesAndData(attr_list
, NULL
);
816 TRACE("service item: %.*s\n", (int)attr_list
->attr
[0].length
, (char *)attr_list
->attr
[0].data
);
817 match
= mac_credential_matches_filter(attr_list
->attr
[0].data
, attr_list
->attr
[0].length
, filter
);
818 SecKeychainItemFreeAttributesAndData(attr_list
, NULL
);
819 if (!match
) continue;
820 ret
= mac_read_credential_from_item(item
, FALSE
,
821 buffer
? credentials
[*count
] : NULL
,
822 buffer
? buffer
+ sizeof(CREDENTIALW
) : NULL
,
825 if (ret
== ERROR_SUCCESS
)
828 if (buffer
) buffer
+= *len
;
834 ERR("SecKeychainSearchCreateFromAttributes returned status %d\n", status
);
835 SecKeychainSetUserInteractionAllowed(saved_user_interaction_allowed
);
836 return ERROR_SUCCESS
;
839 static DWORD
mac_delete_credential(LPCWSTR TargetName
)
842 SecKeychainSearchRef search
;
843 status
= SecKeychainSearchCreateFromAttributes(NULL
, kSecGenericPasswordItemClass
, NULL
, &search
);
846 SecKeychainItemRef item
;
847 while (SecKeychainSearchCopyNext(search
, &item
) == noErr
)
849 SecKeychainAttributeInfo info
;
850 SecKeychainAttributeList
*attr_list
;
851 UInt32 info_tags
[] = { kSecServiceItemAttr
};
854 info
.count
= sizeof(info_tags
)/sizeof(info_tags
[0]);
855 info
.tag
= info_tags
;
857 status
= SecKeychainItemCopyAttributesAndData(item
, &info
, NULL
, &attr_list
, NULL
, NULL
);
860 WARN("SecKeychainItemCopyAttributesAndData returned status %d\n", status
);
863 if (attr_list
->count
!= 1 || attr_list
->attr
[0].tag
!= kSecServiceItemAttr
)
868 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[0].data
, attr_list
->attr
[0].length
, NULL
, 0);
869 target_name
= heap_alloc((str_len
+ 1) * sizeof(WCHAR
));
870 MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[0].data
, attr_list
->attr
[0].length
, target_name
, str_len
);
872 target_name
[str_len
] = '\0';
873 if (strcmpiW(TargetName
, target_name
))
876 heap_free(target_name
);
879 heap_free(target_name
);
880 SecKeychainItemFreeAttributesAndData(attr_list
, NULL
);
881 SecKeychainItemDelete(item
);
885 return ERROR_SUCCESS
;
889 return ERROR_NOT_FOUND
;
893 /******************************************************************************
894 * convert_PCREDENTIALW_to_PCREDENTIALA [internal]
896 * convert a Credential struct from UNICODE to ANSI and return the needed size in Bytes
900 static INT
convert_PCREDENTIALW_to_PCREDENTIALA(const CREDENTIALW
*CredentialW
, PCREDENTIALA CredentialA
, DWORD len
)
904 INT needed
= sizeof(CREDENTIALA
);
908 if (CredentialW
->TargetName
)
909 needed
+= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->TargetName
, -1, NULL
, 0, NULL
, NULL
);
910 if (CredentialW
->Comment
)
911 needed
+= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->Comment
, -1, NULL
, 0, NULL
, NULL
);
912 needed
+= CredentialW
->CredentialBlobSize
;
913 if (CredentialW
->TargetAlias
)
914 needed
+= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->TargetAlias
, -1, NULL
, 0, NULL
, NULL
);
915 if (CredentialW
->UserName
)
916 needed
+= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->UserName
, -1, NULL
, 0, NULL
, NULL
);
922 buffer
= (char *)CredentialA
+ sizeof(CREDENTIALA
);
923 len
-= sizeof(CREDENTIALA
);
924 CredentialA
->Flags
= CredentialW
->Flags
;
925 CredentialA
->Type
= CredentialW
->Type
;
927 if (CredentialW
->TargetName
)
929 CredentialA
->TargetName
= buffer
;
930 string_len
= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->TargetName
, -1, buffer
, len
, NULL
, NULL
);
931 buffer
+= string_len
;
932 needed
+= string_len
;
936 CredentialA
->TargetName
= NULL
;
937 if (CredentialW
->Comment
)
939 CredentialA
->Comment
= buffer
;
940 string_len
= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->Comment
, -1, buffer
, len
, NULL
, NULL
);
941 buffer
+= string_len
;
942 needed
+= string_len
;
946 CredentialA
->Comment
= NULL
;
947 CredentialA
->LastWritten
= CredentialW
->LastWritten
;
948 CredentialA
->CredentialBlobSize
= CredentialW
->CredentialBlobSize
;
949 if (CredentialW
->CredentialBlobSize
&& (CredentialW
->CredentialBlobSize
<= len
))
951 CredentialA
->CredentialBlob
=(LPBYTE
)buffer
;
952 memcpy(CredentialA
->CredentialBlob
, CredentialW
->CredentialBlob
,
953 CredentialW
->CredentialBlobSize
);
954 buffer
+= CredentialW
->CredentialBlobSize
;
955 needed
+= CredentialW
->CredentialBlobSize
;
956 len
-= CredentialW
->CredentialBlobSize
;
959 CredentialA
->CredentialBlob
= NULL
;
960 CredentialA
->Persist
= CredentialW
->Persist
;
961 CredentialA
->AttributeCount
= 0;
962 CredentialA
->Attributes
= NULL
; /* FIXME */
963 if (CredentialW
->TargetAlias
)
965 CredentialA
->TargetAlias
= buffer
;
966 string_len
= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->TargetAlias
, -1, buffer
, len
, NULL
, NULL
);
967 buffer
+= string_len
;
968 needed
+= string_len
;
972 CredentialA
->TargetAlias
= NULL
;
973 if (CredentialW
->UserName
)
975 CredentialA
->UserName
= buffer
;
976 string_len
= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->UserName
, -1, buffer
, len
, NULL
, NULL
);
977 needed
+= string_len
;
980 CredentialA
->UserName
= NULL
;
985 /******************************************************************************
986 * convert_PCREDENTIALA_to_PCREDENTIALW [internal]
988 * convert a Credential struct from ANSI to UNICODE and return the needed size in Bytes
991 static INT
convert_PCREDENTIALA_to_PCREDENTIALW(const CREDENTIALA
*CredentialA
, PCREDENTIALW CredentialW
, INT len
)
995 INT needed
= sizeof(CREDENTIALW
);
999 if (CredentialA
->TargetName
)
1000 needed
+= sizeof(WCHAR
) * MultiByteToWideChar(CP_ACP
, 0, CredentialA
->TargetName
, -1, NULL
, 0);
1001 if (CredentialA
->Comment
)
1002 needed
+= sizeof(WCHAR
) * MultiByteToWideChar(CP_ACP
, 0, CredentialA
->Comment
, -1, NULL
, 0);
1003 needed
+= CredentialA
->CredentialBlobSize
;
1004 if (CredentialA
->TargetAlias
)
1005 needed
+= sizeof(WCHAR
) * MultiByteToWideChar(CP_ACP
, 0, CredentialA
->TargetAlias
, -1, NULL
, 0);
1006 if (CredentialA
->UserName
)
1007 needed
+= sizeof(WCHAR
) * MultiByteToWideChar(CP_ACP
, 0, CredentialA
->UserName
, -1, NULL
, 0);
1012 buffer
= (char *)CredentialW
+ sizeof(CREDENTIALW
);
1013 len
-= sizeof(CREDENTIALW
);
1014 CredentialW
->Flags
= CredentialA
->Flags
;
1015 CredentialW
->Type
= CredentialA
->Type
;
1016 if (CredentialA
->TargetName
)
1018 CredentialW
->TargetName
= (LPWSTR
)buffer
;
1019 string_len
= MultiByteToWideChar(CP_ACP
, 0, CredentialA
->TargetName
, -1, CredentialW
->TargetName
, len
/ sizeof(WCHAR
));
1020 buffer
+= sizeof(WCHAR
) * string_len
;
1021 needed
+= sizeof(WCHAR
) * string_len
;
1022 len
-= sizeof(WCHAR
) * string_len
;
1025 CredentialW
->TargetName
= NULL
;
1026 if (CredentialA
->Comment
)
1028 CredentialW
->Comment
= (LPWSTR
)buffer
;
1029 string_len
= MultiByteToWideChar(CP_ACP
, 0, CredentialA
->Comment
, -1, CredentialW
->Comment
, len
/ sizeof(WCHAR
));
1030 buffer
+= sizeof(WCHAR
) * string_len
;
1031 needed
+= sizeof(WCHAR
) * string_len
;
1032 len
-= sizeof(WCHAR
) * string_len
;
1035 CredentialW
->Comment
= NULL
;
1036 CredentialW
->LastWritten
= CredentialA
->LastWritten
;
1037 CredentialW
->CredentialBlobSize
= CredentialA
->CredentialBlobSize
;
1038 if (CredentialA
->CredentialBlobSize
)
1040 CredentialW
->CredentialBlob
=(LPBYTE
)buffer
;
1041 memcpy(CredentialW
->CredentialBlob
, CredentialA
->CredentialBlob
,
1042 CredentialA
->CredentialBlobSize
);
1043 buffer
+= CredentialA
->CredentialBlobSize
;
1044 needed
+= 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
, len
/ sizeof(WCHAR
));
1056 buffer
+= sizeof(WCHAR
) * string_len
;
1057 needed
+= sizeof(WCHAR
) * string_len
;
1058 len
-= sizeof(WCHAR
) * string_len
;
1061 CredentialW
->TargetAlias
= NULL
;
1062 if (CredentialA
->UserName
)
1064 CredentialW
->UserName
= (LPWSTR
)buffer
;
1065 string_len
= MultiByteToWideChar(CP_ACP
, 0, CredentialA
->UserName
, -1, CredentialW
->UserName
, len
/ sizeof(WCHAR
));
1066 needed
+= sizeof(WCHAR
) * string_len
;
1069 CredentialW
->UserName
= NULL
;
1074 /******************************************************************************
1075 * CredDeleteA [ADVAPI32.@]
1077 BOOL WINAPI
CredDeleteA(LPCSTR TargetName
, DWORD Type
, DWORD Flags
)
1083 TRACE("(%s, %d, 0x%x)\n", debugstr_a(TargetName
), Type
, Flags
);
1087 SetLastError(ERROR_INVALID_PARAMETER
);
1091 len
= MultiByteToWideChar(CP_ACP
, 0, TargetName
, -1, NULL
, 0);
1092 TargetNameW
= heap_alloc(len
* sizeof(WCHAR
));
1095 SetLastError(ERROR_OUTOFMEMORY
);
1098 MultiByteToWideChar(CP_ACP
, 0, TargetName
, -1, TargetNameW
, len
);
1100 ret
= CredDeleteW(TargetNameW
, Type
, Flags
);
1102 heap_free(TargetNameW
);
1107 /******************************************************************************
1108 * CredDeleteW [ADVAPI32.@]
1110 BOOL WINAPI
CredDeleteW(LPCWSTR TargetName
, DWORD Type
, DWORD Flags
)
1116 TRACE("(%s, %d, 0x%x)\n", debugstr_w(TargetName
), Type
, Flags
);
1120 SetLastError(ERROR_INVALID_PARAMETER
);
1124 if (Type
!= CRED_TYPE_GENERIC
&& Type
!= CRED_TYPE_DOMAIN_PASSWORD
)
1126 FIXME("unhandled type %d\n", Type
);
1127 SetLastError(ERROR_INVALID_PARAMETER
);
1133 FIXME("unhandled flags 0x%x\n", Flags
);
1134 SetLastError(ERROR_INVALID_FLAGS
);
1139 if (Type
== CRED_TYPE_DOMAIN_PASSWORD
)
1141 ret
= mac_delete_credential(TargetName
);
1142 if (ret
== ERROR_SUCCESS
)
1147 ret
= open_cred_mgr_key(&hkeyMgr
, TRUE
);
1148 if (ret
!= ERROR_SUCCESS
)
1150 WARN("couldn't open/create manager key, error %d\n", ret
);
1151 SetLastError(ERROR_NO_SUCH_LOGON_SESSION
);
1155 key_name
= get_key_name_for_target(TargetName
, Type
);
1156 ret
= RegDeleteKeyW(hkeyMgr
, key_name
);
1157 heap_free(key_name
);
1158 RegCloseKey(hkeyMgr
);
1159 if (ret
!= ERROR_SUCCESS
)
1161 SetLastError(ERROR_NOT_FOUND
);
1168 /******************************************************************************
1169 * CredEnumerateA [ADVAPI32.@]
1171 BOOL WINAPI
CredEnumerateA(LPCSTR Filter
, DWORD Flags
, DWORD
*Count
,
1172 PCREDENTIALA
**Credentials
)
1175 PCREDENTIALW
*CredentialsW
;
1181 TRACE("(%s, 0x%x, %p, %p)\n", debugstr_a(Filter
), Flags
, Count
, Credentials
);
1185 len
= MultiByteToWideChar(CP_ACP
, 0, Filter
, -1, NULL
, 0);
1186 FilterW
= heap_alloc(len
* sizeof(WCHAR
));
1189 SetLastError(ERROR_OUTOFMEMORY
);
1192 MultiByteToWideChar(CP_ACP
, 0, Filter
, -1, FilterW
, len
);
1197 if (!CredEnumerateW(FilterW
, Flags
, Count
, &CredentialsW
))
1204 len
= *Count
* sizeof(PCREDENTIALA
);
1205 for (i
= 0; i
< *Count
; i
++)
1206 len
+= convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW
[i
], NULL
, 0);
1208 *Credentials
= heap_alloc(len
);
1211 CredFree(CredentialsW
);
1212 SetLastError(ERROR_OUTOFMEMORY
);
1216 buffer
= (char *)&(*Credentials
)[*Count
];
1217 len
-= *Count
* sizeof(PCREDENTIALA
);
1218 for (i
= 0; i
< *Count
; i
++)
1220 (*Credentials
)[i
] = (PCREDENTIALA
)buffer
;
1221 needed
= convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW
[i
], (*Credentials
)[i
], len
);
1226 CredFree(CredentialsW
);
1231 /******************************************************************************
1232 * CredEnumerateW [ADVAPI32.@]
1234 BOOL WINAPI
CredEnumerateW(LPCWSTR Filter
, DWORD Flags
, DWORD
*Count
,
1235 PCREDENTIALW
**Credentials
)
1240 DWORD target_name_len
;
1243 BYTE key_data
[KEY_SIZE
];
1245 TRACE("(%s, 0x%x, %p, %p)\n", debugstr_w(Filter
), Flags
, Count
, Credentials
);
1249 SetLastError(ERROR_INVALID_FLAGS
);
1253 ret
= open_cred_mgr_key(&hkeyMgr
, FALSE
);
1254 if (ret
!= ERROR_SUCCESS
)
1256 WARN("couldn't open/create manager key, error %d\n", ret
);
1257 SetLastError(ERROR_NO_SUCH_LOGON_SESSION
);
1261 ret
= get_cred_mgr_encryption_key(hkeyMgr
, key_data
);
1262 if (ret
!= ERROR_SUCCESS
)
1264 RegCloseKey(hkeyMgr
);
1269 ret
= RegQueryInfoKeyW(hkeyMgr
, NULL
, NULL
, NULL
, NULL
, &target_name_len
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1270 if (ret
!= ERROR_SUCCESS
)
1272 RegCloseKey(hkeyMgr
);
1277 target_name
= heap_alloc((target_name_len
+1)*sizeof(WCHAR
));
1280 RegCloseKey(hkeyMgr
);
1281 SetLastError(ERROR_OUTOFMEMORY
);
1287 ret
= registry_enumerate_credentials(hkeyMgr
, Filter
, target_name
, target_name_len
,
1288 key_data
, NULL
, NULL
, &len
, Count
);
1290 if (ret
== ERROR_SUCCESS
)
1291 ret
= mac_enumerate_credentials(Filter
, NULL
, NULL
, &len
, Count
);
1293 if (ret
== ERROR_SUCCESS
&& *Count
== 0)
1294 ret
= ERROR_NOT_FOUND
;
1295 if (ret
!= ERROR_SUCCESS
)
1297 heap_free(target_name
);
1298 RegCloseKey(hkeyMgr
);
1302 len
+= *Count
* sizeof(PCREDENTIALW
);
1304 if (ret
== ERROR_SUCCESS
)
1306 buffer
= heap_alloc(len
);
1307 *Credentials
= (PCREDENTIALW
*)buffer
;
1310 buffer
+= *Count
* sizeof(PCREDENTIALW
);
1312 ret
= registry_enumerate_credentials(hkeyMgr
, Filter
, target_name
,
1313 target_name_len
, key_data
,
1314 *Credentials
, &buffer
, &len
,
1317 if (ret
== ERROR_SUCCESS
)
1318 ret
= mac_enumerate_credentials(Filter
, *Credentials
,
1319 buffer
, &len
, Count
);
1323 ret
= ERROR_OUTOFMEMORY
;
1326 heap_free(target_name
);
1327 RegCloseKey(hkeyMgr
);
1329 if (ret
!= ERROR_SUCCESS
)
1337 /******************************************************************************
1338 * CredFree [ADVAPI32.@]
1340 VOID WINAPI
CredFree(PVOID Buffer
)
1345 /******************************************************************************
1346 * CredReadA [ADVAPI32.@]
1348 BOOL WINAPI
CredReadA(LPCSTR TargetName
, DWORD Type
, DWORD Flags
, PCREDENTIALA
*Credential
)
1351 PCREDENTIALW CredentialW
;
1354 TRACE("(%s, %d, 0x%x, %p)\n", debugstr_a(TargetName
), Type
, Flags
, Credential
);
1358 SetLastError(ERROR_INVALID_PARAMETER
);
1362 len
= MultiByteToWideChar(CP_ACP
, 0, TargetName
, -1, NULL
, 0);
1363 TargetNameW
= heap_alloc(len
* sizeof(WCHAR
));
1366 SetLastError(ERROR_OUTOFMEMORY
);
1369 MultiByteToWideChar(CP_ACP
, 0, TargetName
, -1, TargetNameW
, len
);
1371 if (!CredReadW(TargetNameW
, Type
, Flags
, &CredentialW
))
1373 heap_free(TargetNameW
);
1376 heap_free(TargetNameW
);
1378 len
= convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW
, NULL
, 0);
1379 *Credential
= heap_alloc(len
);
1382 SetLastError(ERROR_OUTOFMEMORY
);
1385 convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW
, *Credential
, len
);
1387 CredFree(CredentialW
);
1392 /******************************************************************************
1393 * CredReadW [ADVAPI32.@]
1395 BOOL WINAPI
CredReadW(LPCWSTR TargetName
, DWORD Type
, DWORD Flags
, PCREDENTIALW
*Credential
)
1402 BYTE key_data
[KEY_SIZE
];
1404 TRACE("(%s, %d, 0x%x, %p)\n", debugstr_w(TargetName
), Type
, Flags
, Credential
);
1408 SetLastError(ERROR_INVALID_PARAMETER
);
1412 if (Type
!= CRED_TYPE_GENERIC
&& Type
!= CRED_TYPE_DOMAIN_PASSWORD
)
1414 FIXME("unhandled type %d\n", Type
);
1415 SetLastError(ERROR_INVALID_PARAMETER
);
1421 FIXME("unhandled flags 0x%x\n", Flags
);
1422 SetLastError(ERROR_INVALID_FLAGS
);
1427 if (Type
== CRED_TYPE_DOMAIN_PASSWORD
)
1430 SecKeychainSearchRef search
;
1431 status
= SecKeychainSearchCreateFromAttributes(NULL
, kSecGenericPasswordItemClass
, NULL
, &search
);
1432 if (status
== noErr
)
1434 SecKeychainItemRef item
;
1435 while (SecKeychainSearchCopyNext(search
, &item
) == noErr
)
1437 SecKeychainAttributeInfo info
;
1438 SecKeychainAttributeList
*attr_list
;
1439 UInt32 info_tags
[] = { kSecServiceItemAttr
};
1442 info
.count
= sizeof(info_tags
)/sizeof(info_tags
[0]);
1443 info
.tag
= info_tags
;
1445 status
= SecKeychainItemCopyAttributesAndData(item
, &info
, NULL
, &attr_list
, NULL
, NULL
);
1446 len
= sizeof(**Credential
);
1447 if (status
!= noErr
)
1449 WARN("SecKeychainItemCopyAttributesAndData returned status %d\n", status
);
1452 if (attr_list
->count
!= 1 || attr_list
->attr
[0].tag
!= kSecServiceItemAttr
)
1457 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[0].data
, attr_list
->attr
[0].length
, NULL
, 0);
1458 target_name
= heap_alloc((str_len
+ 1) * sizeof(WCHAR
));
1459 MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[0].data
, attr_list
->attr
[0].length
, target_name
, str_len
);
1461 target_name
[str_len
] = '\0';
1462 if (strcmpiW(TargetName
, target_name
))
1465 heap_free(target_name
);
1468 heap_free(target_name
);
1469 SecKeychainItemFreeAttributesAndData(attr_list
, NULL
);
1470 ret
= mac_read_credential_from_item(item
, TRUE
, NULL
, NULL
, &len
);
1471 if (ret
== ERROR_SUCCESS
)
1473 *Credential
= heap_alloc(len
);
1476 len
= sizeof(**Credential
);
1477 ret
= mac_read_credential_from_item(item
, TRUE
, *Credential
,
1478 (char *)(*Credential
+ 1), &len
);
1481 ret
= ERROR_OUTOFMEMORY
;
1484 if (ret
!= ERROR_SUCCESS
)
1498 ret
= open_cred_mgr_key(&hkeyMgr
, FALSE
);
1499 if (ret
!= ERROR_SUCCESS
)
1501 WARN("couldn't open/create manager key, error %d\n", ret
);
1502 SetLastError(ERROR_NO_SUCH_LOGON_SESSION
);
1506 ret
= get_cred_mgr_encryption_key(hkeyMgr
, key_data
);
1507 if (ret
!= ERROR_SUCCESS
)
1509 RegCloseKey(hkeyMgr
);
1514 key_name
= get_key_name_for_target(TargetName
, Type
);
1515 ret
= RegOpenKeyExW(hkeyMgr
, key_name
, 0, KEY_QUERY_VALUE
, &hkeyCred
);
1516 heap_free(key_name
);
1517 if (ret
!= ERROR_SUCCESS
)
1519 TRACE("credentials for target name %s not found\n", debugstr_w(TargetName
));
1520 SetLastError(ERROR_NOT_FOUND
);
1524 len
= sizeof(**Credential
);
1525 ret
= registry_read_credential(hkeyCred
, NULL
, key_data
, NULL
, &len
);
1526 if (ret
== ERROR_SUCCESS
)
1528 *Credential
= heap_alloc(len
);
1531 len
= sizeof(**Credential
);
1532 ret
= registry_read_credential(hkeyCred
, *Credential
, key_data
,
1533 (char *)(*Credential
+ 1), &len
);
1536 ret
= ERROR_OUTOFMEMORY
;
1539 RegCloseKey(hkeyCred
);
1540 RegCloseKey(hkeyMgr
);
1542 if (ret
!= ERROR_SUCCESS
)
1550 /******************************************************************************
1551 * CredReadDomainCredentialsA [ADVAPI32.@]
1553 BOOL WINAPI
CredReadDomainCredentialsA(PCREDENTIAL_TARGET_INFORMATIONA TargetInformation
,
1554 DWORD Flags
, DWORD
*Size
, PCREDENTIALA
**Credentials
)
1556 PCREDENTIAL_TARGET_INFORMATIONW TargetInformationW
;
1559 WCHAR
*buffer
, *end
;
1561 PCREDENTIALW
* CredentialsW
;
1563 TRACE("(%p, 0x%x, %p, %p)\n", TargetInformation
, Flags
, Size
, Credentials
);
1565 /* follow Windows behavior - do not test for NULL, initialize early */
1567 *Credentials
= NULL
;
1569 if (!TargetInformation
)
1571 SetLastError(ERROR_INVALID_PARAMETER
);
1575 len
= sizeof(*TargetInformationW
);
1576 if (TargetInformation
->TargetName
)
1577 len
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->TargetName
, -1, NULL
, 0) * sizeof(WCHAR
);
1578 if (TargetInformation
->NetbiosServerName
)
1579 len
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->NetbiosServerName
, -1, NULL
, 0) * sizeof(WCHAR
);
1580 if (TargetInformation
->DnsServerName
)
1581 len
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->DnsServerName
, -1, NULL
, 0) * sizeof(WCHAR
);
1582 if (TargetInformation
->NetbiosDomainName
)
1583 len
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->NetbiosDomainName
, -1, NULL
, 0) * sizeof(WCHAR
);
1584 if (TargetInformation
->DnsDomainName
)
1585 len
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->DnsDomainName
, -1, NULL
, 0) * sizeof(WCHAR
);
1586 if (TargetInformation
->DnsTreeName
)
1587 len
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->DnsTreeName
, -1, NULL
, 0) * sizeof(WCHAR
);
1588 if (TargetInformation
->PackageName
)
1589 len
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->PackageName
, -1, NULL
, 0) * sizeof(WCHAR
);
1591 TargetInformationW
= heap_alloc(len
);
1592 if (!TargetInformationW
)
1594 SetLastError(ERROR_OUTOFMEMORY
);
1597 buffer
= (WCHAR
*)(TargetInformationW
+ 1);
1598 end
= (WCHAR
*)((char *)TargetInformationW
+ len
);
1600 if (TargetInformation
->TargetName
)
1602 TargetInformationW
->TargetName
= buffer
;
1603 buffer
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->TargetName
, -1,
1604 TargetInformationW
->TargetName
, end
- buffer
);
1606 TargetInformationW
->TargetName
= NULL
;
1608 if (TargetInformation
->NetbiosServerName
)
1610 TargetInformationW
->NetbiosServerName
= buffer
;
1611 buffer
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->NetbiosServerName
, -1,
1612 TargetInformationW
->NetbiosServerName
, end
- buffer
);
1614 TargetInformationW
->NetbiosServerName
= NULL
;
1616 if (TargetInformation
->DnsServerName
)
1618 TargetInformationW
->DnsServerName
= buffer
;
1619 buffer
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->DnsServerName
, -1,
1620 TargetInformationW
->DnsServerName
, end
- buffer
);
1622 TargetInformationW
->DnsServerName
= NULL
;
1624 if (TargetInformation
->NetbiosDomainName
)
1626 TargetInformationW
->NetbiosDomainName
= buffer
;
1627 buffer
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->NetbiosDomainName
, -1,
1628 TargetInformationW
->NetbiosDomainName
, end
- buffer
);
1630 TargetInformationW
->NetbiosDomainName
= NULL
;
1632 if (TargetInformation
->DnsDomainName
)
1634 TargetInformationW
->DnsDomainName
= buffer
;
1635 buffer
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->DnsDomainName
, -1,
1636 TargetInformationW
->DnsDomainName
, end
- buffer
);
1638 TargetInformationW
->DnsDomainName
= NULL
;
1640 if (TargetInformation
->DnsTreeName
)
1642 TargetInformationW
->DnsTreeName
= buffer
;
1643 buffer
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->DnsTreeName
, -1,
1644 TargetInformationW
->DnsTreeName
, end
- buffer
);
1646 TargetInformationW
->DnsTreeName
= NULL
;
1648 if (TargetInformation
->PackageName
)
1650 TargetInformationW
->PackageName
= buffer
;
1651 MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->PackageName
, -1,
1652 TargetInformationW
->PackageName
, end
- buffer
);
1654 TargetInformationW
->PackageName
= NULL
;
1656 TargetInformationW
->Flags
= TargetInformation
->Flags
;
1657 TargetInformationW
->CredTypeCount
= TargetInformation
->CredTypeCount
;
1658 TargetInformationW
->CredTypes
= TargetInformation
->CredTypes
;
1660 ret
= CredReadDomainCredentialsW(TargetInformationW
, Flags
, Size
, &CredentialsW
);
1662 heap_free(TargetInformationW
);
1669 len
= *Size
* sizeof(PCREDENTIALA
);
1670 for (i
= 0; i
< *Size
; i
++)
1671 len
+= convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW
[i
], NULL
, 0);
1673 *Credentials
= heap_alloc(len
);
1676 CredFree(CredentialsW
);
1677 SetLastError(ERROR_OUTOFMEMORY
);
1681 buf
= (char *)&(*Credentials
)[*Size
];
1682 len
-= *Size
* sizeof(PCREDENTIALA
);
1683 for (i
= 0; i
< *Size
; i
++)
1685 (*Credentials
)[i
] = (PCREDENTIALA
)buf
;
1686 needed
= convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW
[i
], (*Credentials
)[i
], len
);
1691 CredFree(CredentialsW
);
1696 /******************************************************************************
1697 * CredReadDomainCredentialsW [ADVAPI32.@]
1699 BOOL WINAPI
CredReadDomainCredentialsW(PCREDENTIAL_TARGET_INFORMATIONW TargetInformation
, DWORD Flags
,
1700 DWORD
*Size
, PCREDENTIALW
**Credentials
)
1702 FIXME("(%p, 0x%x, %p, %p) stub\n", TargetInformation
, Flags
, Size
, Credentials
);
1704 /* follow Windows behavior - do not test for NULL, initialize early */
1706 *Credentials
= NULL
;
1707 if (!TargetInformation
)
1709 SetLastError(ERROR_INVALID_PARAMETER
);
1713 SetLastError(ERROR_NOT_FOUND
);
1717 /******************************************************************************
1718 * CredWriteA [ADVAPI32.@]
1720 BOOL WINAPI
CredWriteA(PCREDENTIALA Credential
, DWORD Flags
)
1724 PCREDENTIALW CredentialW
;
1726 TRACE("(%p, 0x%x)\n", Credential
, Flags
);
1728 if (!Credential
|| !Credential
->TargetName
)
1730 SetLastError(ERROR_INVALID_PARAMETER
);
1734 len
= convert_PCREDENTIALA_to_PCREDENTIALW(Credential
, NULL
, 0);
1735 CredentialW
= heap_alloc(len
);
1738 SetLastError(ERROR_OUTOFMEMORY
);
1742 convert_PCREDENTIALA_to_PCREDENTIALW(Credential
, CredentialW
, len
);
1744 ret
= CredWriteW(CredentialW
, Flags
);
1746 heap_free(CredentialW
);
1751 /******************************************************************************
1752 * CredWriteW [ADVAPI32.@]
1754 BOOL WINAPI
CredWriteW(PCREDENTIALW Credential
, DWORD Flags
)
1760 BYTE key_data
[KEY_SIZE
];
1762 TRACE("(%p, 0x%x)\n", Credential
, Flags
);
1764 if (!Credential
|| !Credential
->TargetName
)
1766 SetLastError(ERROR_INVALID_PARAMETER
);
1770 if (Flags
& ~CRED_PRESERVE_CREDENTIAL_BLOB
)
1772 FIXME("unhandled flags 0x%x\n", Flags
);
1773 SetLastError(ERROR_INVALID_FLAGS
);
1777 if (Credential
->Type
!= CRED_TYPE_GENERIC
&& Credential
->Type
!= CRED_TYPE_DOMAIN_PASSWORD
)
1779 FIXME("unhandled type %d\n", Credential
->Type
);
1780 SetLastError(ERROR_INVALID_PARAMETER
);
1784 TRACE("Credential->Flags = 0x%08x\n", Credential
->Flags
);
1785 TRACE("Credential->Type = %u\n", Credential
->Type
);
1786 TRACE("Credential->TargetName = %s\n", debugstr_w(Credential
->TargetName
));
1787 TRACE("Credential->Comment = %s\n", debugstr_w(Credential
->Comment
));
1788 TRACE("Credential->Persist = %u\n", Credential
->Persist
);
1789 TRACE("Credential->TargetAlias = %s\n", debugstr_w(Credential
->TargetAlias
));
1790 TRACE("Credential->UserName = %s\n", debugstr_w(Credential
->UserName
));
1792 if (Credential
->Type
== CRED_TYPE_DOMAIN_PASSWORD
)
1794 if (!Credential
->UserName
||
1795 (Credential
->Persist
== CRED_PERSIST_ENTERPRISE
&&
1796 (!strchrW(Credential
->UserName
, '\\') && !strchrW(Credential
->UserName
, '@'))))
1798 ERR("bad username %s\n", debugstr_w(Credential
->UserName
));
1799 SetLastError(ERROR_BAD_USERNAME
);
1805 if (!Credential
->AttributeCount
&&
1806 Credential
->Type
== CRED_TYPE_DOMAIN_PASSWORD
&&
1807 (Credential
->Persist
== CRED_PERSIST_LOCAL_MACHINE
|| Credential
->Persist
== CRED_PERSIST_ENTERPRISE
))
1809 ret
= mac_write_credential(Credential
, Flags
& CRED_PRESERVE_CREDENTIAL_BLOB
);
1810 if (ret
!= ERROR_SUCCESS
)
1819 ret
= open_cred_mgr_key(&hkeyMgr
, FALSE
);
1820 if (ret
!= ERROR_SUCCESS
)
1822 WARN("couldn't open/create manager key, error %d\n", ret
);
1823 SetLastError(ERROR_NO_SUCH_LOGON_SESSION
);
1827 ret
= get_cred_mgr_encryption_key(hkeyMgr
, key_data
);
1828 if (ret
!= ERROR_SUCCESS
)
1830 RegCloseKey(hkeyMgr
);
1835 key_name
= get_key_name_for_target(Credential
->TargetName
, Credential
->Type
);
1836 ret
= RegCreateKeyExW(hkeyMgr
, key_name
, 0, NULL
,
1837 Credential
->Persist
== CRED_PERSIST_SESSION
? REG_OPTION_VOLATILE
: REG_OPTION_NON_VOLATILE
,
1838 KEY_READ
|KEY_WRITE
, NULL
, &hkeyCred
, NULL
);
1839 heap_free(key_name
);
1840 if (ret
!= ERROR_SUCCESS
)
1842 TRACE("credentials for target name %s not found\n",
1843 debugstr_w(Credential
->TargetName
));
1844 SetLastError(ERROR_NOT_FOUND
);
1848 ret
= registry_write_credential(hkeyCred
, Credential
, key_data
,
1849 Flags
& CRED_PRESERVE_CREDENTIAL_BLOB
);
1851 RegCloseKey(hkeyCred
);
1852 RegCloseKey(hkeyMgr
);
1854 if (ret
!= ERROR_SUCCESS
)
1862 /******************************************************************************
1863 * CredGetSessionTypes [ADVAPI32.@]
1865 WINADVAPI BOOL WINAPI
CredGetSessionTypes(DWORD persistCount
, LPDWORD persists
)
1867 TRACE("(%u, %p)\n", persistCount
, persists
);
1869 memset(persists
, CRED_PERSIST_NONE
, persistCount
*sizeof(*persists
));
1870 if (CRED_TYPE_GENERIC
< persistCount
)
1872 persists
[CRED_TYPE_GENERIC
] = CRED_PERSIST_ENTERPRISE
;
1874 if (CRED_TYPE_DOMAIN_PASSWORD
< persistCount
)
1876 persists
[CRED_TYPE_DOMAIN_PASSWORD
] = CRED_PERSIST_ENTERPRISE
;
1882 /******************************************************************************
1883 * CredMarshalCredentialA [ADVAPI32.@]
1885 BOOL WINAPI
CredMarshalCredentialA( CRED_MARSHAL_TYPE type
, PVOID cred
, LPSTR
*out
)
1890 TRACE("%u, %p, %p\n", type
, cred
, out
);
1892 if ((ret
= CredMarshalCredentialW( type
, cred
, &outW
)))
1894 int len
= WideCharToMultiByte( CP_ACP
, 0, outW
, -1, NULL
, 0, NULL
, NULL
);
1895 if (!(*out
= heap_alloc( len
)))
1900 WideCharToMultiByte( CP_ACP
, 0, outW
, -1, *out
, len
, NULL
, NULL
);
1906 static UINT
cred_encode( const char *bin
, unsigned int len
, WCHAR
*cred
)
1908 static const char enc
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#-";
1913 cred
[n
++] = enc
[bin
[0] & 0x3f];
1914 x
= (bin
[0] & 0xc0) >> 6;
1920 cred
[n
++] = enc
[((bin
[1] & 0xf) << 2) | x
];
1921 x
= (bin
[1] & 0xf0) >> 4;
1927 cred
[n
++] = enc
[((bin
[2] & 0x3) << 4) | x
];
1928 cred
[n
++] = enc
[(bin
[2] & 0xfc) >> 2];
1935 /******************************************************************************
1936 * CredMarshalCredentialW [ADVAPI32.@]
1938 BOOL WINAPI
CredMarshalCredentialW( CRED_MARSHAL_TYPE type
, PVOID cred
, LPWSTR
*out
)
1940 CERT_CREDENTIAL_INFO
*cert
= cred
;
1941 USERNAME_TARGET_CREDENTIAL_INFO
*target
= cred
;
1945 TRACE("%u, %p, %p\n", type
, cred
, out
);
1947 if (!cred
|| (type
== CertCredential
&& cert
->cbSize
< sizeof(*cert
)) ||
1948 (type
!= CertCredential
&& type
!= UsernameTargetCredential
&& type
!= BinaryBlobCredential
) ||
1949 (type
== UsernameTargetCredential
&& (!target
->UserName
|| !target
->UserName
[0])))
1951 SetLastError( ERROR_INVALID_PARAMETER
);
1956 case CertCredential
:
1958 size
= (sizeof(cert
->rgbHashOfCert
) + 2) * 4 / 3;
1959 if (!(p
= heap_alloc( (size
+ 4) * sizeof(WCHAR
) ))) return FALSE
;
1963 len
= cred_encode( (const char *)cert
->rgbHashOfCert
, sizeof(cert
->rgbHashOfCert
), p
+ 3 );
1967 case UsernameTargetCredential
:
1969 len
= strlenW( target
->UserName
);
1970 size
= (sizeof(DWORD
) + len
* sizeof(WCHAR
) + 2) * 4 / 3;
1971 if (!(p
= heap_alloc( (size
+ 4) * sizeof(WCHAR
) ))) return FALSE
;
1975 size
= len
* sizeof(WCHAR
);
1976 len
= cred_encode( (const char *)&size
, sizeof(DWORD
), p
+ 3 );
1977 len
+= cred_encode( (const char *)target
->UserName
, size
, p
+ 3 + len
);
1981 case BinaryBlobCredential
:
1982 FIXME("BinaryBlobCredential not implemented\n");
1991 /******************************************************************************
1992 * CredUnmarshalCredentialA [ADVAPI32.@]
1994 BOOL WINAPI
CredUnmarshalCredentialA( LPCSTR cred
, PCRED_MARSHAL_TYPE type
, PVOID
*out
)
1997 WCHAR
*credW
= NULL
;
1999 TRACE("%s, %p, %p\n", debugstr_a(cred
), type
, out
);
2003 int len
= MultiByteToWideChar( CP_ACP
, 0, cred
, -1, NULL
, 0 );
2004 if (!(credW
= heap_alloc( len
* sizeof(WCHAR
) ))) return FALSE
;
2005 MultiByteToWideChar( CP_ACP
, 0, cred
, -1, credW
, len
);
2007 ret
= CredUnmarshalCredentialW( credW
, type
, out
);
2012 static inline char char_decode( WCHAR c
)
2014 if (c
>= 'A' && c
<= 'Z') return c
- 'A';
2015 if (c
>= 'a' && c
<= 'z') return c
- 'a' + 26;
2016 if (c
>= '0' && c
<= '9') return c
- '0' + 52;
2017 if (c
== '#') return 62;
2018 if (c
== '-') return 63;
2022 static BOOL
cred_decode( const WCHAR
*cred
, unsigned int len
, char *buf
)
2025 char c0
, c1
, c2
, c3
;
2026 const WCHAR
*p
= cred
;
2030 if ((c0
= char_decode( p
[0] )) > 63) return FALSE
;
2031 if ((c1
= char_decode( p
[1] )) > 63) return FALSE
;
2032 if ((c2
= char_decode( p
[2] )) > 63) return FALSE
;
2033 if ((c3
= char_decode( p
[3] )) > 63) return FALSE
;
2035 buf
[i
+ 0] = (c1
<< 6) | c0
;
2036 buf
[i
+ 1] = (c2
<< 4) | (c1
>> 2);
2037 buf
[i
+ 2] = (c3
<< 2) | (c2
>> 4);
2044 if ((c0
= char_decode( p
[0] )) > 63) return FALSE
;
2045 if ((c1
= char_decode( p
[1] )) > 63) return FALSE
;
2046 if ((c2
= char_decode( p
[2] )) > 63) return FALSE
;
2048 buf
[i
+ 0] = (c1
<< 6) | c0
;
2049 buf
[i
+ 1] = (c2
<< 4) | (c1
>> 2);
2053 if ((c0
= char_decode( p
[0] )) > 63) return FALSE
;
2054 if ((c1
= char_decode( p
[1] )) > 63) return FALSE
;
2056 buf
[i
+ 0] = (c1
<< 6) | c0
;
2065 /******************************************************************************
2066 * CredUnmarshalCredentialW [ADVAPI32.@]
2068 BOOL WINAPI
CredUnmarshalCredentialW( LPCWSTR cred
, PCRED_MARSHAL_TYPE type
, PVOID
*out
)
2070 unsigned int len
, buflen
;
2072 TRACE("%s, %p, %p\n", debugstr_w(cred
), type
, out
);
2074 if (!cred
|| cred
[0] != '@' || cred
[1] != '@' ||
2075 char_decode( cred
[2] ) > 63)
2077 SetLastError( ERROR_INVALID_PARAMETER
);
2080 len
= strlenW( cred
+ 3 );
2081 *type
= char_decode( cred
[2] );
2084 case CertCredential
:
2086 char hash
[CERT_HASH_LENGTH
];
2087 CERT_CREDENTIAL_INFO
*cert
;
2089 if (len
!= 27 || !cred_decode( cred
+ 3, len
, hash
))
2091 SetLastError( ERROR_INVALID_PARAMETER
);
2094 if (!(cert
= heap_alloc( sizeof(*cert
) ))) return FALSE
;
2095 memcpy( cert
->rgbHashOfCert
, hash
, sizeof(cert
->rgbHashOfCert
) );
2096 cert
->cbSize
= sizeof(*cert
);
2100 case UsernameTargetCredential
:
2102 USERNAME_TARGET_CREDENTIAL_INFO
*target
;
2105 if (len
< 9 || !cred_decode( cred
+ 3, 6, (char *)&size
) ||
2106 size
% sizeof(WCHAR
) || len
- 6 != (size
* 4 + 2) / 3)
2108 SetLastError( ERROR_INVALID_PARAMETER
);
2111 buflen
= sizeof(*target
) + size
+ sizeof(WCHAR
);
2112 if (!(target
= heap_alloc( buflen
))) return FALSE
;
2113 if (!cred_decode( cred
+ 9, len
- 6, (char *)(target
+ 1) ))
2115 heap_free( target
);
2118 target
->UserName
= (WCHAR
*)(target
+ 1);
2119 target
->UserName
[size
/ sizeof(WCHAR
)] = 0;
2123 case BinaryBlobCredential
:
2124 FIXME("BinaryBlobCredential not implemented\n");
2127 WARN("unhandled type %u\n", *type
);
2128 SetLastError( ERROR_INVALID_PARAMETER
);
2134 /******************************************************************************
2135 * CredIsMarshaledCredentialW [ADVAPI32.@]
2137 * Check, if the name parameter is a marshaled credential, hash or binary blob
2140 * name the name to check
2143 * TRUE: the name parameter is a marshaled credential, hash or binary blob
2144 * FALSE: the name is a plain username
2146 BOOL WINAPI
CredIsMarshaledCredentialW(LPCWSTR name
)
2148 TRACE("(%s)\n", debugstr_w(name
));
2150 if (name
&& name
[0] == '@' && name
[1] == '@' && name
[2] > 'A' && name
[3])
2152 char hash
[CERT_HASH_LENGTH
];
2153 int len
= strlenW(name
+ 3 );
2156 if ((name
[2] - 'A') == CertCredential
&& (len
== 27) && cred_decode(name
+ 3, len
, hash
))
2159 if (((name
[2] - 'A') == UsernameTargetCredential
) &&
2160 (len
>= 9) && cred_decode(name
+ 3, 6, (char *)&size
) && size
)
2163 if ((name
[2] - 'A') == BinaryBlobCredential
)
2164 FIXME("BinaryBlobCredential not checked\n");
2166 if ((name
[2] - 'A') > BinaryBlobCredential
)
2167 TRACE("unknown type: %d\n", (name
[2] - 'A'));
2170 SetLastError(ERROR_INVALID_PARAMETER
);
2174 /******************************************************************************
2175 * CredIsMarshaledCredentialA [ADVAPI32.@]
2177 * See CredIsMarshaledCredentialW
2180 BOOL WINAPI
CredIsMarshaledCredentialA(LPCSTR name
)
2182 LPWSTR nameW
= NULL
;
2186 TRACE("(%s)\n", debugstr_a(name
));
2190 len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, NULL
, 0);
2191 nameW
= heap_alloc(len
* sizeof(WCHAR
));
2192 MultiByteToWideChar(CP_ACP
, 0, name
, -1, nameW
, len
);
2195 res
= CredIsMarshaledCredentialW(nameW
);