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
25 WINE_DEFAULT_DEBUG_CHANNEL(cred
);
27 /* the size of the ARC4 key used to encrypt the password data */
30 static const WCHAR wszCredentialManagerKey
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
31 'C','r','e','d','e','n','t','i','a','l',' ','M','a','n','a','g','e','r',0};
32 static const WCHAR wszEncryptionKeyValue
[] = {'E','n','c','r','y','p','t','i','o','n','K','e','y',0};
34 static const WCHAR wszFlagsValue
[] = {'F','l','a','g','s',0};
35 static const WCHAR wszTypeValue
[] = {'T','y','p','e',0};
36 static const WCHAR wszCommentValue
[] = {'C','o','m','m','e','n','t',0};
37 static const WCHAR wszLastWrittenValue
[] = {'L','a','s','t','W','r','i','t','t','e','n',0};
38 static const WCHAR wszPersistValue
[] = {'P','e','r','s','i','s','t',0};
39 static const WCHAR wszTargetAliasValue
[] = {'T','a','r','g','e','t','A','l','i','a','s',0};
40 static const WCHAR wszUserNameValue
[] = {'U','s','e','r','N','a','m','e',0};
41 static const WCHAR wszPasswordValue
[] = {'P','a','s','s','w','o','r','d',0};
43 static DWORD
read_credential_blob(HKEY hkey
, const BYTE key_data
[KEY_SIZE
],
44 LPBYTE credential_blob
,
45 DWORD
*credential_blob_size
)
50 *credential_blob_size
= 0;
51 ret
= RegQueryValueExW(hkey
, wszPasswordValue
, 0, &type
, NULL
, credential_blob_size
);
52 if (ret
!= ERROR_SUCCESS
)
54 else if (type
!= REG_BINARY
)
55 return ERROR_REGISTRY_CORRUPT
;
61 ret
= RegQueryValueExW(hkey
, wszPasswordValue
, 0, &type
, credential_blob
,
62 credential_blob_size
);
63 if (ret
!= ERROR_SUCCESS
)
65 else if (type
!= REG_BINARY
)
66 return ERROR_REGISTRY_CORRUPT
;
68 key
.Length
= key
.MaximumLength
= KEY_SIZE
;
69 key
.Buffer
= (unsigned char *)key_data
;
71 data
.Length
= data
.MaximumLength
= *credential_blob_size
;
72 data
.Buffer
= credential_blob
;
73 SystemFunction032(&data
, &key
);
78 static DWORD
registry_read_credential(HKEY hkey
, PCREDENTIALW credential
,
79 const BYTE key_data
[KEY_SIZE
],
80 char *buffer
, DWORD
*len
)
86 ret
= RegQueryValueExW(hkey
, NULL
, 0, &type
, NULL
, &count
);
87 if (ret
!= ERROR_SUCCESS
)
89 else if (type
!= REG_SZ
)
90 return ERROR_REGISTRY_CORRUPT
;
94 credential
->TargetName
= (LPWSTR
)buffer
;
95 ret
= RegQueryValueExW(hkey
, NULL
, 0, &type
, (LPVOID
)credential
->TargetName
,
97 if (ret
!= ERROR_SUCCESS
)
99 else if (type
!= REG_SZ
)
100 return ERROR_REGISTRY_CORRUPT
;
104 ret
= RegQueryValueExW(hkey
, wszCommentValue
, 0, &type
, NULL
, &count
);
105 if (ret
!= ERROR_FILE_NOT_FOUND
)
107 if (ret
!= ERROR_SUCCESS
)
109 else if (type
!= REG_SZ
)
110 return ERROR_REGISTRY_CORRUPT
;
115 credential
->Comment
= (LPWSTR
)buffer
;
116 ret
= RegQueryValueExW(hkey
, wszCommentValue
, 0, &type
, (LPVOID
)credential
->Comment
,
118 if (ret
== ERROR_FILE_NOT_FOUND
)
119 credential
->Comment
= NULL
;
120 else if (ret
!= ERROR_SUCCESS
)
122 else if (type
!= REG_SZ
)
123 return ERROR_REGISTRY_CORRUPT
;
128 ret
= RegQueryValueExW(hkey
, wszTargetAliasValue
, 0, &type
, NULL
, &count
);
129 if (ret
!= ERROR_FILE_NOT_FOUND
)
131 if (ret
!= ERROR_SUCCESS
)
133 else if (type
!= REG_SZ
)
134 return ERROR_REGISTRY_CORRUPT
;
139 credential
->TargetAlias
= (LPWSTR
)buffer
;
140 ret
= RegQueryValueExW(hkey
, wszTargetAliasValue
, 0, &type
, (LPVOID
)credential
->TargetAlias
,
142 if (ret
== ERROR_FILE_NOT_FOUND
)
143 credential
->TargetAlias
= NULL
;
144 else if (ret
!= ERROR_SUCCESS
)
146 else if (type
!= REG_SZ
)
147 return ERROR_REGISTRY_CORRUPT
;
152 ret
= RegQueryValueExW(hkey
, wszUserNameValue
, 0, &type
, NULL
, &count
);
153 if (ret
!= ERROR_FILE_NOT_FOUND
)
155 if (ret
!= ERROR_SUCCESS
)
157 else if (type
!= REG_SZ
)
158 return ERROR_REGISTRY_CORRUPT
;
163 credential
->UserName
= (LPWSTR
)buffer
;
164 ret
= RegQueryValueExW(hkey
, wszUserNameValue
, 0, &type
, (LPVOID
)credential
->UserName
,
166 if (ret
== ERROR_FILE_NOT_FOUND
)
167 credential
->UserName
= NULL
;
168 else if (ret
!= ERROR_SUCCESS
)
170 else if (type
!= REG_SZ
)
171 return ERROR_REGISTRY_CORRUPT
;
176 ret
= read_credential_blob(hkey
, key_data
, NULL
, &count
);
177 if (ret
!= ERROR_FILE_NOT_FOUND
)
179 if (ret
!= ERROR_SUCCESS
)
185 credential
->CredentialBlob
= (LPBYTE
)buffer
;
186 ret
= read_credential_blob(hkey
, key_data
, credential
->CredentialBlob
, &count
);
187 if (ret
== ERROR_FILE_NOT_FOUND
)
188 credential
->CredentialBlob
= NULL
;
189 else if (ret
!= ERROR_SUCCESS
)
191 credential
->CredentialBlobSize
= count
;
194 /* FIXME: Attributes */
197 credential
->AttributeCount
= 0;
198 credential
->Attributes
= NULL
;
201 if (!credential
) return ERROR_SUCCESS
;
203 count
= sizeof(credential
->Flags
);
204 ret
= RegQueryValueExW(hkey
, wszFlagsValue
, NULL
, &type
, (LPVOID
)&credential
->Flags
,
206 if (ret
!= ERROR_SUCCESS
)
208 else if (type
!= REG_DWORD
)
209 return ERROR_REGISTRY_CORRUPT
;
210 count
= sizeof(credential
->Type
);
211 ret
= RegQueryValueExW(hkey
, wszTypeValue
, NULL
, &type
, (LPVOID
)&credential
->Type
,
213 if (ret
!= ERROR_SUCCESS
)
215 else if (type
!= REG_DWORD
)
216 return ERROR_REGISTRY_CORRUPT
;
218 count
= sizeof(credential
->LastWritten
);
219 ret
= RegQueryValueExW(hkey
, wszLastWrittenValue
, NULL
, &type
, (LPVOID
)&credential
->LastWritten
,
221 if (ret
!= ERROR_SUCCESS
)
223 else if (type
!= REG_BINARY
)
224 return ERROR_REGISTRY_CORRUPT
;
225 count
= sizeof(credential
->Persist
);
226 ret
= RegQueryValueExW(hkey
, wszPersistValue
, NULL
, &type
, (LPVOID
)&credential
->Persist
,
228 if (ret
== ERROR_SUCCESS
&& type
!= REG_DWORD
)
229 return ERROR_REGISTRY_CORRUPT
;
234 static DWORD
mac_read_credential_from_item(SecKeychainItemRef item
, BOOL require_password
,
235 PCREDENTIALW credential
, char *buffer
,
240 UInt32 cred_blob_len
;
242 LPWSTR domain
= NULL
;
244 BOOL user_name_present
= FALSE
;
245 SecKeychainAttributeInfo info
;
246 SecKeychainAttributeList
*attr_list
;
247 UInt32 info_tags
[] = { kSecServerItemAttr
, kSecSecurityDomainItemAttr
, kSecAccountItemAttr
,
248 kSecCommentItemAttr
, kSecCreationDateItemAttr
};
249 info
.count
= sizeof(info_tags
)/sizeof(info_tags
[0]);
250 info
.tag
= info_tags
;
252 status
= SecKeychainItemCopyAttributesAndData(item
, &info
, NULL
, &attr_list
, &cred_blob_len
, &cred_blob
);
253 if (status
== errSecAuthFailed
&& !require_password
)
257 status
= SecKeychainItemCopyAttributesAndData(item
, &info
, NULL
, &attr_list
, &cred_blob_len
, NULL
);
261 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status
);
262 return ERROR_NOT_FOUND
;
265 for (i
= 0; i
< attr_list
->count
; i
++)
266 if (attr_list
->attr
[i
].tag
== kSecAccountItemAttr
&& attr_list
->attr
[i
].data
)
268 user_name_present
= TRUE
;
271 if (!user_name_present
)
273 WARN("no kSecAccountItemAttr for item\n");
274 SecKeychainItemFreeAttributesAndData(attr_list
, cred_blob
);
275 return ERROR_NOT_FOUND
;
280 credential
->Flags
= 0;
281 credential
->Type
= CRED_TYPE_DOMAIN_PASSWORD
;
282 credential
->TargetName
= NULL
;
283 credential
->Comment
= NULL
;
284 memset(&credential
->LastWritten
, 0, sizeof(credential
->LastWritten
));
285 credential
->CredentialBlobSize
= 0;
286 credential
->CredentialBlob
= NULL
;
287 credential
->Persist
= CRED_PERSIST_LOCAL_MACHINE
;
288 credential
->AttributeCount
= 0;
289 credential
->Attributes
= NULL
;
290 credential
->TargetAlias
= NULL
;
291 credential
->UserName
= NULL
;
293 for (i
= 0; i
< attr_list
->count
; i
++)
295 switch (attr_list
->attr
[i
].tag
)
297 case kSecServerItemAttr
:
298 TRACE("kSecServerItemAttr: %.*s\n", (int)attr_list
->attr
[i
].length
,
299 (char *)attr_list
->attr
[i
].data
);
300 if (!attr_list
->attr
[i
].data
) continue;
304 credential
->TargetName
= (LPWSTR
)buffer
;
305 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[i
].data
,
306 attr_list
->attr
[i
].length
, (LPWSTR
)buffer
, 0xffff);
307 credential
->TargetName
[str_len
] = '\0';
308 buffer
+= (str_len
+ 1) * sizeof(WCHAR
);
309 *len
+= (str_len
+ 1) * sizeof(WCHAR
);
314 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[i
].data
,
315 attr_list
->attr
[i
].length
, NULL
, 0);
316 *len
+= (str_len
+ 1) * sizeof(WCHAR
);
319 case kSecAccountItemAttr
:
322 TRACE("kSecAccountItemAttr: %.*s\n", (int)attr_list
->attr
[i
].length
,
323 (char *)attr_list
->attr
[i
].data
);
324 if (!attr_list
->attr
[i
].data
) continue;
325 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[i
].data
,
326 attr_list
->attr
[i
].length
, NULL
, 0);
327 user
= HeapAlloc(GetProcessHeap(), 0, (str_len
+ 1) * sizeof(WCHAR
));
328 MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[i
].data
,
329 attr_list
->attr
[i
].length
, user
, str_len
);
330 user
[str_len
] = '\0';
333 case kSecCommentItemAttr
:
334 TRACE("kSecCommentItemAttr: %.*s\n", (int)attr_list
->attr
[i
].length
,
335 (char *)attr_list
->attr
[i
].data
);
336 if (!attr_list
->attr
[i
].data
) continue;
340 credential
->Comment
= (LPWSTR
)buffer
;
341 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[i
].data
,
342 attr_list
->attr
[i
].length
, (LPWSTR
)buffer
, 0xffff);
343 credential
->Comment
[str_len
] = '\0';
344 buffer
+= (str_len
+ 1) * sizeof(WCHAR
);
345 *len
+= (str_len
+ 1) * sizeof(WCHAR
);
350 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[i
].data
,
351 attr_list
->attr
[i
].length
, NULL
, 0);
352 *len
+= (str_len
+ 1) * sizeof(WCHAR
);
355 case kSecSecurityDomainItemAttr
:
358 TRACE("kSecSecurityDomainItemAttr: %.*s\n", (int)attr_list
->attr
[i
].length
,
359 (char *)attr_list
->attr
[i
].data
);
360 if (!attr_list
->attr
[i
].data
) continue;
361 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[i
].data
,
362 attr_list
->attr
[i
].length
, NULL
, 0);
363 domain
= HeapAlloc(GetProcessHeap(), 0, (str_len
+ 1) * sizeof(WCHAR
));
364 MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[i
].data
,
365 attr_list
->attr
[i
].length
, domain
, str_len
);
366 domain
[str_len
] = '\0';
369 case kSecCreationDateItemAttr
:
370 TRACE("kSecCreationDateItemAttr: %.*s\n", (int)attr_list
->attr
[i
].length
,
371 (char *)attr_list
->attr
[i
].data
);
374 LARGE_INTEGER win_time
;
377 memset(&tm
, 0, sizeof(tm
));
378 strptime(attr_list
->attr
[i
].data
, "%Y%m%d%H%M%SZ", &tm
);
380 RtlSecondsSince1970ToTime(time
, &win_time
);
381 credential
->LastWritten
.dwLowDateTime
= win_time
.u
.LowPart
;
382 credential
->LastWritten
.dwHighDateTime
= win_time
.u
.HighPart
;
392 credential
->UserName
= (LPWSTR
)buffer
;
395 str_len
= strlenW(domain
);
396 *len
+= (str_len
+ 1) * sizeof(WCHAR
);
399 memcpy(credential
->UserName
, domain
, str_len
* sizeof(WCHAR
));
400 /* FIXME: figure out when to use an '@' */
401 credential
->UserName
[str_len
] = '\\';
402 buffer
+= (str_len
+ 1) * sizeof(WCHAR
);
405 str_len
= strlenW(user
);
406 *len
+= (str_len
+ 1) * sizeof(WCHAR
);
409 memcpy(buffer
, user
, (str_len
+ 1) * sizeof(WCHAR
));
410 buffer
+= (str_len
+ 1) * sizeof(WCHAR
);
411 TRACE("UserName = %s\n", debugstr_w(credential
->UserName
));
414 HeapFree(GetProcessHeap(), 0, user
);
415 HeapFree(GetProcessHeap(), 0, domain
);
422 credential
->CredentialBlob
= (BYTE
*)buffer
;
423 str_len
= MultiByteToWideChar(CP_UTF8
, 0, cred_blob
, cred_blob_len
,
424 (LPWSTR
)buffer
, 0xffff);
425 credential
->CredentialBlobSize
= str_len
* sizeof(WCHAR
);
426 *len
+= str_len
* sizeof(WCHAR
);
431 str_len
= MultiByteToWideChar(CP_UTF8
, 0, cred_blob
, cred_blob_len
,
433 *len
+= str_len
* sizeof(WCHAR
);
436 SecKeychainItemFreeAttributesAndData(attr_list
, cred_blob
);
437 return ERROR_SUCCESS
;
441 static DWORD
write_credential_blob(HKEY hkey
, LPCWSTR target_name
, DWORD type
,
442 const BYTE key_data
[KEY_SIZE
],
443 const BYTE
*credential_blob
, DWORD credential_blob_size
)
445 LPBYTE encrypted_credential_blob
;
450 key
.Length
= key
.MaximumLength
= KEY_SIZE
;
451 key
.Buffer
= (unsigned char *)key_data
;
453 encrypted_credential_blob
= HeapAlloc(GetProcessHeap(), 0, credential_blob_size
);
454 if (!encrypted_credential_blob
) return ERROR_OUTOFMEMORY
;
456 memcpy(encrypted_credential_blob
, credential_blob
, credential_blob_size
);
457 data
.Length
= data
.MaximumLength
= credential_blob_size
;
458 data
.Buffer
= encrypted_credential_blob
;
459 SystemFunction032(&data
, &key
);
461 ret
= RegSetValueExW(hkey
, wszPasswordValue
, 0, REG_BINARY
, encrypted_credential_blob
, credential_blob_size
);
462 HeapFree(GetProcessHeap(), 0, encrypted_credential_blob
);
467 static DWORD
registry_write_credential(HKEY hkey
, const CREDENTIALW
*credential
,
468 const BYTE key_data
[KEY_SIZE
], BOOL preserve_blob
)
471 FILETIME LastWritten
;
473 GetSystemTimeAsFileTime(&LastWritten
);
475 ret
= RegSetValueExW(hkey
, wszFlagsValue
, 0, REG_DWORD
, (const BYTE
*)&credential
->Flags
,
476 sizeof(credential
->Flags
));
477 if (ret
!= ERROR_SUCCESS
) return ret
;
478 ret
= RegSetValueExW(hkey
, wszTypeValue
, 0, REG_DWORD
, (const BYTE
*)&credential
->Type
,
479 sizeof(credential
->Type
));
480 if (ret
!= ERROR_SUCCESS
) return ret
;
481 ret
= RegSetValueExW(hkey
, NULL
, 0, REG_SZ
, (LPVOID
)credential
->TargetName
,
482 sizeof(WCHAR
)*(strlenW(credential
->TargetName
)+1));
483 if (ret
!= ERROR_SUCCESS
) return ret
;
484 if (credential
->Comment
)
486 ret
= RegSetValueExW(hkey
, wszCommentValue
, 0, REG_SZ
, (LPVOID
)credential
->Comment
,
487 sizeof(WCHAR
)*(strlenW(credential
->Comment
)+1));
488 if (ret
!= ERROR_SUCCESS
) return ret
;
490 ret
= RegSetValueExW(hkey
, wszLastWrittenValue
, 0, REG_BINARY
, (LPVOID
)&LastWritten
,
491 sizeof(LastWritten
));
492 if (ret
!= ERROR_SUCCESS
) return ret
;
493 ret
= RegSetValueExW(hkey
, wszPersistValue
, 0, REG_DWORD
, (const BYTE
*)&credential
->Persist
,
494 sizeof(credential
->Persist
));
495 if (ret
!= ERROR_SUCCESS
) return ret
;
496 /* FIXME: Attributes */
497 if (credential
->TargetAlias
)
499 ret
= RegSetValueExW(hkey
, wszTargetAliasValue
, 0, REG_SZ
, (LPVOID
)credential
->TargetAlias
,
500 sizeof(WCHAR
)*(strlenW(credential
->TargetAlias
)+1));
501 if (ret
!= ERROR_SUCCESS
) return ret
;
503 if (credential
->UserName
)
505 ret
= RegSetValueExW(hkey
, wszUserNameValue
, 0, REG_SZ
, (LPVOID
)credential
->UserName
,
506 sizeof(WCHAR
)*(strlenW(credential
->UserName
)+1));
507 if (ret
!= ERROR_SUCCESS
) return ret
;
511 ret
= write_credential_blob(hkey
, credential
->TargetName
, credential
->Type
,
512 key_data
, credential
->CredentialBlob
,
513 credential
->CredentialBlobSize
);
519 static DWORD
mac_write_credential(const CREDENTIALW
*credential
, BOOL preserve_blob
)
522 SecKeychainItemRef keychain_item
;
528 UInt32 domainlen
= 0;
532 SecKeychainAttribute attrs
[1];
533 SecKeychainAttributeList attr_list
;
535 if (credential
->Flags
)
536 FIXME("Flags 0x%x not written\n", credential
->Flags
);
537 if (credential
->Type
!= CRED_TYPE_DOMAIN_PASSWORD
)
538 FIXME("credential type of %d not supported\n", credential
->Type
);
539 if (credential
->Persist
!= CRED_PERSIST_LOCAL_MACHINE
)
540 FIXME("persist value of %d not supported\n", credential
->Persist
);
541 if (credential
->AttributeCount
)
542 FIXME("custom attributes not supported\n");
544 p
= strchrW(credential
->UserName
, '\\');
547 domainlen
= WideCharToMultiByte(CP_UTF8
, 0, credential
->UserName
,
548 p
- credential
->UserName
, NULL
, 0, NULL
, NULL
);
549 domain
= HeapAlloc(GetProcessHeap(), 0, (domainlen
+ 1) * sizeof(*domain
));
550 WideCharToMultiByte(CP_UTF8
, 0, credential
->UserName
, p
- credential
->UserName
,
551 domain
, domainlen
, NULL
, NULL
);
552 domain
[domainlen
] = '\0';
556 p
= credential
->UserName
;
557 userlen
= WideCharToMultiByte(CP_UTF8
, 0, p
, -1, NULL
, 0, NULL
, NULL
);
558 username
= HeapAlloc(GetProcessHeap(), 0, userlen
* sizeof(*username
));
559 WideCharToMultiByte(CP_UTF8
, 0, p
, -1, username
, userlen
, NULL
, NULL
);
561 serverlen
= WideCharToMultiByte(CP_UTF8
, 0, credential
->TargetName
, -1, NULL
, 0, NULL
, NULL
);
562 servername
= HeapAlloc(GetProcessHeap(), 0, serverlen
* sizeof(*servername
));
563 WideCharToMultiByte(CP_UTF8
, 0, credential
->TargetName
, -1, servername
, serverlen
, NULL
, NULL
);
564 pwlen
= WideCharToMultiByte(CP_UTF8
, 0, (LPCWSTR
)credential
->CredentialBlob
,
565 credential
->CredentialBlobSize
/ sizeof(WCHAR
), NULL
, 0, NULL
, NULL
);
566 password
= HeapAlloc(GetProcessHeap(), 0, pwlen
* sizeof(*domain
));
567 WideCharToMultiByte(CP_UTF8
, 0, (LPCWSTR
)credential
->CredentialBlob
,
568 credential
->CredentialBlobSize
/ sizeof(WCHAR
), password
, pwlen
, NULL
, NULL
);
570 TRACE("adding server %s, domain %s, username %s using Keychain\n", servername
, domain
, username
);
571 status
= SecKeychainAddInternetPassword(NULL
, strlen(servername
), servername
,
572 strlen(domain
), domain
, strlen(username
),
573 username
, 0, NULL
, 0,
575 kSecAuthenticationTypeDefault
,
576 strlen(password
), password
, &keychain_item
);
578 ERR("SecKeychainAddInternetPassword returned %ld\n", status
);
579 if (status
== errSecDuplicateItem
)
581 SecKeychainItemRef keychain_item
;
583 status
= SecKeychainFindInternetPassword(NULL
, strlen(servername
), servername
,
584 strlen(domain
), domain
,
585 strlen(username
), username
,
586 0, NULL
/* any path */, 0,
587 0 /* any protocol */,
588 0 /* any authentication type */,
589 0, NULL
, &keychain_item
);
591 ERR("SecKeychainFindInternetPassword returned %ld\n", status
);
593 HeapFree(GetProcessHeap(), 0, domain
);
594 HeapFree(GetProcessHeap(), 0, username
);
595 HeapFree(GetProcessHeap(), 0, servername
);
598 HeapFree(GetProcessHeap(), 0, password
);
599 return ERROR_GEN_FAILURE
;
601 if (credential
->Comment
)
604 attr_list
.attr
= attrs
;
605 attrs
[0].tag
= kSecCommentItemAttr
;
606 attrs
[0].length
= WideCharToMultiByte(CP_UTF8
, 0, credential
->Comment
, -1, NULL
, 0, NULL
, NULL
);
607 if (attrs
[0].length
) attrs
[0].length
--;
608 attrs
[0].data
= HeapAlloc(GetProcessHeap(), 0, attrs
[0].length
);
609 WideCharToMultiByte(CP_UTF8
, 0, credential
->Comment
, -1, attrs
[0].data
, attrs
[0].length
, NULL
, NULL
);
614 attr_list
.attr
= NULL
;
616 status
= SecKeychainItemModifyAttributesAndData(keychain_item
, &attr_list
,
617 preserve_blob
? 0 : strlen(password
),
618 preserve_blob
? NULL
: password
);
619 if (credential
->Comment
)
620 HeapFree(GetProcessHeap(), 0, attrs
[0].data
);
621 HeapFree(GetProcessHeap(), 0, password
);
622 /* FIXME: set TargetAlias attribute */
623 CFRelease(keychain_item
);
625 return ERROR_GEN_FAILURE
;
626 return ERROR_SUCCESS
;
630 static DWORD
open_cred_mgr_key(HKEY
*hkey
, BOOL open_for_write
)
632 return RegCreateKeyExW(HKEY_CURRENT_USER
, wszCredentialManagerKey
, 0,
633 NULL
, REG_OPTION_NON_VOLATILE
,
634 KEY_READ
| (open_for_write
? KEY_WRITE
: 0), NULL
, hkey
, NULL
);
637 static DWORD
get_cred_mgr_encryption_key(HKEY hkeyMgr
, BYTE key_data
[KEY_SIZE
])
639 static const BYTE my_key_data
[KEY_SIZE
] = { 0 };
647 memcpy(key_data
, my_key_data
, KEY_SIZE
);
650 ret
= RegQueryValueExW(hkeyMgr
, wszEncryptionKeyValue
, NULL
, &type
, key_data
,
652 if (ret
== ERROR_SUCCESS
)
654 if (type
!= REG_BINARY
)
655 return ERROR_REGISTRY_CORRUPT
;
657 return ERROR_SUCCESS
;
659 if (ret
!= ERROR_FILE_NOT_FOUND
)
662 GetSystemTimeAsFileTime(&ft
);
663 seed
= ft
.dwLowDateTime
;
664 value
= RtlUniform(&seed
);
665 *(DWORD
*)key_data
= value
;
666 seed
= ft
.dwHighDateTime
;
667 value
= RtlUniform(&seed
);
668 *(DWORD
*)(key_data
+ 4) = value
;
670 ret
= RegSetValueExW(hkeyMgr
, wszEncryptionKeyValue
, 0, REG_BINARY
,
672 if (ret
== ERROR_ACCESS_DENIED
)
674 ret
= open_cred_mgr_key(&hkeyMgr
, TRUE
);
675 if (ret
== ERROR_SUCCESS
)
677 ret
= RegSetValueExW(hkeyMgr
, wszEncryptionKeyValue
, 0, REG_BINARY
,
679 RegCloseKey(hkeyMgr
);
685 static LPWSTR
get_key_name_for_target(LPCWSTR target_name
, DWORD type
)
687 static const WCHAR wszGenericPrefix
[] = {'G','e','n','e','r','i','c',':',' ',0};
688 static const WCHAR wszDomPasswdPrefix
[] = {'D','o','m','P','a','s','s','w','d',':',' ',0};
690 LPCWSTR prefix
= NULL
;
693 len
= strlenW(target_name
);
694 if (type
== CRED_TYPE_GENERIC
)
696 prefix
= wszGenericPrefix
;
697 len
+= sizeof(wszGenericPrefix
)/sizeof(wszGenericPrefix
[0]);
701 prefix
= wszDomPasswdPrefix
;
702 len
+= sizeof(wszDomPasswdPrefix
)/sizeof(wszDomPasswdPrefix
[0]);
705 key_name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
706 if (!key_name
) return NULL
;
708 strcpyW(key_name
, prefix
);
709 strcatW(key_name
, target_name
);
711 for (p
= key_name
; *p
; p
++)
712 if (*p
== '\\') *p
= '_';
717 static BOOL
registry_credential_matches_filter(HKEY hkeyCred
, LPCWSTR filter
)
725 if (!filter
) return TRUE
;
727 ret
= RegQueryValueExW(hkeyCred
, NULL
, 0, &type
, NULL
, &count
);
728 if (ret
!= ERROR_SUCCESS
)
730 else if (type
!= REG_SZ
)
733 target_name
= HeapAlloc(GetProcessHeap(), 0, count
);
736 ret
= RegQueryValueExW(hkeyCred
, NULL
, 0, &type
, (LPVOID
)target_name
, &count
);
737 if (ret
!= ERROR_SUCCESS
|| type
!= REG_SZ
)
739 HeapFree(GetProcessHeap(), 0, target_name
);
743 TRACE("comparing filter %s to target name %s\n", debugstr_w(filter
),
744 debugstr_w(target_name
));
746 p
= strchrW(filter
, '*');
747 ret
= CompareStringW(GetThreadLocale(), 0, filter
,
748 (p
&& !p
[1] ? p
- filter
: -1), target_name
,
749 (p
&& !p
[1] ? p
- filter
: -1)) == CSTR_EQUAL
;
751 HeapFree(GetProcessHeap(), 0, target_name
);
755 static DWORD
registry_enumerate_credentials(HKEY hkeyMgr
, LPCWSTR filter
,
757 DWORD target_name_len
, const BYTE key_data
[KEY_SIZE
],
758 PCREDENTIALW
*credentials
, char **buffer
,
759 DWORD
*len
, DWORD
*count
)
766 ret
= RegEnumKeyW(hkeyMgr
, i
, target_name
, target_name_len
+1);
767 if (ret
== ERROR_NO_MORE_ITEMS
)
772 else if (ret
!= ERROR_SUCCESS
)
774 TRACE("target_name = %s\n", debugstr_w(target_name
));
775 ret
= RegOpenKeyExW(hkeyMgr
, target_name
, 0, KEY_QUERY_VALUE
, &hkeyCred
);
776 if (ret
!= ERROR_SUCCESS
)
778 if (!registry_credential_matches_filter(hkeyCred
, filter
))
780 RegCloseKey(hkeyCred
);
785 *len
= sizeof(CREDENTIALW
);
786 credentials
[*count
] = (PCREDENTIALW
)*buffer
;
789 *len
+= sizeof(CREDENTIALW
);
790 ret
= registry_read_credential(hkeyCred
, buffer
? credentials
[*count
] : NULL
,
791 key_data
, buffer
? *buffer
+ sizeof(CREDENTIALW
) : NULL
,
793 RegCloseKey(hkeyCred
);
794 if (ret
!= ERROR_SUCCESS
) break;
795 if (buffer
) *buffer
+= *len
;
802 static BOOL
mac_credential_matches_filter(void *data
, UInt32 data_len
, const WCHAR
*filter
)
809 if (!filter
) return TRUE
;
811 len
= MultiByteToWideChar(CP_UTF8
, 0, data
, data_len
, NULL
, 0);
812 if (!(target_name
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
)))) return FALSE
;
813 MultiByteToWideChar(CP_UTF8
, 0, data
, data_len
, target_name
, len
);
814 target_name
[len
] = 0;
816 TRACE("comparing filter %s to target name %s\n", debugstr_w(filter
), debugstr_w(target_name
));
818 p
= strchrW(filter
, '*');
819 ret
= CompareStringW(GetThreadLocale(), 0, filter
,
820 (p
&& !p
[1] ? p
- filter
: -1), target_name
,
821 (p
&& !p
[1] ? p
- filter
: -1)) == CSTR_EQUAL
;
822 HeapFree(GetProcessHeap(), 0, target_name
);
826 static DWORD
mac_enumerate_credentials(LPCWSTR filter
, PCREDENTIALW
*credentials
,
827 char *buffer
, DWORD
*len
, DWORD
*count
)
829 SecKeychainSearchRef search
;
830 SecKeychainItemRef item
;
832 Boolean saved_user_interaction_allowed
;
835 SecKeychainGetUserInteractionAllowed(&saved_user_interaction_allowed
);
836 SecKeychainSetUserInteractionAllowed(false);
838 status
= SecKeychainSearchCreateFromAttributes(NULL
, kSecInternetPasswordItemClass
, NULL
, &search
);
841 while (SecKeychainSearchCopyNext(search
, &item
) == noErr
)
843 SecKeychainAttributeInfo info
;
844 SecKeychainAttributeList
*attr_list
;
845 UInt32 info_tags
[] = { kSecServerItemAttr
};
848 info
.count
= sizeof(info_tags
)/sizeof(info_tags
[0]);
849 info
.tag
= info_tags
;
851 status
= SecKeychainItemCopyAttributesAndData(item
, &info
, NULL
, &attr_list
, NULL
, NULL
);
854 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status
);
859 *len
= sizeof(CREDENTIALW
);
860 credentials
[*count
] = (PCREDENTIALW
)buffer
;
863 *len
+= sizeof(CREDENTIALW
);
864 if (attr_list
->count
!= 1 || attr_list
->attr
[0].tag
!= kSecServerItemAttr
)
866 SecKeychainItemFreeAttributesAndData(attr_list
, NULL
);
869 TRACE("server item: %.*s\n", (int)attr_list
->attr
[0].length
, (char *)attr_list
->attr
[0].data
);
870 match
= mac_credential_matches_filter(attr_list
->attr
[0].data
, attr_list
->attr
[0].length
, filter
);
871 SecKeychainItemFreeAttributesAndData(attr_list
, NULL
);
872 if (!match
) continue;
873 ret
= mac_read_credential_from_item(item
, FALSE
,
874 buffer
? credentials
[*count
] : NULL
,
875 buffer
? buffer
+ sizeof(CREDENTIALW
) : NULL
,
878 if (ret
== ERROR_SUCCESS
)
881 if (buffer
) buffer
+= *len
;
887 ERR("SecKeychainSearchCreateFromAttributes returned status %ld\n", status
);
888 SecKeychainSetUserInteractionAllowed(saved_user_interaction_allowed
);
889 return ERROR_SUCCESS
;
892 static DWORD
mac_delete_credential(LPCWSTR TargetName
)
895 SecKeychainSearchRef search
;
896 status
= SecKeychainSearchCreateFromAttributes(NULL
, kSecInternetPasswordItemClass
, NULL
, &search
);
899 SecKeychainItemRef item
;
900 while (SecKeychainSearchCopyNext(search
, &item
) == noErr
)
902 SecKeychainAttributeInfo info
;
903 SecKeychainAttributeList
*attr_list
;
904 UInt32 info_tags
[] = { kSecServerItemAttr
};
907 info
.count
= sizeof(info_tags
)/sizeof(info_tags
[0]);
908 info
.tag
= info_tags
;
910 status
= SecKeychainItemCopyAttributesAndData(item
, &info
, NULL
, &attr_list
, NULL
, NULL
);
913 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status
);
916 if (attr_list
->count
!= 1 || attr_list
->attr
[0].tag
!= kSecServerItemAttr
)
921 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[0].data
, attr_list
->attr
[0].length
, NULL
, 0);
922 target_name
= HeapAlloc(GetProcessHeap(), 0, (str_len
+ 1) * sizeof(WCHAR
));
923 MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[0].data
, attr_list
->attr
[0].length
, target_name
, str_len
);
925 target_name
[str_len
] = '\0';
926 if (strcmpiW(TargetName
, target_name
))
929 HeapFree(GetProcessHeap(), 0, target_name
);
932 HeapFree(GetProcessHeap(), 0, target_name
);
933 SecKeychainItemFreeAttributesAndData(attr_list
, NULL
);
934 SecKeychainItemDelete(item
);
938 return ERROR_SUCCESS
;
942 return ERROR_NOT_FOUND
;
946 /******************************************************************************
947 * convert_PCREDENTIALW_to_PCREDENTIALA [internal]
949 * convert a Credential struct from UNICODE to ANSI and return the needed size in Bytes
953 static INT
convert_PCREDENTIALW_to_PCREDENTIALA(const CREDENTIALW
*CredentialW
, PCREDENTIALA CredentialA
, DWORD len
)
957 INT needed
= sizeof(CREDENTIALA
);
961 if (CredentialW
->TargetName
)
962 needed
+= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->TargetName
, -1, NULL
, 0, NULL
, NULL
);
963 if (CredentialW
->Comment
)
964 needed
+= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->Comment
, -1, NULL
, 0, NULL
, NULL
);
965 needed
+= CredentialW
->CredentialBlobSize
;
966 if (CredentialW
->TargetAlias
)
967 needed
+= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->TargetAlias
, -1, NULL
, 0, NULL
, NULL
);
968 if (CredentialW
->UserName
)
969 needed
+= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->UserName
, -1, NULL
, 0, NULL
, NULL
);
975 buffer
= (char *)CredentialA
+ sizeof(CREDENTIALA
);
976 len
-= sizeof(CREDENTIALA
);
977 CredentialA
->Flags
= CredentialW
->Flags
;
978 CredentialA
->Type
= CredentialW
->Type
;
980 if (CredentialW
->TargetName
)
982 CredentialA
->TargetName
= buffer
;
983 string_len
= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->TargetName
, -1, buffer
, len
, NULL
, NULL
);
984 buffer
+= string_len
;
985 needed
+= string_len
;
989 CredentialA
->TargetName
= NULL
;
990 if (CredentialW
->Comment
)
992 CredentialA
->Comment
= buffer
;
993 string_len
= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->Comment
, -1, buffer
, len
, NULL
, NULL
);
994 buffer
+= string_len
;
995 needed
+= string_len
;
999 CredentialA
->Comment
= NULL
;
1000 CredentialA
->LastWritten
= CredentialW
->LastWritten
;
1001 CredentialA
->CredentialBlobSize
= CredentialW
->CredentialBlobSize
;
1002 if (CredentialW
->CredentialBlobSize
&& (CredentialW
->CredentialBlobSize
<= len
))
1004 CredentialA
->CredentialBlob
=(LPBYTE
)buffer
;
1005 memcpy(CredentialA
->CredentialBlob
, CredentialW
->CredentialBlob
,
1006 CredentialW
->CredentialBlobSize
);
1007 buffer
+= CredentialW
->CredentialBlobSize
;
1008 needed
+= CredentialW
->CredentialBlobSize
;
1009 len
-= CredentialW
->CredentialBlobSize
;
1012 CredentialA
->CredentialBlob
= NULL
;
1013 CredentialA
->Persist
= CredentialW
->Persist
;
1014 CredentialA
->AttributeCount
= 0;
1015 CredentialA
->Attributes
= NULL
; /* FIXME */
1016 if (CredentialW
->TargetAlias
)
1018 CredentialA
->TargetAlias
= buffer
;
1019 string_len
= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->TargetAlias
, -1, buffer
, len
, NULL
, NULL
);
1020 buffer
+= string_len
;
1021 needed
+= string_len
;
1025 CredentialA
->TargetAlias
= NULL
;
1026 if (CredentialW
->UserName
)
1028 CredentialA
->UserName
= buffer
;
1029 string_len
= WideCharToMultiByte(CP_ACP
, 0, CredentialW
->UserName
, -1, buffer
, len
, NULL
, NULL
);
1030 needed
+= string_len
;
1033 CredentialA
->UserName
= NULL
;
1038 /******************************************************************************
1039 * convert_PCREDENTIALA_to_PCREDENTIALW [internal]
1041 * convert a Credential struct from ANSI to UNICODE and return the needed size in Bytes
1044 static INT
convert_PCREDENTIALA_to_PCREDENTIALW(const CREDENTIALA
*CredentialA
, PCREDENTIALW CredentialW
, INT len
)
1048 INT needed
= sizeof(CREDENTIALW
);
1052 if (CredentialA
->TargetName
)
1053 needed
+= sizeof(WCHAR
) * MultiByteToWideChar(CP_ACP
, 0, CredentialA
->TargetName
, -1, NULL
, 0);
1054 if (CredentialA
->Comment
)
1055 needed
+= sizeof(WCHAR
) * MultiByteToWideChar(CP_ACP
, 0, CredentialA
->Comment
, -1, NULL
, 0);
1056 needed
+= CredentialA
->CredentialBlobSize
;
1057 if (CredentialA
->TargetAlias
)
1058 needed
+= sizeof(WCHAR
) * MultiByteToWideChar(CP_ACP
, 0, CredentialA
->TargetAlias
, -1, NULL
, 0);
1059 if (CredentialA
->UserName
)
1060 needed
+= sizeof(WCHAR
) * MultiByteToWideChar(CP_ACP
, 0, CredentialA
->UserName
, -1, NULL
, 0);
1065 buffer
= (char *)CredentialW
+ sizeof(CREDENTIALW
);
1066 len
-= sizeof(CREDENTIALW
);
1067 CredentialW
->Flags
= CredentialA
->Flags
;
1068 CredentialW
->Type
= CredentialA
->Type
;
1069 if (CredentialA
->TargetName
)
1071 CredentialW
->TargetName
= (LPWSTR
)buffer
;
1072 string_len
= MultiByteToWideChar(CP_ACP
, 0, CredentialA
->TargetName
, -1, CredentialW
->TargetName
, len
/ sizeof(WCHAR
));
1073 buffer
+= sizeof(WCHAR
) * string_len
;
1074 needed
+= sizeof(WCHAR
) * string_len
;
1075 len
-= sizeof(WCHAR
) * string_len
;
1078 CredentialW
->TargetName
= NULL
;
1079 if (CredentialA
->Comment
)
1081 CredentialW
->Comment
= (LPWSTR
)buffer
;
1082 string_len
= MultiByteToWideChar(CP_ACP
, 0, CredentialA
->Comment
, -1, CredentialW
->Comment
, len
/ sizeof(WCHAR
));
1083 buffer
+= sizeof(WCHAR
) * string_len
;
1084 needed
+= sizeof(WCHAR
) * string_len
;
1085 len
-= sizeof(WCHAR
) * string_len
;
1088 CredentialW
->Comment
= NULL
;
1089 CredentialW
->LastWritten
= CredentialA
->LastWritten
;
1090 CredentialW
->CredentialBlobSize
= CredentialA
->CredentialBlobSize
;
1091 if (CredentialA
->CredentialBlobSize
)
1093 CredentialW
->CredentialBlob
=(LPBYTE
)buffer
;
1094 memcpy(CredentialW
->CredentialBlob
, CredentialA
->CredentialBlob
,
1095 CredentialA
->CredentialBlobSize
);
1096 buffer
+= CredentialA
->CredentialBlobSize
;
1097 needed
+= CredentialA
->CredentialBlobSize
;
1098 len
-= CredentialA
->CredentialBlobSize
;
1101 CredentialW
->CredentialBlob
= NULL
;
1102 CredentialW
->Persist
= CredentialA
->Persist
;
1103 CredentialW
->AttributeCount
= 0;
1104 CredentialW
->Attributes
= NULL
; /* FIXME */
1105 if (CredentialA
->TargetAlias
)
1107 CredentialW
->TargetAlias
= (LPWSTR
)buffer
;
1108 string_len
= MultiByteToWideChar(CP_ACP
, 0, CredentialA
->TargetAlias
, -1, CredentialW
->TargetAlias
, len
/ sizeof(WCHAR
));
1109 buffer
+= sizeof(WCHAR
) * string_len
;
1110 needed
+= sizeof(WCHAR
) * string_len
;
1111 len
-= sizeof(WCHAR
) * string_len
;
1114 CredentialW
->TargetAlias
= NULL
;
1115 if (CredentialA
->UserName
)
1117 CredentialW
->UserName
= (LPWSTR
)buffer
;
1118 string_len
= MultiByteToWideChar(CP_ACP
, 0, CredentialA
->UserName
, -1, CredentialW
->UserName
, len
/ sizeof(WCHAR
));
1119 needed
+= sizeof(WCHAR
) * string_len
;
1122 CredentialW
->UserName
= NULL
;
1127 /******************************************************************************
1128 * CredDeleteA [ADVAPI32.@]
1130 BOOL WINAPI
CredDeleteA(LPCSTR TargetName
, DWORD Type
, DWORD Flags
)
1136 TRACE("(%s, %d, 0x%x)\n", debugstr_a(TargetName
), Type
, Flags
);
1140 SetLastError(ERROR_INVALID_PARAMETER
);
1144 len
= MultiByteToWideChar(CP_ACP
, 0, TargetName
, -1, NULL
, 0);
1145 TargetNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1148 SetLastError(ERROR_OUTOFMEMORY
);
1151 MultiByteToWideChar(CP_ACP
, 0, TargetName
, -1, TargetNameW
, len
);
1153 ret
= CredDeleteW(TargetNameW
, Type
, Flags
);
1155 HeapFree(GetProcessHeap(), 0, TargetNameW
);
1160 /******************************************************************************
1161 * CredDeleteW [ADVAPI32.@]
1163 BOOL WINAPI
CredDeleteW(LPCWSTR TargetName
, DWORD Type
, DWORD Flags
)
1169 TRACE("(%s, %d, 0x%x)\n", debugstr_w(TargetName
), Type
, Flags
);
1173 SetLastError(ERROR_INVALID_PARAMETER
);
1177 if (Type
!= CRED_TYPE_GENERIC
&& Type
!= CRED_TYPE_DOMAIN_PASSWORD
)
1179 FIXME("unhandled type %d\n", Type
);
1180 SetLastError(ERROR_INVALID_PARAMETER
);
1186 FIXME("unhandled flags 0x%x\n", Flags
);
1187 SetLastError(ERROR_INVALID_FLAGS
);
1192 if (Type
== CRED_TYPE_DOMAIN_PASSWORD
)
1194 ret
= mac_delete_credential(TargetName
);
1195 if (ret
== ERROR_SUCCESS
)
1200 ret
= open_cred_mgr_key(&hkeyMgr
, TRUE
);
1201 if (ret
!= ERROR_SUCCESS
)
1203 WARN("couldn't open/create manager key, error %d\n", ret
);
1204 SetLastError(ERROR_NO_SUCH_LOGON_SESSION
);
1208 key_name
= get_key_name_for_target(TargetName
, Type
);
1209 ret
= RegDeleteKeyW(hkeyMgr
, key_name
);
1210 HeapFree(GetProcessHeap(), 0, key_name
);
1211 RegCloseKey(hkeyMgr
);
1212 if (ret
!= ERROR_SUCCESS
)
1214 SetLastError(ERROR_NOT_FOUND
);
1221 /******************************************************************************
1222 * CredEnumerateA [ADVAPI32.@]
1224 BOOL WINAPI
CredEnumerateA(LPCSTR Filter
, DWORD Flags
, DWORD
*Count
,
1225 PCREDENTIALA
**Credentials
)
1228 PCREDENTIALW
*CredentialsW
;
1234 TRACE("(%s, 0x%x, %p, %p)\n", debugstr_a(Filter
), Flags
, Count
, Credentials
);
1238 len
= MultiByteToWideChar(CP_ACP
, 0, Filter
, -1, NULL
, 0);
1239 FilterW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1242 SetLastError(ERROR_OUTOFMEMORY
);
1245 MultiByteToWideChar(CP_ACP
, 0, Filter
, -1, FilterW
, len
);
1250 if (!CredEnumerateW(FilterW
, Flags
, Count
, &CredentialsW
))
1252 HeapFree(GetProcessHeap(), 0, FilterW
);
1255 HeapFree(GetProcessHeap(), 0, FilterW
);
1257 len
= *Count
* sizeof(PCREDENTIALA
);
1258 for (i
= 0; i
< *Count
; i
++)
1259 len
+= convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW
[i
], NULL
, 0);
1261 *Credentials
= HeapAlloc(GetProcessHeap(), 0, len
);
1264 CredFree(CredentialsW
);
1265 SetLastError(ERROR_OUTOFMEMORY
);
1269 buffer
= (char *)&(*Credentials
)[*Count
];
1270 len
-= *Count
* sizeof(PCREDENTIALA
);
1271 for (i
= 0; i
< *Count
; i
++)
1273 (*Credentials
)[i
] = (PCREDENTIALA
)buffer
;
1274 needed
= convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW
[i
], (*Credentials
)[i
], len
);
1279 CredFree(CredentialsW
);
1284 /******************************************************************************
1285 * CredEnumerateW [ADVAPI32.@]
1287 BOOL WINAPI
CredEnumerateW(LPCWSTR Filter
, DWORD Flags
, DWORD
*Count
,
1288 PCREDENTIALW
**Credentials
)
1293 DWORD target_name_len
;
1296 BYTE key_data
[KEY_SIZE
];
1298 TRACE("(%s, 0x%x, %p, %p)\n", debugstr_w(Filter
), Flags
, Count
, Credentials
);
1302 SetLastError(ERROR_INVALID_FLAGS
);
1306 ret
= open_cred_mgr_key(&hkeyMgr
, FALSE
);
1307 if (ret
!= ERROR_SUCCESS
)
1309 WARN("couldn't open/create manager key, error %d\n", ret
);
1310 SetLastError(ERROR_NO_SUCH_LOGON_SESSION
);
1314 ret
= get_cred_mgr_encryption_key(hkeyMgr
, key_data
);
1315 if (ret
!= ERROR_SUCCESS
)
1317 RegCloseKey(hkeyMgr
);
1322 ret
= RegQueryInfoKeyW(hkeyMgr
, NULL
, NULL
, NULL
, NULL
, &target_name_len
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1323 if (ret
!= ERROR_SUCCESS
)
1325 RegCloseKey(hkeyMgr
);
1330 target_name
= HeapAlloc(GetProcessHeap(), 0, (target_name_len
+1)*sizeof(WCHAR
));
1333 RegCloseKey(hkeyMgr
);
1334 SetLastError(ERROR_OUTOFMEMORY
);
1340 ret
= registry_enumerate_credentials(hkeyMgr
, Filter
, target_name
, target_name_len
,
1341 key_data
, NULL
, NULL
, &len
, Count
);
1343 if (ret
== ERROR_SUCCESS
)
1344 ret
= mac_enumerate_credentials(Filter
, NULL
, NULL
, &len
, Count
);
1346 if (ret
== ERROR_SUCCESS
&& *Count
== 0)
1347 ret
= ERROR_NOT_FOUND
;
1348 if (ret
!= ERROR_SUCCESS
)
1350 HeapFree(GetProcessHeap(), 0, target_name
);
1351 RegCloseKey(hkeyMgr
);
1355 len
+= *Count
* sizeof(PCREDENTIALW
);
1357 if (ret
== ERROR_SUCCESS
)
1359 buffer
= HeapAlloc(GetProcessHeap(), 0, len
);
1360 *Credentials
= (PCREDENTIALW
*)buffer
;
1363 buffer
+= *Count
* sizeof(PCREDENTIALW
);
1365 ret
= registry_enumerate_credentials(hkeyMgr
, Filter
, target_name
,
1366 target_name_len
, key_data
,
1367 *Credentials
, &buffer
, &len
,
1370 if (ret
== ERROR_SUCCESS
)
1371 ret
= mac_enumerate_credentials(Filter
, *Credentials
,
1372 buffer
, &len
, Count
);
1376 ret
= ERROR_OUTOFMEMORY
;
1379 HeapFree(GetProcessHeap(), 0, target_name
);
1380 RegCloseKey(hkeyMgr
);
1382 if (ret
!= ERROR_SUCCESS
)
1390 /******************************************************************************
1391 * CredFree [ADVAPI32.@]
1393 VOID WINAPI
CredFree(PVOID Buffer
)
1395 HeapFree(GetProcessHeap(), 0, Buffer
);
1398 /******************************************************************************
1399 * CredReadA [ADVAPI32.@]
1401 BOOL WINAPI
CredReadA(LPCSTR TargetName
, DWORD Type
, DWORD Flags
, PCREDENTIALA
*Credential
)
1404 PCREDENTIALW CredentialW
;
1407 TRACE("(%s, %d, 0x%x, %p)\n", debugstr_a(TargetName
), Type
, Flags
, Credential
);
1411 SetLastError(ERROR_INVALID_PARAMETER
);
1415 len
= MultiByteToWideChar(CP_ACP
, 0, TargetName
, -1, NULL
, 0);
1416 TargetNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1419 SetLastError(ERROR_OUTOFMEMORY
);
1422 MultiByteToWideChar(CP_ACP
, 0, TargetName
, -1, TargetNameW
, len
);
1424 if (!CredReadW(TargetNameW
, Type
, Flags
, &CredentialW
))
1426 HeapFree(GetProcessHeap(), 0, TargetNameW
);
1429 HeapFree(GetProcessHeap(), 0, TargetNameW
);
1431 len
= convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW
, NULL
, 0);
1432 *Credential
= HeapAlloc(GetProcessHeap(), 0, len
);
1435 SetLastError(ERROR_OUTOFMEMORY
);
1438 convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW
, *Credential
, len
);
1440 CredFree(CredentialW
);
1445 /******************************************************************************
1446 * CredReadW [ADVAPI32.@]
1448 BOOL WINAPI
CredReadW(LPCWSTR TargetName
, DWORD Type
, DWORD Flags
, PCREDENTIALW
*Credential
)
1455 BYTE key_data
[KEY_SIZE
];
1457 TRACE("(%s, %d, 0x%x, %p)\n", debugstr_w(TargetName
), Type
, Flags
, Credential
);
1461 SetLastError(ERROR_INVALID_PARAMETER
);
1465 if (Type
!= CRED_TYPE_GENERIC
&& Type
!= CRED_TYPE_DOMAIN_PASSWORD
)
1467 FIXME("unhandled type %d\n", Type
);
1468 SetLastError(ERROR_INVALID_PARAMETER
);
1474 FIXME("unhandled flags 0x%x\n", Flags
);
1475 SetLastError(ERROR_INVALID_FLAGS
);
1480 if (Type
== CRED_TYPE_DOMAIN_PASSWORD
)
1483 SecKeychainSearchRef search
;
1484 status
= SecKeychainSearchCreateFromAttributes(NULL
, kSecInternetPasswordItemClass
, NULL
, &search
);
1485 if (status
== noErr
)
1487 SecKeychainItemRef item
;
1488 while (SecKeychainSearchCopyNext(search
, &item
) == noErr
)
1490 SecKeychainAttributeInfo info
;
1491 SecKeychainAttributeList
*attr_list
;
1492 UInt32 info_tags
[] = { kSecServerItemAttr
};
1495 info
.count
= sizeof(info_tags
)/sizeof(info_tags
[0]);
1496 info
.tag
= info_tags
;
1498 status
= SecKeychainItemCopyAttributesAndData(item
, &info
, NULL
, &attr_list
, NULL
, NULL
);
1499 len
= sizeof(**Credential
);
1500 if (status
!= noErr
)
1502 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status
);
1505 if (attr_list
->count
!= 1 || attr_list
->attr
[0].tag
!= kSecServerItemAttr
)
1510 str_len
= MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[0].data
, attr_list
->attr
[0].length
, NULL
, 0);
1511 target_name
= HeapAlloc(GetProcessHeap(), 0, (str_len
+ 1) * sizeof(WCHAR
));
1512 MultiByteToWideChar(CP_UTF8
, 0, attr_list
->attr
[0].data
, attr_list
->attr
[0].length
, target_name
, str_len
);
1514 target_name
[str_len
] = '\0';
1515 if (strcmpiW(TargetName
, target_name
))
1518 HeapFree(GetProcessHeap(), 0, target_name
);
1521 HeapFree(GetProcessHeap(), 0, target_name
);
1522 SecKeychainItemFreeAttributesAndData(attr_list
, NULL
);
1523 ret
= mac_read_credential_from_item(item
, TRUE
, NULL
, NULL
, &len
);
1524 if (ret
== ERROR_SUCCESS
)
1526 *Credential
= HeapAlloc(GetProcessHeap(), 0, len
);
1529 len
= sizeof(**Credential
);
1530 ret
= mac_read_credential_from_item(item
, TRUE
, *Credential
,
1531 (char *)(*Credential
+ 1), &len
);
1534 ret
= ERROR_OUTOFMEMORY
;
1537 if (ret
!= ERROR_SUCCESS
)
1551 ret
= open_cred_mgr_key(&hkeyMgr
, FALSE
);
1552 if (ret
!= ERROR_SUCCESS
)
1554 WARN("couldn't open/create manager key, error %d\n", ret
);
1555 SetLastError(ERROR_NO_SUCH_LOGON_SESSION
);
1559 ret
= get_cred_mgr_encryption_key(hkeyMgr
, key_data
);
1560 if (ret
!= ERROR_SUCCESS
)
1562 RegCloseKey(hkeyMgr
);
1567 key_name
= get_key_name_for_target(TargetName
, Type
);
1568 ret
= RegOpenKeyExW(hkeyMgr
, key_name
, 0, KEY_QUERY_VALUE
, &hkeyCred
);
1569 HeapFree(GetProcessHeap(), 0, key_name
);
1570 if (ret
!= ERROR_SUCCESS
)
1572 TRACE("credentials for target name %s not found\n", debugstr_w(TargetName
));
1573 SetLastError(ERROR_NOT_FOUND
);
1577 len
= sizeof(**Credential
);
1578 ret
= registry_read_credential(hkeyCred
, NULL
, key_data
, NULL
, &len
);
1579 if (ret
== ERROR_SUCCESS
)
1581 *Credential
= HeapAlloc(GetProcessHeap(), 0, len
);
1584 len
= sizeof(**Credential
);
1585 ret
= registry_read_credential(hkeyCred
, *Credential
, key_data
,
1586 (char *)(*Credential
+ 1), &len
);
1589 ret
= ERROR_OUTOFMEMORY
;
1592 RegCloseKey(hkeyCred
);
1593 RegCloseKey(hkeyMgr
);
1595 if (ret
!= ERROR_SUCCESS
)
1603 /******************************************************************************
1604 * CredReadDomainCredentialsA [ADVAPI32.@]
1606 BOOL WINAPI
CredReadDomainCredentialsA(PCREDENTIAL_TARGET_INFORMATIONA TargetInformation
,
1607 DWORD Flags
, DWORD
*Size
, PCREDENTIALA
**Credentials
)
1609 PCREDENTIAL_TARGET_INFORMATIONW TargetInformationW
;
1612 WCHAR
*buffer
, *end
;
1614 PCREDENTIALW
* CredentialsW
;
1616 TRACE("(%p, 0x%x, %p, %p)\n", TargetInformation
, Flags
, Size
, Credentials
);
1618 /* follow Windows behavior - do not test for NULL, initialize early */
1620 *Credentials
= NULL
;
1622 if (!TargetInformation
)
1624 SetLastError(ERROR_INVALID_PARAMETER
);
1628 len
= sizeof(*TargetInformationW
);
1629 if (TargetInformation
->TargetName
)
1630 len
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->TargetName
, -1, NULL
, 0) * sizeof(WCHAR
);
1631 if (TargetInformation
->NetbiosServerName
)
1632 len
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->NetbiosServerName
, -1, NULL
, 0) * sizeof(WCHAR
);
1633 if (TargetInformation
->DnsServerName
)
1634 len
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->DnsServerName
, -1, NULL
, 0) * sizeof(WCHAR
);
1635 if (TargetInformation
->NetbiosDomainName
)
1636 len
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->NetbiosDomainName
, -1, NULL
, 0) * sizeof(WCHAR
);
1637 if (TargetInformation
->DnsDomainName
)
1638 len
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->DnsDomainName
, -1, NULL
, 0) * sizeof(WCHAR
);
1639 if (TargetInformation
->DnsTreeName
)
1640 len
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->DnsTreeName
, -1, NULL
, 0) * sizeof(WCHAR
);
1641 if (TargetInformation
->PackageName
)
1642 len
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->PackageName
, -1, NULL
, 0) * sizeof(WCHAR
);
1644 TargetInformationW
= HeapAlloc(GetProcessHeap(), 0, len
);
1645 if (!TargetInformationW
)
1647 SetLastError(ERROR_OUTOFMEMORY
);
1650 buffer
= (WCHAR
*)(TargetInformationW
+ 1);
1651 end
= (WCHAR
*)((char *)TargetInformationW
+ len
);
1653 if (TargetInformation
->TargetName
)
1655 TargetInformationW
->TargetName
= buffer
;
1656 buffer
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->TargetName
, -1,
1657 TargetInformationW
->TargetName
, end
- buffer
);
1659 TargetInformationW
->TargetName
= NULL
;
1661 if (TargetInformation
->NetbiosServerName
)
1663 TargetInformationW
->NetbiosServerName
= buffer
;
1664 buffer
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->NetbiosServerName
, -1,
1665 TargetInformationW
->NetbiosServerName
, end
- buffer
);
1667 TargetInformationW
->NetbiosServerName
= NULL
;
1669 if (TargetInformation
->DnsServerName
)
1671 TargetInformationW
->DnsServerName
= buffer
;
1672 buffer
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->DnsServerName
, -1,
1673 TargetInformationW
->DnsServerName
, end
- buffer
);
1675 TargetInformationW
->DnsServerName
= NULL
;
1677 if (TargetInformation
->NetbiosDomainName
)
1679 TargetInformationW
->NetbiosDomainName
= buffer
;
1680 buffer
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->NetbiosDomainName
, -1,
1681 TargetInformationW
->NetbiosDomainName
, end
- buffer
);
1683 TargetInformationW
->NetbiosDomainName
= NULL
;
1685 if (TargetInformation
->DnsDomainName
)
1687 TargetInformationW
->DnsDomainName
= buffer
;
1688 buffer
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->DnsDomainName
, -1,
1689 TargetInformationW
->DnsDomainName
, end
- buffer
);
1691 TargetInformationW
->DnsDomainName
= NULL
;
1693 if (TargetInformation
->DnsTreeName
)
1695 TargetInformationW
->DnsTreeName
= buffer
;
1696 buffer
+= MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->DnsTreeName
, -1,
1697 TargetInformationW
->DnsTreeName
, end
- buffer
);
1699 TargetInformationW
->DnsTreeName
= NULL
;
1701 if (TargetInformation
->PackageName
)
1703 TargetInformationW
->PackageName
= buffer
;
1704 MultiByteToWideChar(CP_ACP
, 0, TargetInformation
->PackageName
, -1,
1705 TargetInformationW
->PackageName
, end
- buffer
);
1707 TargetInformationW
->PackageName
= NULL
;
1709 TargetInformationW
->Flags
= TargetInformation
->Flags
;
1710 TargetInformationW
->CredTypeCount
= TargetInformation
->CredTypeCount
;
1711 TargetInformationW
->CredTypes
= TargetInformation
->CredTypes
;
1713 ret
= CredReadDomainCredentialsW(TargetInformationW
, Flags
, Size
, &CredentialsW
);
1715 HeapFree(GetProcessHeap(), 0, TargetInformationW
);
1722 len
= *Size
* sizeof(PCREDENTIALA
);
1723 for (i
= 0; i
< *Size
; i
++)
1724 len
+= convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW
[i
], NULL
, 0);
1726 *Credentials
= HeapAlloc(GetProcessHeap(), 0, len
);
1729 CredFree(CredentialsW
);
1730 SetLastError(ERROR_OUTOFMEMORY
);
1734 buf
= (char *)&(*Credentials
)[*Size
];
1735 len
-= *Size
* sizeof(PCREDENTIALA
);
1736 for (i
= 0; i
< *Size
; i
++)
1738 (*Credentials
)[i
] = (PCREDENTIALA
)buf
;
1739 needed
= convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW
[i
], (*Credentials
)[i
], len
);
1744 CredFree(CredentialsW
);
1749 /******************************************************************************
1750 * CredReadDomainCredentialsW [ADVAPI32.@]
1752 BOOL WINAPI
CredReadDomainCredentialsW(PCREDENTIAL_TARGET_INFORMATIONW TargetInformation
, DWORD Flags
,
1753 DWORD
*Size
, PCREDENTIALW
**Credentials
)
1755 FIXME("(%p, 0x%x, %p, %p) stub\n", TargetInformation
, Flags
, Size
, Credentials
);
1757 /* follow Windows behavior - do not test for NULL, initialize early */
1759 *Credentials
= NULL
;
1760 if (!TargetInformation
)
1762 SetLastError(ERROR_INVALID_PARAMETER
);
1766 SetLastError(ERROR_NOT_FOUND
);
1770 /******************************************************************************
1771 * CredWriteA [ADVAPI32.@]
1773 BOOL WINAPI
CredWriteA(PCREDENTIALA Credential
, DWORD Flags
)
1777 PCREDENTIALW CredentialW
;
1779 TRACE("(%p, 0x%x)\n", Credential
, Flags
);
1781 if (!Credential
|| !Credential
->TargetName
)
1783 SetLastError(ERROR_INVALID_PARAMETER
);
1787 len
= convert_PCREDENTIALA_to_PCREDENTIALW(Credential
, NULL
, 0);
1788 CredentialW
= HeapAlloc(GetProcessHeap(), 0, len
);
1791 SetLastError(ERROR_OUTOFMEMORY
);
1795 convert_PCREDENTIALA_to_PCREDENTIALW(Credential
, CredentialW
, len
);
1797 ret
= CredWriteW(CredentialW
, Flags
);
1799 HeapFree(GetProcessHeap(), 0, CredentialW
);
1804 /******************************************************************************
1805 * CredWriteW [ADVAPI32.@]
1807 BOOL WINAPI
CredWriteW(PCREDENTIALW Credential
, DWORD Flags
)
1813 BYTE key_data
[KEY_SIZE
];
1815 TRACE("(%p, 0x%x)\n", Credential
, Flags
);
1817 if (!Credential
|| !Credential
->TargetName
)
1819 SetLastError(ERROR_INVALID_PARAMETER
);
1823 if (Flags
& ~CRED_PRESERVE_CREDENTIAL_BLOB
)
1825 FIXME("unhandled flags 0x%x\n", Flags
);
1826 SetLastError(ERROR_INVALID_FLAGS
);
1830 if (Credential
->Type
!= CRED_TYPE_GENERIC
&& Credential
->Type
!= CRED_TYPE_DOMAIN_PASSWORD
)
1832 FIXME("unhandled type %d\n", Credential
->Type
);
1833 SetLastError(ERROR_INVALID_PARAMETER
);
1837 TRACE("Credential->Flags = 0x%08x\n", Credential
->Flags
);
1838 TRACE("Credential->Type = %u\n", Credential
->Type
);
1839 TRACE("Credential->TargetName = %s\n", debugstr_w(Credential
->TargetName
));
1840 TRACE("Credential->Comment = %s\n", debugstr_w(Credential
->Comment
));
1841 TRACE("Credential->Persist = %u\n", Credential
->Persist
);
1842 TRACE("Credential->TargetAlias = %s\n", debugstr_w(Credential
->TargetAlias
));
1843 TRACE("Credential->UserName = %s\n", debugstr_w(Credential
->UserName
));
1845 if (Credential
->Type
== CRED_TYPE_DOMAIN_PASSWORD
)
1847 if (!Credential
->UserName
||
1848 (Credential
->Persist
== CRED_PERSIST_ENTERPRISE
&&
1849 (!strchrW(Credential
->UserName
, '\\') && !strchrW(Credential
->UserName
, '@'))))
1851 ERR("bad username %s\n", debugstr_w(Credential
->UserName
));
1852 SetLastError(ERROR_BAD_USERNAME
);
1858 if (!Credential
->AttributeCount
&&
1859 Credential
->Type
== CRED_TYPE_DOMAIN_PASSWORD
&&
1860 (Credential
->Persist
== CRED_PERSIST_LOCAL_MACHINE
|| Credential
->Persist
== CRED_PERSIST_ENTERPRISE
))
1862 ret
= mac_write_credential(Credential
, Flags
& CRED_PRESERVE_CREDENTIAL_BLOB
);
1863 if (ret
!= ERROR_SUCCESS
)
1872 ret
= open_cred_mgr_key(&hkeyMgr
, FALSE
);
1873 if (ret
!= ERROR_SUCCESS
)
1875 WARN("couldn't open/create manager key, error %d\n", ret
);
1876 SetLastError(ERROR_NO_SUCH_LOGON_SESSION
);
1880 ret
= get_cred_mgr_encryption_key(hkeyMgr
, key_data
);
1881 if (ret
!= ERROR_SUCCESS
)
1883 RegCloseKey(hkeyMgr
);
1888 key_name
= get_key_name_for_target(Credential
->TargetName
, Credential
->Type
);
1889 ret
= RegCreateKeyExW(hkeyMgr
, key_name
, 0, NULL
,
1890 Credential
->Persist
== CRED_PERSIST_SESSION
? REG_OPTION_VOLATILE
: REG_OPTION_NON_VOLATILE
,
1891 KEY_READ
|KEY_WRITE
, NULL
, &hkeyCred
, NULL
);
1892 HeapFree(GetProcessHeap(), 0, key_name
);
1893 if (ret
!= ERROR_SUCCESS
)
1895 TRACE("credentials for target name %s not found\n",
1896 debugstr_w(Credential
->TargetName
));
1897 SetLastError(ERROR_NOT_FOUND
);
1901 ret
= registry_write_credential(hkeyCred
, Credential
, key_data
,
1902 Flags
& CRED_PRESERVE_CREDENTIAL_BLOB
);
1904 RegCloseKey(hkeyCred
);
1905 RegCloseKey(hkeyMgr
);
1907 if (ret
!= ERROR_SUCCESS
)
1915 /******************************************************************************
1916 * CredGetSessionTypes [ADVAPI32.@]
1918 WINADVAPI BOOL WINAPI
CredGetSessionTypes(DWORD persistCount
, LPDWORD persists
)
1920 TRACE("(%u, %p)\n", persistCount
, persists
);
1922 memset(persists
, CRED_PERSIST_NONE
, persistCount
*sizeof(*persists
));
1923 if (CRED_TYPE_GENERIC
< persistCount
)
1925 persists
[CRED_TYPE_GENERIC
] = CRED_PERSIST_ENTERPRISE
;
1927 if (CRED_TYPE_DOMAIN_PASSWORD
< persistCount
)
1929 persists
[CRED_TYPE_DOMAIN_PASSWORD
] = CRED_PERSIST_ENTERPRISE
;
1935 /******************************************************************************
1936 * CredMarshalCredentialA [ADVAPI32.@]
1938 BOOL WINAPI
CredMarshalCredentialA( CRED_MARSHAL_TYPE type
, PVOID cred
, LPSTR
*out
)
1943 TRACE("%u, %p, %p\n", type
, cred
, out
);
1945 if ((ret
= CredMarshalCredentialW( type
, cred
, &outW
)))
1947 int len
= WideCharToMultiByte( CP_ACP
, 0, outW
, -1, NULL
, 0, NULL
, NULL
);
1948 if (!(*out
= HeapAlloc( GetProcessHeap(), 0, len
)))
1950 HeapFree( GetProcessHeap(), 0, outW
);
1953 WideCharToMultiByte( CP_ACP
, 0, outW
, -1, *out
, len
, NULL
, NULL
);
1954 HeapFree( GetProcessHeap(), 0, outW
);
1959 static UINT
cred_encode( const char *bin
, unsigned int len
, WCHAR
*cred
)
1961 static char enc
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#-";
1966 cred
[n
++] = enc
[bin
[0] & 0x3f];
1967 x
= (bin
[0] & 0xc0) >> 6;
1973 cred
[n
++] = enc
[((bin
[1] & 0xf) << 2) | x
];
1974 x
= (bin
[1] & 0xf0) >> 4;
1980 cred
[n
++] = enc
[((bin
[2] & 0x3) << 4) | x
];
1981 cred
[n
++] = enc
[(bin
[2] & 0xfc) >> 2];
1988 /******************************************************************************
1989 * CredMarshalCredentialW [ADVAPI32.@]
1991 BOOL WINAPI
CredMarshalCredentialW( CRED_MARSHAL_TYPE type
, PVOID cred
, LPWSTR
*out
)
1993 CERT_CREDENTIAL_INFO
*cert
= cred
;
1994 USERNAME_TARGET_CREDENTIAL_INFO
*target
= cred
;
1998 TRACE("%u, %p, %p\n", type
, cred
, out
);
2000 if (!cred
|| (type
== CertCredential
&& cert
->cbSize
< sizeof(*cert
)) ||
2001 (type
!= CertCredential
&& type
!= UsernameTargetCredential
&& type
!= BinaryBlobCredential
) ||
2002 (type
== UsernameTargetCredential
&& (!target
->UserName
|| !target
->UserName
[0])))
2004 SetLastError( ERROR_INVALID_PARAMETER
);
2009 case CertCredential
:
2011 char hash
[CERT_HASH_LENGTH
+ 2];
2013 memcpy( hash
, cert
->rgbHashOfCert
, sizeof(cert
->rgbHashOfCert
) );
2014 memset( hash
+ sizeof(cert
->rgbHashOfCert
), 0, sizeof(hash
) - sizeof(cert
->rgbHashOfCert
) );
2016 size
= sizeof(hash
) * 4 / 3;
2017 if (!(p
= HeapAlloc( GetProcessHeap(), 0, (size
+ 4) * sizeof(WCHAR
) ))) return FALSE
;
2021 len
= cred_encode( (const char *)hash
, sizeof(hash
), p
+ 3 );
2025 case UsernameTargetCredential
:
2027 len
= strlenW( target
->UserName
);
2028 size
= (sizeof(DWORD
) + len
* sizeof(WCHAR
) + 2) * 4 / 3;
2029 if (!(p
= HeapAlloc( GetProcessHeap(), 0, (size
+ 4) * sizeof(WCHAR
) ))) return FALSE
;
2033 size
= len
* sizeof(WCHAR
);
2034 len
= cred_encode( (const char *)&size
, sizeof(DWORD
), p
+ 3 );
2035 len
+= cred_encode( (const char *)target
->UserName
, size
, p
+ 3 + len
);
2039 case BinaryBlobCredential
:
2040 FIXME("BinaryBlobCredential not implemented\n");
2049 /******************************************************************************
2050 * CredUnmarshalCredentialA [ADVAPI32.@]
2052 BOOL WINAPI
CredUnmarshalCredentialA( LPCSTR cred
, PCRED_MARSHAL_TYPE type
, PVOID
*out
)
2055 WCHAR
*credW
= NULL
;
2057 TRACE("%s, %p, %p\n", debugstr_a(cred
), type
, out
);
2061 int len
= MultiByteToWideChar( CP_ACP
, 0, cred
, -1, NULL
, 0 );
2062 if (!(credW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return FALSE
;
2063 MultiByteToWideChar( CP_ACP
, 0, cred
, -1, credW
, len
);
2065 ret
= CredUnmarshalCredentialW( credW
, type
, out
);
2066 HeapFree( GetProcessHeap(), 0, credW
);
2070 static inline char char_decode( WCHAR c
)
2072 if (c
>= 'A' && c
<= 'Z') return c
- 'A';
2073 if (c
>= 'a' && c
<= 'z') return c
- 'a' + 26;
2074 if (c
>= '0' && c
<= '9') return c
- '0' + 52;
2075 if (c
== '#') return 62;
2076 if (c
== '-') return 63;
2080 static BOOL
cred_decode( const WCHAR
*cred
, unsigned int len
, char *buf
)
2083 char c0
, c1
, c2
, c3
;
2084 const WCHAR
*p
= cred
;
2088 if ((c0
= char_decode( p
[0] )) > 63) return FALSE
;
2089 if ((c1
= char_decode( p
[1] )) > 63) return FALSE
;
2090 if ((c2
= char_decode( p
[2] )) > 63) return FALSE
;
2091 if ((c3
= char_decode( p
[3] )) > 63) return FALSE
;
2093 buf
[i
+ 0] = (c1
<< 6) | c0
;
2094 buf
[i
+ 1] = (c2
<< 4) | (c1
>> 2);
2095 buf
[i
+ 2] = (c3
<< 2) | (c2
>> 4);
2102 if ((c0
= char_decode( p
[0] )) > 63) return FALSE
;
2103 if ((c1
= char_decode( p
[1] )) > 63) return FALSE
;
2104 if ((c2
= char_decode( p
[2] )) > 63) return FALSE
;
2106 buf
[i
+ 0] = (c1
<< 6) | c0
;
2107 buf
[i
+ 1] = (c2
<< 4) | (c1
>> 2);
2108 buf
[i
+ 2] = c2
>> 4;
2112 if ((c0
= char_decode( p
[0] )) > 63) return FALSE
;
2113 if ((c1
= char_decode( p
[1] )) > 63) return FALSE
;
2115 buf
[i
+ 0] = (c1
<< 6) | c0
;
2116 buf
[i
+ 1] = c1
>> 2;
2121 if ((c0
= char_decode( p
[0] )) > 63) return FALSE
;
2130 /******************************************************************************
2131 * CredUnmarshalCredentialW [ADVAPI32.@]
2133 BOOL WINAPI
CredUnmarshalCredentialW( LPCWSTR cred
, PCRED_MARSHAL_TYPE type
, PVOID
*out
)
2135 unsigned int len
, buflen
;
2137 TRACE("%s, %p, %p\n", debugstr_w(cred
), type
, out
);
2139 if (!cred
|| cred
[0] != '@' || cred
[1] != '@' || !cred
[2] || !cred
[3])
2141 SetLastError( ERROR_INVALID_PARAMETER
);
2144 len
= strlenW( cred
+ 3 );
2145 switch (cred
[2] - 'A')
2147 case CertCredential
:
2149 char hash
[CERT_HASH_LENGTH
+ 2];
2150 CERT_CREDENTIAL_INFO
*cert
;
2152 if (len
!= 27 || !cred_decode( cred
+ 3, len
, hash
))
2154 SetLastError( ERROR_INVALID_PARAMETER
);
2157 if (!(cert
= HeapAlloc( GetProcessHeap(), 0, sizeof(*cert
) ))) return FALSE
;
2158 memcpy( cert
->rgbHashOfCert
, hash
, sizeof(cert
->rgbHashOfCert
) );
2159 cert
->cbSize
= sizeof(*cert
);
2160 *type
= CertCredential
;
2164 case UsernameTargetCredential
:
2166 USERNAME_TARGET_CREDENTIAL_INFO
*target
;
2169 if (len
< 9 || !cred_decode( cred
+ 3, 6, (char *)&size
) ||
2170 !size
|| size
% sizeof(WCHAR
) || size
> INT_MAX
)
2172 SetLastError( ERROR_INVALID_PARAMETER
);
2175 buflen
= sizeof(*target
) + size
+ sizeof(WCHAR
);
2176 if (!(target
= HeapAlloc( GetProcessHeap(), 0, buflen
))) return FALSE
;
2177 if (!cred_decode( cred
+ 9, len
- 6, (char *)(target
+ 1) ))
2179 HeapFree( GetProcessHeap(), 0, target
);
2182 target
->UserName
= (WCHAR
*)(target
+ 1);
2183 target
->UserName
[size
/ sizeof(WCHAR
)] = 0;
2184 *type
= UsernameTargetCredential
;
2188 case BinaryBlobCredential
:
2189 FIXME("BinaryBlobCredential not implemented\n");
2192 WARN("unhandled type %u\n", cred
[2] - 'A');
2198 /******************************************************************************
2199 * CredIsMarshaledCredentialW [ADVAPI32.@]
2201 * Check, if the name parameter is a marshaled credential, hash or binary blob
2204 * name the name to check
2207 * TRUE: the name parameter is a marshaled credential, hash or binary blob
2208 * FALSE: the name is a plain username
2210 BOOL WINAPI
CredIsMarshaledCredentialW(LPCWSTR name
)
2212 TRACE("(%s)\n", debugstr_w(name
));
2214 if (name
&& name
[0] == '@' && name
[1] == '@' && name
[2] > 'A' && name
[3])
2216 char hash
[CERT_HASH_LENGTH
+ 2];
2217 int len
= strlenW(name
+ 3 );
2220 if ((name
[2] - 'A') == CertCredential
&& (len
== 27) && cred_decode(name
+ 3, len
, hash
))
2223 if (((name
[2] - 'A') == UsernameTargetCredential
) &&
2224 (len
>= 9) && cred_decode(name
+ 3, 6, (char *)&size
) && size
)
2227 if ((name
[2] - 'A') == BinaryBlobCredential
)
2228 FIXME("BinaryBlobCredential not checked\n");
2230 if ((name
[2] - 'A') > BinaryBlobCredential
)
2231 TRACE("unknown type: %d\n", (name
[2] - 'A'));
2234 SetLastError(ERROR_INVALID_PARAMETER
);
2238 /******************************************************************************
2239 * CredIsMarshaledCredentialA [ADVAPI32.@]
2241 * See CredIsMarshaledCredentialW
2244 BOOL WINAPI
CredIsMarshaledCredentialA(LPCSTR name
)
2246 LPWSTR nameW
= NULL
;
2250 TRACE("(%s)\n", debugstr_a(name
));
2254 len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, NULL
, 0);
2255 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2256 MultiByteToWideChar(CP_ACP
, 0, name
, -1, nameW
, len
);
2259 res
= CredIsMarshaledCredentialW(nameW
);
2260 HeapFree(GetProcessHeap(), 0, nameW
);