wbemprox: Add __DERIVATION to the list of system properties.
[wine.git] / dlls / advapi32 / cred.c
blobde94cb1b87618309b53a356aad83c5c863f13c52
1 /*
2 * Credential Management APIs
4 * Copyright 2007 Robert Shearman for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <time.h>
23 #include <limits.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "wincred.h"
29 #include "winternl.h"
30 #include "winioctl.h"
31 #define WINE_MOUNTMGR_EXTENSIONS
32 #include "ddk/mountmgr.h"
34 #include "crypt.h"
36 #include "wine/debug.h"
38 #include "advapi32_misc.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(cred);
42 /* the size of the ARC4 key used to encrypt the password data */
43 #define KEY_SIZE 8
45 static DWORD read_credential_blob(HKEY hkey, const BYTE key_data[KEY_SIZE],
46 LPBYTE credential_blob,
47 DWORD *credential_blob_size)
49 DWORD ret;
50 DWORD type;
52 *credential_blob_size = 0;
53 ret = RegQueryValueExW(hkey, L"Password", 0, &type, NULL, credential_blob_size);
54 if (ret != ERROR_SUCCESS)
55 return ret;
56 else if (type != REG_BINARY)
57 return ERROR_REGISTRY_CORRUPT;
58 if (credential_blob)
60 struct ustring data;
61 struct ustring key;
63 ret = RegQueryValueExW(hkey, L"Password", 0, &type, credential_blob,
64 credential_blob_size);
65 if (ret != ERROR_SUCCESS)
66 return ret;
67 else if (type != REG_BINARY)
68 return ERROR_REGISTRY_CORRUPT;
70 key.Length = key.MaximumLength = KEY_SIZE;
71 key.Buffer = (unsigned char *)key_data;
73 data.Length = data.MaximumLength = *credential_blob_size;
74 data.Buffer = credential_blob;
75 SystemFunction032(&data, &key);
77 return ERROR_SUCCESS;
80 static DWORD registry_read_credential(HKEY hkey, PCREDENTIALW credential,
81 const BYTE key_data[KEY_SIZE],
82 char *buffer, DWORD *len)
84 DWORD type;
85 DWORD ret;
86 DWORD count;
88 ret = RegQueryValueExW(hkey, NULL, 0, &type, NULL, &count);
89 if (ret != ERROR_SUCCESS)
90 return ret;
91 else if (type != REG_SZ)
92 return ERROR_REGISTRY_CORRUPT;
93 *len += count;
94 if (credential)
96 credential->TargetName = (LPWSTR)buffer;
97 ret = RegQueryValueExW(hkey, NULL, 0, &type, (LPVOID)credential->TargetName,
98 &count);
99 if (ret != ERROR_SUCCESS || type != REG_SZ) return ret;
100 buffer += count;
103 ret = RegQueryValueExW(hkey, L"Comment", 0, &type, NULL, &count);
104 if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
105 return ret;
106 else if (type != REG_SZ)
107 return ERROR_REGISTRY_CORRUPT;
108 *len += count;
109 if (credential)
111 credential->Comment = (LPWSTR)buffer;
112 ret = RegQueryValueExW(hkey, L"Comment", 0, &type, (LPVOID)credential->Comment,
113 &count);
114 if (ret == ERROR_FILE_NOT_FOUND)
115 credential->Comment = NULL;
116 else if (ret != ERROR_SUCCESS)
117 return ret;
118 else if (type != REG_SZ)
119 return ERROR_REGISTRY_CORRUPT;
120 else
121 buffer += count;
124 ret = RegQueryValueExW(hkey, L"TargetAlias", 0, &type, NULL, &count);
125 if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
126 return ret;
127 else if (type != REG_SZ)
128 return ERROR_REGISTRY_CORRUPT;
129 *len += count;
130 if (credential)
132 credential->TargetAlias = (LPWSTR)buffer;
133 ret = RegQueryValueExW(hkey, L"TargetAlias", 0, &type, (LPVOID)credential->TargetAlias,
134 &count);
135 if (ret == ERROR_FILE_NOT_FOUND)
136 credential->TargetAlias = NULL;
137 else if (ret != ERROR_SUCCESS)
138 return ret;
139 else if (type != REG_SZ)
140 return ERROR_REGISTRY_CORRUPT;
141 else
142 buffer += count;
145 ret = RegQueryValueExW(hkey, L"UserName", 0, &type, NULL, &count);
146 if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
147 return ret;
148 else if (type != REG_SZ)
149 return ERROR_REGISTRY_CORRUPT;
150 *len += count;
151 if (credential)
153 credential->UserName = (LPWSTR)buffer;
154 ret = RegQueryValueExW(hkey, L"UserName", 0, &type, (LPVOID)credential->UserName,
155 &count);
156 if (ret == ERROR_FILE_NOT_FOUND)
157 credential->UserName = NULL;
158 else if (ret != ERROR_SUCCESS)
159 return ret;
160 else if (type != REG_SZ)
161 return ERROR_REGISTRY_CORRUPT;
162 else
163 buffer += count;
166 ret = read_credential_blob(hkey, key_data, NULL, &count);
167 if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS)
168 return ret;
169 *len += count;
170 if (credential)
172 credential->CredentialBlob = (LPBYTE)buffer;
173 ret = read_credential_blob(hkey, key_data, credential->CredentialBlob, &count);
174 if (ret == ERROR_FILE_NOT_FOUND)
175 credential->CredentialBlob = NULL;
176 else if (ret != ERROR_SUCCESS)
177 return ret;
178 credential->CredentialBlobSize = count;
181 /* FIXME: Attributes */
182 if (credential)
184 credential->AttributeCount = 0;
185 credential->Attributes = NULL;
188 if (!credential) return ERROR_SUCCESS;
190 count = sizeof(credential->Flags);
191 ret = RegQueryValueExW(hkey, L"Flags", NULL, &type, (LPVOID)&credential->Flags,
192 &count);
193 if (ret != ERROR_SUCCESS)
194 return ret;
195 else if (type != REG_DWORD)
196 return ERROR_REGISTRY_CORRUPT;
197 count = sizeof(credential->Type);
198 ret = RegQueryValueExW(hkey, L"Type", NULL, &type, (LPVOID)&credential->Type,
199 &count);
200 if (ret != ERROR_SUCCESS)
201 return ret;
202 else if (type != REG_DWORD)
203 return ERROR_REGISTRY_CORRUPT;
205 count = sizeof(credential->LastWritten);
206 ret = RegQueryValueExW(hkey, L"LastWritten", NULL, &type, (LPVOID)&credential->LastWritten,
207 &count);
208 if (ret != ERROR_SUCCESS)
209 return ret;
210 else if (type != REG_BINARY)
211 return ERROR_REGISTRY_CORRUPT;
212 count = sizeof(credential->Persist);
213 ret = RegQueryValueExW(hkey, L"Persist", NULL, &type, (LPVOID)&credential->Persist,
214 &count);
215 if (ret == ERROR_SUCCESS && type != REG_DWORD)
216 return ERROR_REGISTRY_CORRUPT;
217 return ret;
220 static DWORD write_credential_blob(HKEY hkey, LPCWSTR target_name, DWORD type,
221 const BYTE key_data[KEY_SIZE],
222 const BYTE *credential_blob, DWORD credential_blob_size)
224 LPBYTE encrypted_credential_blob;
225 struct ustring data;
226 struct ustring key;
227 DWORD ret;
229 key.Length = key.MaximumLength = KEY_SIZE;
230 key.Buffer = (unsigned char *)key_data;
232 encrypted_credential_blob = heap_alloc(credential_blob_size);
233 if (!encrypted_credential_blob) return ERROR_OUTOFMEMORY;
235 memcpy(encrypted_credential_blob, credential_blob, credential_blob_size);
236 data.Length = data.MaximumLength = credential_blob_size;
237 data.Buffer = encrypted_credential_blob;
238 SystemFunction032(&data, &key);
240 ret = RegSetValueExW(hkey, L"Password", 0, REG_BINARY, encrypted_credential_blob, credential_blob_size);
241 heap_free(encrypted_credential_blob);
243 return ret;
246 static DWORD registry_write_credential(HKEY hkey, const CREDENTIALW *credential,
247 const BYTE key_data[KEY_SIZE], BOOL preserve_blob)
249 DWORD ret;
250 FILETIME LastWritten;
252 GetSystemTimeAsFileTime(&LastWritten);
254 ret = RegSetValueExW(hkey, L"Flags", 0, REG_DWORD, (const BYTE*)&credential->Flags,
255 sizeof(credential->Flags));
256 if (ret != ERROR_SUCCESS) return ret;
257 ret = RegSetValueExW(hkey, L"Type", 0, REG_DWORD, (const BYTE*)&credential->Type,
258 sizeof(credential->Type));
259 if (ret != ERROR_SUCCESS) return ret;
260 ret = RegSetValueExW(hkey, NULL, 0, REG_SZ, (LPVOID)credential->TargetName,
261 sizeof(WCHAR)*(lstrlenW(credential->TargetName)+1));
262 if (ret != ERROR_SUCCESS) return ret;
263 if (credential->Comment)
265 ret = RegSetValueExW(hkey, L"Comment", 0, REG_SZ, (LPVOID)credential->Comment,
266 sizeof(WCHAR)*(lstrlenW(credential->Comment)+1));
267 if (ret != ERROR_SUCCESS) return ret;
269 ret = RegSetValueExW(hkey, L"LastWritten", 0, REG_BINARY, (LPVOID)&LastWritten,
270 sizeof(LastWritten));
271 if (ret != ERROR_SUCCESS) return ret;
272 ret = RegSetValueExW(hkey, L"Persist", 0, REG_DWORD, (const BYTE*)&credential->Persist,
273 sizeof(credential->Persist));
274 if (ret != ERROR_SUCCESS) return ret;
275 /* FIXME: Attributes */
276 if (credential->TargetAlias)
278 ret = RegSetValueExW(hkey, L"TargetAlias", 0, REG_SZ, (LPVOID)credential->TargetAlias,
279 sizeof(WCHAR)*(lstrlenW(credential->TargetAlias)+1));
280 if (ret != ERROR_SUCCESS) return ret;
282 if (credential->UserName)
284 ret = RegSetValueExW(hkey, L"UserName", 0, REG_SZ, (LPVOID)credential->UserName,
285 sizeof(WCHAR)*(lstrlenW(credential->UserName)+1));
286 if (ret != ERROR_SUCCESS) return ret;
288 if (!preserve_blob)
290 ret = write_credential_blob(hkey, credential->TargetName, credential->Type,
291 key_data, credential->CredentialBlob,
292 credential->CredentialBlobSize);
294 return ret;
297 static DWORD host_write_credential( const CREDENTIALW *credential, BOOL preserve_blob )
299 struct mountmgr_credential *cred;
300 HANDLE mgr;
301 DWORD size;
302 WCHAR *ptr;
303 BOOL ret;
305 if (credential->Flags)
306 FIXME( "flags 0x%x not written\n", credential->Flags );
307 if (credential->Type != CRED_TYPE_DOMAIN_PASSWORD)
308 FIXME( "credential type of %d not supported\n", credential->Type );
309 if (credential->Persist != CRED_PERSIST_LOCAL_MACHINE)
310 FIXME( "persist value of %d not supported\n", credential->Persist );
311 if (credential->AttributeCount)
312 FIXME( "custom attributes not supported\n" );
314 if (credential->CredentialBlobSize % sizeof(WCHAR)) return ERROR_NOT_SUPPORTED;
316 mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
317 OPEN_EXISTING, 0, 0 );
318 if (mgr == INVALID_HANDLE_VALUE) return GetLastError();
320 size = sizeof(*cred) + (lstrlenW( credential->TargetName ) + lstrlenW( credential->UserName ) + 2) * sizeof(WCHAR);
321 size += credential->CredentialBlobSize;
322 if (credential->Comment) size += (lstrlenW( credential->Comment ) + 1) * sizeof(WCHAR);
323 if (!(cred = heap_alloc( size )))
325 CloseHandle( mgr );
326 return ERROR_OUTOFMEMORY;
328 ptr = (WCHAR *)(cred + 1);
330 cred->targetname_offset = sizeof(*cred);
331 cred->targetname_size = (lstrlenW( credential->TargetName ) + 1) * sizeof(WCHAR);
332 lstrcpyW( ptr, credential->TargetName );
333 ptr += cred->targetname_size / sizeof(WCHAR);
335 cred->username_offset = cred->targetname_offset + cred->targetname_size;
336 cred->username_size = (lstrlenW( credential->UserName ) + 1) * sizeof(WCHAR);
337 lstrcpyW( ptr, credential->UserName );
338 ptr += cred->username_size / sizeof(WCHAR);
340 cred->blob_offset = cred->username_offset + cred->username_size;
341 if (credential->CredentialBlob)
343 cred->blob_size = credential->CredentialBlobSize;
344 memcpy( ptr, credential->CredentialBlob, credential->CredentialBlobSize );
345 ptr += cred->blob_size / sizeof(WCHAR);
347 else cred->blob_size = 0;
348 cred->blob_preserve = preserve_blob;
350 cred->comment_offset = cred->blob_offset + cred->blob_size;
351 if (credential->Comment)
353 cred->comment_size = (lstrlenW( credential->Comment ) + 1) * sizeof(WCHAR);
354 lstrcpyW( ptr, credential->Comment );
356 else cred->comment_size = 0;
358 ret = DeviceIoControl( mgr, IOCTL_MOUNTMGR_WRITE_CREDENTIAL, cred, size, NULL, 0, NULL, NULL );
359 heap_free( cred );
360 CloseHandle( mgr );
362 return ret ? ERROR_SUCCESS : GetLastError();
365 static DWORD open_cred_mgr_key(HKEY *hkey, BOOL open_for_write)
367 return RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Wine\\Credential Manager", 0,
368 NULL, REG_OPTION_NON_VOLATILE,
369 KEY_READ | (open_for_write ? KEY_WRITE : 0), NULL, hkey, NULL);
372 static DWORD get_cred_mgr_encryption_key(HKEY hkeyMgr, BYTE key_data[KEY_SIZE])
374 static const BYTE my_key_data[KEY_SIZE] = { 0 };
375 DWORD type;
376 DWORD count;
377 FILETIME ft;
378 ULONG seed;
379 ULONG value;
380 DWORD ret;
382 memcpy(key_data, my_key_data, KEY_SIZE);
384 count = KEY_SIZE;
385 ret = RegQueryValueExW(hkeyMgr, L"EncryptionKey", NULL, &type, key_data,
386 &count);
387 if (ret == ERROR_SUCCESS)
389 if (type != REG_BINARY)
390 return ERROR_REGISTRY_CORRUPT;
391 else
392 return ERROR_SUCCESS;
394 if (ret != ERROR_FILE_NOT_FOUND)
395 return ret;
397 GetSystemTimeAsFileTime(&ft);
398 seed = ft.dwLowDateTime;
399 value = RtlUniform(&seed);
400 *(DWORD *)key_data = value;
401 seed = ft.dwHighDateTime;
402 value = RtlUniform(&seed);
403 *(DWORD *)(key_data + 4) = value;
405 ret = RegSetValueExW(hkeyMgr, L"EncryptionKey", 0, REG_BINARY,
406 key_data, KEY_SIZE);
407 if (ret == ERROR_ACCESS_DENIED)
409 ret = open_cred_mgr_key(&hkeyMgr, TRUE);
410 if (ret == ERROR_SUCCESS)
412 ret = RegSetValueExW(hkeyMgr, L"EncryptionKey", 0, REG_BINARY,
413 key_data, KEY_SIZE);
414 RegCloseKey(hkeyMgr);
417 return ret;
420 static LPWSTR get_key_name_for_target(LPCWSTR target_name, DWORD type)
422 INT len;
423 LPCWSTR prefix = NULL;
424 LPWSTR key_name, p;
426 len = lstrlenW(target_name);
427 if (type == CRED_TYPE_GENERIC)
429 prefix = L"Generic: ";
430 len += ARRAY_SIZE(L"Generic: ");
432 else
434 prefix = L"DomPasswd: ";
435 len += ARRAY_SIZE(L"DomPasswd: ");
438 key_name = heap_alloc(len * sizeof(WCHAR));
439 if (!key_name) return NULL;
441 lstrcpyW(key_name, prefix);
442 lstrcatW(key_name, target_name);
444 for (p = key_name; *p; p++)
445 if (*p == '\\') *p = '_';
447 return key_name;
450 static BOOL registry_credential_matches_filter(HKEY hkeyCred, LPCWSTR filter)
452 LPWSTR target_name;
453 DWORD ret;
454 DWORD type;
455 DWORD count;
456 LPCWSTR p;
458 if (!filter) return TRUE;
460 ret = RegQueryValueExW(hkeyCred, NULL, 0, &type, NULL, &count);
461 if (ret != ERROR_SUCCESS)
462 return FALSE;
463 else if (type != REG_SZ)
464 return FALSE;
466 target_name = heap_alloc(count);
467 if (!target_name)
468 return FALSE;
469 ret = RegQueryValueExW(hkeyCred, NULL, 0, &type, (LPVOID)target_name, &count);
470 if (ret != ERROR_SUCCESS || type != REG_SZ)
472 heap_free(target_name);
473 return FALSE;
476 TRACE("comparing filter %s to target name %s\n", debugstr_w(filter),
477 debugstr_w(target_name));
479 p = wcschr(filter, '*');
480 ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, filter,
481 (p && !p[1] ? p - filter : -1), target_name,
482 (p && !p[1] ? p - filter : -1)) == CSTR_EQUAL;
484 heap_free(target_name);
485 return ret;
488 static DWORD registry_enumerate_credentials(HKEY hkeyMgr, LPCWSTR filter,
489 LPWSTR target_name,
490 DWORD target_name_len, const BYTE key_data[KEY_SIZE],
491 PCREDENTIALW *credentials, char **buffer,
492 DWORD *len, DWORD *count)
494 DWORD i;
495 DWORD ret;
496 for (i = 0;; i++)
498 HKEY hkeyCred;
499 ret = RegEnumKeyW(hkeyMgr, i, target_name, target_name_len+1);
500 if (ret == ERROR_NO_MORE_ITEMS)
502 ret = ERROR_SUCCESS;
503 break;
505 else if (ret != ERROR_SUCCESS)
506 continue;
507 TRACE("target_name = %s\n", debugstr_w(target_name));
508 ret = RegOpenKeyExW(hkeyMgr, target_name, 0, KEY_QUERY_VALUE, &hkeyCred);
509 if (ret != ERROR_SUCCESS)
510 continue;
511 if (!registry_credential_matches_filter(hkeyCred, filter))
513 RegCloseKey(hkeyCred);
514 continue;
516 if (buffer)
518 *len = sizeof(CREDENTIALW);
519 credentials[*count] = (PCREDENTIALW)*buffer;
521 else
522 *len += sizeof(CREDENTIALW);
523 ret = registry_read_credential(hkeyCred, buffer ? credentials[*count] : NULL,
524 key_data, buffer ? *buffer + sizeof(CREDENTIALW) : NULL,
525 len);
526 RegCloseKey(hkeyCred);
527 if (ret != ERROR_SUCCESS) break;
528 if (buffer) *buffer += *len;
529 (*count)++;
531 return ret;
534 /******************************************************************************
535 * convert_PCREDENTIALW_to_PCREDENTIALA [internal]
537 * convert a Credential struct from UNICODE to ANSI and return the needed size in Bytes
541 static INT convert_PCREDENTIALW_to_PCREDENTIALA(const CREDENTIALW *CredentialW, PCREDENTIALA CredentialA, DWORD len)
543 char *buffer;
544 INT string_len;
545 INT needed = sizeof(CREDENTIALA);
547 if (!CredentialA)
549 if (CredentialW->TargetName)
550 needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetName, -1, NULL, 0, NULL, NULL);
551 if (CredentialW->Comment)
552 needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->Comment, -1, NULL, 0, NULL, NULL);
553 needed += CredentialW->CredentialBlobSize;
554 if (CredentialW->TargetAlias)
555 needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetAlias, -1, NULL, 0, NULL, NULL);
556 if (CredentialW->UserName)
557 needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->UserName, -1, NULL, 0, NULL, NULL);
559 return needed;
563 buffer = (char *)CredentialA + sizeof(CREDENTIALA);
564 len -= sizeof(CREDENTIALA);
565 CredentialA->Flags = CredentialW->Flags;
566 CredentialA->Type = CredentialW->Type;
568 if (CredentialW->TargetName)
570 CredentialA->TargetName = buffer;
571 string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetName, -1, buffer, len, NULL, NULL);
572 buffer += string_len;
573 needed += string_len;
574 len -= string_len;
576 else
577 CredentialA->TargetName = NULL;
578 if (CredentialW->Comment)
580 CredentialA->Comment = buffer;
581 string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->Comment, -1, buffer, len, NULL, NULL);
582 buffer += string_len;
583 needed += string_len;
584 len -= string_len;
586 else
587 CredentialA->Comment = NULL;
588 CredentialA->LastWritten = CredentialW->LastWritten;
589 CredentialA->CredentialBlobSize = CredentialW->CredentialBlobSize;
590 if (CredentialW->CredentialBlobSize && (CredentialW->CredentialBlobSize <= len))
592 CredentialA->CredentialBlob =(LPBYTE)buffer;
593 memcpy(CredentialA->CredentialBlob, CredentialW->CredentialBlob,
594 CredentialW->CredentialBlobSize);
595 buffer += CredentialW->CredentialBlobSize;
596 needed += CredentialW->CredentialBlobSize;
597 len -= CredentialW->CredentialBlobSize;
599 else
600 CredentialA->CredentialBlob = NULL;
601 CredentialA->Persist = CredentialW->Persist;
602 CredentialA->AttributeCount = 0;
603 CredentialA->Attributes = NULL; /* FIXME */
604 if (CredentialW->TargetAlias)
606 CredentialA->TargetAlias = buffer;
607 string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetAlias, -1, buffer, len, NULL, NULL);
608 buffer += string_len;
609 needed += string_len;
610 len -= string_len;
612 else
613 CredentialA->TargetAlias = NULL;
614 if (CredentialW->UserName)
616 CredentialA->UserName = buffer;
617 string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->UserName, -1, buffer, len, NULL, NULL);
618 needed += string_len;
620 else
621 CredentialA->UserName = NULL;
623 return needed;
626 /******************************************************************************
627 * convert_PCREDENTIALA_to_PCREDENTIALW [internal]
629 * convert a Credential struct from ANSI to UNICODE and return the needed size in Bytes
632 static INT convert_PCREDENTIALA_to_PCREDENTIALW(const CREDENTIALA *CredentialA, PCREDENTIALW CredentialW, INT len)
634 char *buffer;
635 INT string_len;
636 INT needed = sizeof(CREDENTIALW);
638 if (!CredentialW)
640 if (CredentialA->TargetName)
641 needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetName, -1, NULL, 0);
642 if (CredentialA->Comment)
643 needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->Comment, -1, NULL, 0);
644 needed += CredentialA->CredentialBlobSize;
645 if (CredentialA->TargetAlias)
646 needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetAlias, -1, NULL, 0);
647 if (CredentialA->UserName)
648 needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->UserName, -1, NULL, 0);
650 return needed;
653 buffer = (char *)CredentialW + sizeof(CREDENTIALW);
654 len -= sizeof(CREDENTIALW);
655 CredentialW->Flags = CredentialA->Flags;
656 CredentialW->Type = CredentialA->Type;
657 if (CredentialA->TargetName)
659 CredentialW->TargetName = (LPWSTR)buffer;
660 string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetName, -1, CredentialW->TargetName, len / sizeof(WCHAR));
661 buffer += sizeof(WCHAR) * string_len;
662 needed += sizeof(WCHAR) * string_len;
663 len -= sizeof(WCHAR) * string_len;
665 else
666 CredentialW->TargetName = NULL;
667 if (CredentialA->Comment)
669 CredentialW->Comment = (LPWSTR)buffer;
670 string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->Comment, -1, CredentialW->Comment, len / sizeof(WCHAR));
671 buffer += sizeof(WCHAR) * string_len;
672 needed += sizeof(WCHAR) * string_len;
673 len -= sizeof(WCHAR) * string_len;
675 else
676 CredentialW->Comment = NULL;
677 CredentialW->LastWritten = CredentialA->LastWritten;
678 CredentialW->CredentialBlobSize = CredentialA->CredentialBlobSize;
679 if (CredentialA->CredentialBlobSize)
681 CredentialW->CredentialBlob =(LPBYTE)buffer;
682 memcpy(CredentialW->CredentialBlob, CredentialA->CredentialBlob,
683 CredentialA->CredentialBlobSize);
684 buffer += CredentialA->CredentialBlobSize;
685 needed += CredentialA->CredentialBlobSize;
686 len -= CredentialA->CredentialBlobSize;
688 else
689 CredentialW->CredentialBlob = NULL;
690 CredentialW->Persist = CredentialA->Persist;
691 CredentialW->AttributeCount = 0;
692 CredentialW->Attributes = NULL; /* FIXME */
693 if (CredentialA->TargetAlias)
695 CredentialW->TargetAlias = (LPWSTR)buffer;
696 string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetAlias, -1, CredentialW->TargetAlias, len / sizeof(WCHAR));
697 buffer += sizeof(WCHAR) * string_len;
698 needed += sizeof(WCHAR) * string_len;
699 len -= sizeof(WCHAR) * string_len;
701 else
702 CredentialW->TargetAlias = NULL;
703 if (CredentialA->UserName)
705 CredentialW->UserName = (LPWSTR)buffer;
706 string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->UserName, -1, CredentialW->UserName, len / sizeof(WCHAR));
707 needed += sizeof(WCHAR) * string_len;
709 else
710 CredentialW->UserName = NULL;
712 return needed;
715 /******************************************************************************
716 * CredDeleteA [ADVAPI32.@]
718 BOOL WINAPI CredDeleteA(LPCSTR TargetName, DWORD Type, DWORD Flags)
720 LPWSTR TargetNameW;
721 DWORD len;
722 BOOL ret;
724 TRACE("(%s, %d, 0x%x)\n", debugstr_a(TargetName), Type, Flags);
726 if (!TargetName)
728 SetLastError(ERROR_INVALID_PARAMETER);
729 return FALSE;
732 len = MultiByteToWideChar(CP_ACP, 0, TargetName, -1, NULL, 0);
733 TargetNameW = heap_alloc(len * sizeof(WCHAR));
734 if (!TargetNameW)
736 SetLastError(ERROR_OUTOFMEMORY);
737 return FALSE;
739 MultiByteToWideChar(CP_ACP, 0, TargetName, -1, TargetNameW, len);
741 ret = CredDeleteW(TargetNameW, Type, Flags);
743 heap_free(TargetNameW);
745 return ret;
748 static DWORD host_delete_credential( const WCHAR *targetname )
750 struct mountmgr_credential *cred;
751 DWORD size, name_size = (lstrlenW( targetname ) + 1) * sizeof(WCHAR);
752 HANDLE mgr;
753 WCHAR *ptr;
754 BOOL ret;
756 mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
757 OPEN_EXISTING, 0, 0 );
758 if (mgr == INVALID_HANDLE_VALUE) return GetLastError();
760 size = sizeof(*cred) + name_size;
761 if (!(cred = heap_alloc( size )))
763 CloseHandle( mgr );
764 return ERROR_OUTOFMEMORY;
766 cred->targetname_offset = sizeof(*cred);
767 cred->targetname_size = name_size;
768 ptr = (WCHAR *)(cred + 1);
769 lstrcpyW( ptr, targetname );
771 ret = DeviceIoControl( mgr, IOCTL_MOUNTMGR_DELETE_CREDENTIAL, cred, size, NULL, 0, NULL, NULL );
772 heap_free( cred );
773 CloseHandle( mgr );
775 return ret ? ERROR_SUCCESS : GetLastError();
778 /******************************************************************************
779 * CredDeleteW [ADVAPI32.@]
781 BOOL WINAPI CredDeleteW(LPCWSTR TargetName, DWORD Type, DWORD Flags)
783 HKEY hkeyMgr;
784 DWORD ret;
785 LPWSTR key_name;
787 TRACE("(%s, %d, 0x%x)\n", debugstr_w(TargetName), Type, Flags);
789 if (!TargetName)
791 SetLastError(ERROR_INVALID_PARAMETER);
792 return FALSE;
795 if (Type != CRED_TYPE_GENERIC && Type != CRED_TYPE_DOMAIN_PASSWORD)
797 FIXME("unhandled type %d\n", Type);
798 SetLastError(ERROR_INVALID_PARAMETER);
799 return FALSE;
802 if (Flags)
804 FIXME("unhandled flags 0x%x\n", Flags);
805 SetLastError(ERROR_INVALID_FLAGS);
806 return FALSE;
809 if (Type == CRED_TYPE_DOMAIN_PASSWORD)
811 ret = host_delete_credential(TargetName);
812 if (ret == ERROR_SUCCESS)
813 return TRUE;
816 ret = open_cred_mgr_key(&hkeyMgr, TRUE);
817 if (ret != ERROR_SUCCESS)
819 WARN("couldn't open/create manager key, error %d\n", ret);
820 SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
821 return FALSE;
824 key_name = get_key_name_for_target(TargetName, Type);
825 ret = RegDeleteKeyW(hkeyMgr, key_name);
826 heap_free(key_name);
827 RegCloseKey(hkeyMgr);
828 if (ret != ERROR_SUCCESS)
830 SetLastError(ERROR_NOT_FOUND);
831 return FALSE;
834 return TRUE;
837 /******************************************************************************
838 * CredEnumerateA [ADVAPI32.@]
840 BOOL WINAPI CredEnumerateA(LPCSTR Filter, DWORD Flags, DWORD *Count,
841 PCREDENTIALA **Credentials)
843 LPWSTR FilterW;
844 PCREDENTIALW *CredentialsW;
845 DWORD i;
846 INT len;
847 INT needed;
848 char *buffer;
850 TRACE("(%s, 0x%x, %p, %p)\n", debugstr_a(Filter), Flags, Count, Credentials);
852 if (Filter)
854 len = MultiByteToWideChar(CP_ACP, 0, Filter, -1, NULL, 0);
855 FilterW = heap_alloc(len * sizeof(WCHAR));
856 if (!FilterW)
858 SetLastError(ERROR_OUTOFMEMORY);
859 return FALSE;
861 MultiByteToWideChar(CP_ACP, 0, Filter, -1, FilterW, len);
863 else
864 FilterW = NULL;
866 if (!CredEnumerateW(FilterW, Flags, Count, &CredentialsW))
868 heap_free(FilterW);
869 return FALSE;
871 heap_free(FilterW);
873 len = *Count * sizeof(PCREDENTIALA);
874 for (i = 0; i < *Count; i++)
875 len += convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], NULL, 0);
877 *Credentials = heap_alloc(len);
878 if (!*Credentials)
880 CredFree(CredentialsW);
881 SetLastError(ERROR_OUTOFMEMORY);
882 return FALSE;
885 buffer = (char *)&(*Credentials)[*Count];
886 len -= *Count * sizeof(PCREDENTIALA);
887 for (i = 0; i < *Count; i++)
889 (*Credentials)[i] = (PCREDENTIALA)buffer;
890 needed = convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], (*Credentials)[i], len);
891 buffer += needed;
892 len -= needed;
895 CredFree(CredentialsW);
897 return TRUE;
900 #define CRED_LIST_COUNT 16
901 #define CRED_DATA_SIZE 2048
902 static DWORD host_enumerate_credentials( const WCHAR *filter, CREDENTIALW **credentials, char *buf, DWORD *len, DWORD *count )
904 struct mountmgr_credential_list *list, *tmp;
905 DWORD i, j, ret, size, filter_size, offset = 0;
906 HANDLE mgr;
907 WCHAR *ptr;
909 if (filter) filter_size = (lstrlenW( filter ) + 1) * sizeof(WCHAR);
910 else
912 filter = L"";
913 filter_size = sizeof(L"");
916 mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
917 if (mgr == INVALID_HANDLE_VALUE) return GetLastError();
919 size = FIELD_OFFSET( struct mountmgr_credential_list, creds[CRED_LIST_COUNT] ) + filter_size + CRED_DATA_SIZE;
920 if (!(list = heap_alloc( size )))
922 CloseHandle( mgr );
923 return ERROR_OUTOFMEMORY;
926 for (;;)
928 list->filter_offset = sizeof(*list);
929 list->filter_size = filter_size;
930 ptr = (WCHAR *)((char *)list + list->filter_offset);
931 lstrcpyW( ptr, filter );
933 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_ENUMERATE_CREDENTIALS, list, size, list, size, NULL, NULL )) break;
934 if ((ret = GetLastError()) != ERROR_MORE_DATA) goto done;
936 size = list->size + filter_size;
937 if (!(tmp = heap_realloc( list, size )))
939 ret = ERROR_OUTOFMEMORY;
940 goto done;
942 list = tmp;
945 for (i = 0, j = *count; i < list->count; i++)
947 CREDENTIALW *cred = (CREDENTIALW *)(buf + offset);
949 offset += sizeof(*cred) + list->creds[i].targetname_size + list->creds[i].comment_size + list->creds[i].blob_size +
950 list->creds[i].username_size;
951 if (!buf) continue;
953 ptr = (WCHAR *)(cred + 1);
954 cred->Flags = 0;
955 cred->Type = CRED_TYPE_DOMAIN_PASSWORD;
956 cred->TargetName = ptr;
957 memcpy( cred->TargetName, (char *)&list->creds[i] + list->creds[i].targetname_offset, list->creds[i].targetname_size );
958 ptr += list->creds[i].targetname_size / sizeof(WCHAR);
959 if (list->creds[i].comment_size)
961 cred->Comment = ptr;
962 memcpy( cred->Comment, (char *)&list->creds[i] + list->creds[i].comment_offset, list->creds[i].comment_size );
963 ptr += list->creds[i].comment_size / sizeof(WCHAR);
965 else cred->Comment = NULL;
966 cred->LastWritten = list->creds[i].last_written;
967 if (list->creds[i].blob_size)
969 cred->CredentialBlobSize = list->creds[i].blob_size;
970 cred->CredentialBlob = (BYTE *)ptr;
971 memcpy( cred->CredentialBlob, (char *)&list->creds[i] + list->creds[i].blob_offset, list->creds[i].blob_size );
972 ptr += list->creds[i].blob_size / sizeof(WCHAR);
974 else
976 cred->CredentialBlobSize = 0;
977 cred->CredentialBlob = NULL;
979 cred->Persist = CRED_PERSIST_LOCAL_MACHINE;
980 cred->AttributeCount = 0;
981 cred->Attributes = NULL;
982 cred->TargetAlias = NULL;
983 if (list->creds[i].username_size)
985 cred->UserName = ptr;
986 memcpy( cred->UserName, (char *)&list->creds[i] + list->creds[i].username_offset, list->creds[i].username_size );
988 else cred->UserName = NULL;
989 if (credentials) credentials[j++] = cred;
992 *len += offset;
993 *count += list->count;
994 ret = ERROR_SUCCESS;
996 done:
997 heap_free( list );
998 CloseHandle( mgr );
999 return ret;
1002 /******************************************************************************
1003 * CredEnumerateW [ADVAPI32.@]
1005 BOOL WINAPI CredEnumerateW(LPCWSTR Filter, DWORD Flags, DWORD *Count, PCREDENTIALW **Credentials)
1007 HKEY hkeyMgr;
1008 DWORD ret;
1009 LPWSTR target_name;
1010 DWORD target_name_len;
1011 DWORD len;
1012 char *buffer;
1013 BYTE key_data[KEY_SIZE];
1015 TRACE("(%s, 0x%x, %p, %p)\n", debugstr_w(Filter), Flags, Count, Credentials);
1017 if (Flags)
1019 SetLastError(ERROR_INVALID_FLAGS);
1020 return FALSE;
1023 ret = open_cred_mgr_key(&hkeyMgr, FALSE);
1024 if (ret != ERROR_SUCCESS)
1026 WARN("couldn't open/create manager key, error %d\n", ret);
1027 SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1028 return FALSE;
1031 ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
1032 if (ret != ERROR_SUCCESS)
1034 RegCloseKey(hkeyMgr);
1035 SetLastError(ret);
1036 return FALSE;
1039 ret = RegQueryInfoKeyW(hkeyMgr, NULL, NULL, NULL, NULL, &target_name_len, NULL, NULL, NULL, NULL, NULL, NULL);
1040 if (ret != ERROR_SUCCESS)
1042 RegCloseKey(hkeyMgr);
1043 SetLastError(ret);
1044 return FALSE;
1047 target_name = heap_alloc((target_name_len+1)*sizeof(WCHAR));
1048 if (!target_name)
1050 RegCloseKey(hkeyMgr);
1051 SetLastError(ERROR_OUTOFMEMORY);
1052 return FALSE;
1055 *Count = 0;
1056 len = 0;
1057 ret = registry_enumerate_credentials(hkeyMgr, Filter, target_name, target_name_len,
1058 key_data, NULL, NULL, &len, Count);
1059 if (ret == ERROR_SUCCESS)
1061 ret = host_enumerate_credentials(Filter, NULL, NULL, &len, Count);
1062 if (ret == ERROR_NOT_SUPPORTED) ret = ERROR_SUCCESS;
1064 if (ret == ERROR_SUCCESS && *Count == 0)
1065 ret = ERROR_NOT_FOUND;
1066 if (ret != ERROR_SUCCESS)
1068 heap_free(target_name);
1069 RegCloseKey(hkeyMgr);
1070 SetLastError(ret);
1071 return FALSE;
1073 len += *Count * sizeof(PCREDENTIALW);
1075 if (ret == ERROR_SUCCESS)
1077 buffer = heap_alloc(len);
1078 *Credentials = (PCREDENTIALW *)buffer;
1079 if (buffer)
1081 buffer += *Count * sizeof(PCREDENTIALW);
1082 *Count = 0;
1083 ret = registry_enumerate_credentials(hkeyMgr, Filter, target_name, target_name_len, key_data,
1084 *Credentials, &buffer, &len, Count);
1085 if (ret == ERROR_SUCCESS)
1087 ret = host_enumerate_credentials(Filter, *Credentials, buffer, &len, Count);
1088 if (ret == ERROR_NOT_SUPPORTED) ret = ERROR_SUCCESS;
1091 else ret = ERROR_OUTOFMEMORY;
1094 heap_free(target_name);
1095 RegCloseKey(hkeyMgr);
1097 if (ret != ERROR_SUCCESS)
1099 SetLastError(ret);
1100 return FALSE;
1102 return TRUE;
1105 /******************************************************************************
1106 * CredFree [ADVAPI32.@]
1108 VOID WINAPI CredFree(PVOID Buffer)
1110 heap_free(Buffer);
1113 /******************************************************************************
1114 * CredReadA [ADVAPI32.@]
1116 BOOL WINAPI CredReadA(LPCSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALA *Credential)
1118 LPWSTR TargetNameW;
1119 PCREDENTIALW CredentialW;
1120 INT len;
1122 TRACE("(%s, %d, 0x%x, %p)\n", debugstr_a(TargetName), Type, Flags, Credential);
1124 if (!TargetName)
1126 SetLastError(ERROR_INVALID_PARAMETER);
1127 return FALSE;
1130 len = MultiByteToWideChar(CP_ACP, 0, TargetName, -1, NULL, 0);
1131 TargetNameW = heap_alloc(len * sizeof(WCHAR));
1132 if (!TargetNameW)
1134 SetLastError(ERROR_OUTOFMEMORY);
1135 return FALSE;
1137 MultiByteToWideChar(CP_ACP, 0, TargetName, -1, TargetNameW, len);
1139 if (!CredReadW(TargetNameW, Type, Flags, &CredentialW))
1141 heap_free(TargetNameW);
1142 return FALSE;
1144 heap_free(TargetNameW);
1146 len = convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW, NULL, 0);
1147 *Credential = heap_alloc(len);
1148 if (!*Credential)
1150 SetLastError(ERROR_OUTOFMEMORY);
1151 return FALSE;
1153 convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW, *Credential, len);
1155 CredFree(CredentialW);
1157 return TRUE;
1160 static DWORD host_read_credential( const WCHAR *targetname, CREDENTIALW **ret_credential )
1162 struct mountmgr_credential *cred_in, *cred_out = NULL, *tmp;
1163 DWORD err = ERROR_OUTOFMEMORY, size_in, size_out, size_name = (lstrlenW( targetname ) + 1) * sizeof(WCHAR);
1164 HANDLE mgr;
1165 WCHAR *ptr;
1166 BOOL ret;
1168 mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
1169 OPEN_EXISTING, 0, 0 );
1170 if (mgr == INVALID_HANDLE_VALUE) return GetLastError();
1172 size_in = sizeof(*cred_in) + size_name;
1173 if (!(cred_in = heap_alloc( size_in )))
1175 CloseHandle( mgr );
1176 return ERROR_OUTOFMEMORY;
1178 cred_in->targetname_offset = sizeof(*cred_in);
1179 cred_in->targetname_size = size_name;
1180 ptr = (WCHAR *)(cred_in + 1);
1181 lstrcpyW( ptr, targetname );
1183 size_out = 256;
1184 if (!(cred_out = heap_alloc( size_out ))) goto done;
1186 for (;;)
1188 ret = DeviceIoControl( mgr, IOCTL_MOUNTMGR_READ_CREDENTIAL, cred_in, size_in, cred_out, size_out, NULL, NULL );
1189 if (ret || (err = GetLastError()) != ERROR_MORE_DATA) break;
1190 size_out *= 2;
1191 if (!(tmp = heap_realloc( cred_out, size_out ))) goto done;
1192 cred_out = tmp;
1195 if (ret)
1197 CREDENTIALW *credential;
1198 DWORD size = sizeof(*credential) + cred_out->targetname_size + cred_out->username_size + cred_out->comment_size +
1199 cred_out->blob_size;
1201 if (!(credential = heap_alloc_zero( size )))
1203 err = ERROR_OUTOFMEMORY;
1204 goto done;
1206 ptr = (WCHAR *)(credential + 1);
1208 credential->Type = CRED_TYPE_DOMAIN_PASSWORD;
1209 memcpy( ptr, (char *)cred_out + cred_out->targetname_offset, cred_out->targetname_size );
1210 credential->TargetName = ptr;
1211 ptr += lstrlenW( ptr ) + 1;
1212 if (cred_out->comment_size)
1214 memcpy( ptr, (char *)cred_out + cred_out->comment_offset, cred_out->comment_size );
1215 credential->Comment = ptr;
1216 ptr += lstrlenW( ptr ) + 1;
1218 credential->LastWritten = cred_out->last_written;
1219 if ((credential->CredentialBlobSize = cred_out->blob_size))
1221 memcpy( ptr, (char *)cred_out + cred_out->blob_offset, cred_out->blob_size );
1222 credential->CredentialBlob = (BYTE *)ptr;
1223 ptr += cred_out->blob_size / sizeof(WCHAR);
1225 credential->Persist = CRED_PERSIST_LOCAL_MACHINE;
1226 memcpy( ptr, (char *)cred_out + cred_out->username_offset, cred_out->username_size );
1227 credential->UserName = ptr;
1229 *ret_credential = credential;
1230 err = ERROR_SUCCESS;
1233 done:
1234 heap_free( cred_in );
1235 heap_free( cred_out );
1236 CloseHandle( mgr );
1237 return err;
1240 /******************************************************************************
1241 * CredReadW [ADVAPI32.@]
1243 BOOL WINAPI CredReadW(LPCWSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALW *Credential)
1245 HKEY hkeyMgr;
1246 HKEY hkeyCred;
1247 DWORD ret;
1248 LPWSTR key_name;
1249 DWORD len;
1250 BYTE key_data[KEY_SIZE];
1252 TRACE("(%s, %d, 0x%x, %p)\n", debugstr_w(TargetName), Type, Flags, Credential);
1254 if (!TargetName)
1256 SetLastError(ERROR_INVALID_PARAMETER);
1257 return FALSE;
1260 if (Type != CRED_TYPE_GENERIC && Type != CRED_TYPE_DOMAIN_PASSWORD)
1262 FIXME("unhandled type %d\n", Type);
1263 SetLastError(ERROR_INVALID_PARAMETER);
1264 return FALSE;
1267 if (Flags)
1269 FIXME("unhandled flags 0x%x\n", Flags);
1270 SetLastError(ERROR_INVALID_FLAGS);
1271 return FALSE;
1274 if (Type == CRED_TYPE_DOMAIN_PASSWORD)
1276 ret = host_read_credential( TargetName, Credential );
1277 if (ret != ERROR_SUCCESS && ret != ERROR_NOT_SUPPORTED)
1279 SetLastError(ret);
1280 return FALSE;
1282 if (ret == ERROR_SUCCESS) return TRUE;
1285 ret = open_cred_mgr_key(&hkeyMgr, FALSE);
1286 if (ret != ERROR_SUCCESS)
1288 WARN("couldn't open/create manager key, error %d\n", ret);
1289 SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1290 return FALSE;
1293 ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
1294 if (ret != ERROR_SUCCESS)
1296 RegCloseKey(hkeyMgr);
1297 SetLastError(ret);
1298 return FALSE;
1301 key_name = get_key_name_for_target(TargetName, Type);
1302 ret = RegOpenKeyExW(hkeyMgr, key_name, 0, KEY_QUERY_VALUE, &hkeyCred);
1303 heap_free(key_name);
1304 if (ret != ERROR_SUCCESS)
1306 TRACE("credentials for target name %s not found\n", debugstr_w(TargetName));
1307 SetLastError(ERROR_NOT_FOUND);
1308 return FALSE;
1311 len = sizeof(**Credential);
1312 ret = registry_read_credential(hkeyCred, NULL, key_data, NULL, &len);
1313 if (ret == ERROR_SUCCESS)
1315 *Credential = heap_alloc(len);
1316 if (*Credential)
1318 len = sizeof(**Credential);
1319 ret = registry_read_credential(hkeyCred, *Credential, key_data,
1320 (char *)(*Credential + 1), &len);
1322 else
1323 ret = ERROR_OUTOFMEMORY;
1326 RegCloseKey(hkeyCred);
1327 RegCloseKey(hkeyMgr);
1329 if (ret != ERROR_SUCCESS)
1331 SetLastError(ret);
1332 return FALSE;
1334 return TRUE;
1337 /******************************************************************************
1338 * CredReadDomainCredentialsA [ADVAPI32.@]
1340 BOOL WINAPI CredReadDomainCredentialsA(PCREDENTIAL_TARGET_INFORMATIONA TargetInformation,
1341 DWORD Flags, DWORD *Size, PCREDENTIALA **Credentials)
1343 PCREDENTIAL_TARGET_INFORMATIONW TargetInformationW;
1344 INT len;
1345 DWORD i;
1346 WCHAR *buffer, *end;
1347 BOOL ret;
1348 PCREDENTIALW* CredentialsW;
1350 TRACE("(%p, 0x%x, %p, %p)\n", TargetInformation, Flags, Size, Credentials);
1352 /* follow Windows behavior - do not test for NULL, initialize early */
1353 *Size = 0;
1354 *Credentials = NULL;
1356 if (!TargetInformation)
1358 SetLastError(ERROR_INVALID_PARAMETER);
1359 return FALSE;
1362 len = sizeof(*TargetInformationW);
1363 if (TargetInformation->TargetName)
1364 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->TargetName, -1, NULL, 0) * sizeof(WCHAR);
1365 if (TargetInformation->NetbiosServerName)
1366 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosServerName, -1, NULL, 0) * sizeof(WCHAR);
1367 if (TargetInformation->DnsServerName)
1368 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsServerName, -1, NULL, 0) * sizeof(WCHAR);
1369 if (TargetInformation->NetbiosDomainName)
1370 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosDomainName, -1, NULL, 0) * sizeof(WCHAR);
1371 if (TargetInformation->DnsDomainName)
1372 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsDomainName, -1, NULL, 0) * sizeof(WCHAR);
1373 if (TargetInformation->DnsTreeName)
1374 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsTreeName, -1, NULL, 0) * sizeof(WCHAR);
1375 if (TargetInformation->PackageName)
1376 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->PackageName, -1, NULL, 0) * sizeof(WCHAR);
1378 TargetInformationW = heap_alloc(len);
1379 if (!TargetInformationW)
1381 SetLastError(ERROR_OUTOFMEMORY);
1382 return FALSE;
1384 buffer = (WCHAR*)(TargetInformationW + 1);
1385 end = (WCHAR *)((char *)TargetInformationW + len);
1387 if (TargetInformation->TargetName)
1389 TargetInformationW->TargetName = buffer;
1390 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->TargetName, -1,
1391 TargetInformationW->TargetName, end - buffer);
1392 } else
1393 TargetInformationW->TargetName = NULL;
1395 if (TargetInformation->NetbiosServerName)
1397 TargetInformationW->NetbiosServerName = buffer;
1398 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosServerName, -1,
1399 TargetInformationW->NetbiosServerName, end - buffer);
1400 } else
1401 TargetInformationW->NetbiosServerName = NULL;
1403 if (TargetInformation->DnsServerName)
1405 TargetInformationW->DnsServerName = buffer;
1406 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsServerName, -1,
1407 TargetInformationW->DnsServerName, end - buffer);
1408 } else
1409 TargetInformationW->DnsServerName = NULL;
1411 if (TargetInformation->NetbiosDomainName)
1413 TargetInformationW->NetbiosDomainName = buffer;
1414 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosDomainName, -1,
1415 TargetInformationW->NetbiosDomainName, end - buffer);
1416 } else
1417 TargetInformationW->NetbiosDomainName = NULL;
1419 if (TargetInformation->DnsDomainName)
1421 TargetInformationW->DnsDomainName = buffer;
1422 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsDomainName, -1,
1423 TargetInformationW->DnsDomainName, end - buffer);
1424 } else
1425 TargetInformationW->DnsDomainName = NULL;
1427 if (TargetInformation->DnsTreeName)
1429 TargetInformationW->DnsTreeName = buffer;
1430 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsTreeName, -1,
1431 TargetInformationW->DnsTreeName, end - buffer);
1432 } else
1433 TargetInformationW->DnsTreeName = NULL;
1435 if (TargetInformation->PackageName)
1437 TargetInformationW->PackageName = buffer;
1438 MultiByteToWideChar(CP_ACP, 0, TargetInformation->PackageName, -1,
1439 TargetInformationW->PackageName, end - buffer);
1440 } else
1441 TargetInformationW->PackageName = NULL;
1443 TargetInformationW->Flags = TargetInformation->Flags;
1444 TargetInformationW->CredTypeCount = TargetInformation->CredTypeCount;
1445 TargetInformationW->CredTypes = TargetInformation->CredTypes;
1447 ret = CredReadDomainCredentialsW(TargetInformationW, Flags, Size, &CredentialsW);
1449 heap_free(TargetInformationW);
1451 if (ret)
1453 char *buf;
1454 INT needed;
1456 len = *Size * sizeof(PCREDENTIALA);
1457 for (i = 0; i < *Size; i++)
1458 len += convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], NULL, 0);
1460 *Credentials = heap_alloc(len);
1461 if (!*Credentials)
1463 CredFree(CredentialsW);
1464 SetLastError(ERROR_OUTOFMEMORY);
1465 return FALSE;
1468 buf = (char *)&(*Credentials)[*Size];
1469 len -= *Size * sizeof(PCREDENTIALA);
1470 for (i = 0; i < *Size; i++)
1472 (*Credentials)[i] = (PCREDENTIALA)buf;
1473 needed = convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], (*Credentials)[i], len);
1474 buf += needed;
1475 len -= needed;
1478 CredFree(CredentialsW);
1480 return ret;
1483 /******************************************************************************
1484 * CredReadDomainCredentialsW [ADVAPI32.@]
1486 BOOL WINAPI CredReadDomainCredentialsW(PCREDENTIAL_TARGET_INFORMATIONW TargetInformation, DWORD Flags,
1487 DWORD *Size, PCREDENTIALW **Credentials)
1489 FIXME("(%p, 0x%x, %p, %p) stub\n", TargetInformation, Flags, Size, Credentials);
1491 /* follow Windows behavior - do not test for NULL, initialize early */
1492 *Size = 0;
1493 *Credentials = NULL;
1494 if (!TargetInformation)
1496 SetLastError(ERROR_INVALID_PARAMETER);
1497 return FALSE;
1500 SetLastError(ERROR_NOT_FOUND);
1501 return FALSE;
1504 /******************************************************************************
1505 * CredWriteA [ADVAPI32.@]
1507 BOOL WINAPI CredWriteA(PCREDENTIALA Credential, DWORD Flags)
1509 BOOL ret;
1510 INT len;
1511 PCREDENTIALW CredentialW;
1513 TRACE("(%p, 0x%x)\n", Credential, Flags);
1515 if (!Credential || !Credential->TargetName)
1517 SetLastError(ERROR_INVALID_PARAMETER);
1518 return FALSE;
1521 len = convert_PCREDENTIALA_to_PCREDENTIALW(Credential, NULL, 0);
1522 CredentialW = heap_alloc(len);
1523 if (!CredentialW)
1525 SetLastError(ERROR_OUTOFMEMORY);
1526 return FALSE;
1529 convert_PCREDENTIALA_to_PCREDENTIALW(Credential, CredentialW, len);
1531 ret = CredWriteW(CredentialW, Flags);
1533 heap_free(CredentialW);
1535 return ret;
1538 /******************************************************************************
1539 * CredWriteW [ADVAPI32.@]
1541 BOOL WINAPI CredWriteW(PCREDENTIALW Credential, DWORD Flags)
1543 HKEY hkeyMgr;
1544 HKEY hkeyCred;
1545 DWORD ret;
1546 LPWSTR key_name;
1547 BYTE key_data[KEY_SIZE];
1549 TRACE("(%p, 0x%x)\n", Credential, Flags);
1551 if (!Credential || !Credential->TargetName)
1553 SetLastError(ERROR_INVALID_PARAMETER);
1554 return FALSE;
1557 if (Flags & ~CRED_PRESERVE_CREDENTIAL_BLOB)
1559 FIXME("unhandled flags 0x%x\n", Flags);
1560 SetLastError(ERROR_INVALID_FLAGS);
1561 return FALSE;
1564 if (Credential->Type != CRED_TYPE_GENERIC && Credential->Type != CRED_TYPE_DOMAIN_PASSWORD)
1566 FIXME("unhandled type %d\n", Credential->Type);
1567 SetLastError(ERROR_INVALID_PARAMETER);
1568 return FALSE;
1571 TRACE("Credential->Flags = 0x%08x\n", Credential->Flags);
1572 TRACE("Credential->Type = %u\n", Credential->Type);
1573 TRACE("Credential->TargetName = %s\n", debugstr_w(Credential->TargetName));
1574 TRACE("Credential->Comment = %s\n", debugstr_w(Credential->Comment));
1575 TRACE("Credential->Persist = %u\n", Credential->Persist);
1576 TRACE("Credential->TargetAlias = %s\n", debugstr_w(Credential->TargetAlias));
1577 TRACE("Credential->UserName = %s\n", debugstr_w(Credential->UserName));
1579 if (Credential->Type == CRED_TYPE_DOMAIN_PASSWORD)
1581 if (!Credential->UserName ||
1582 (Credential->Persist == CRED_PERSIST_ENTERPRISE &&
1583 (!wcschr(Credential->UserName, '\\') && !wcschr(Credential->UserName, '@'))))
1585 ERR("bad username %s\n", debugstr_w(Credential->UserName));
1586 SetLastError(ERROR_BAD_USERNAME);
1587 return FALSE;
1591 if (!Credential->AttributeCount &&
1592 Credential->Type == CRED_TYPE_DOMAIN_PASSWORD &&
1593 (Credential->Persist == CRED_PERSIST_LOCAL_MACHINE || Credential->Persist == CRED_PERSIST_ENTERPRISE))
1595 ret = host_write_credential(Credential, Flags & CRED_PRESERVE_CREDENTIAL_BLOB);
1596 if (ret != ERROR_SUCCESS && ret != ERROR_NOT_SUPPORTED)
1598 SetLastError(ret);
1599 return FALSE;
1601 if (ret == ERROR_SUCCESS) return TRUE;
1604 ret = open_cred_mgr_key(&hkeyMgr, FALSE);
1605 if (ret != ERROR_SUCCESS)
1607 WARN("couldn't open/create manager key, error %d\n", ret);
1608 SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1609 return FALSE;
1612 ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
1613 if (ret != ERROR_SUCCESS)
1615 RegCloseKey(hkeyMgr);
1616 SetLastError(ret);
1617 return FALSE;
1620 key_name = get_key_name_for_target(Credential->TargetName, Credential->Type);
1621 ret = RegCreateKeyExW(hkeyMgr, key_name, 0, NULL,
1622 Credential->Persist == CRED_PERSIST_SESSION ? REG_OPTION_VOLATILE : REG_OPTION_NON_VOLATILE,
1623 KEY_READ|KEY_WRITE, NULL, &hkeyCred, NULL);
1624 heap_free(key_name);
1625 if (ret != ERROR_SUCCESS)
1627 TRACE("credentials for target name %s not found\n",
1628 debugstr_w(Credential->TargetName));
1629 SetLastError(ERROR_NOT_FOUND);
1630 return FALSE;
1633 ret = registry_write_credential(hkeyCred, Credential, key_data,
1634 Flags & CRED_PRESERVE_CREDENTIAL_BLOB);
1636 RegCloseKey(hkeyCred);
1637 RegCloseKey(hkeyMgr);
1639 if (ret != ERROR_SUCCESS)
1641 SetLastError(ret);
1642 return FALSE;
1644 return TRUE;
1647 /******************************************************************************
1648 * CredGetSessionTypes [ADVAPI32.@]
1650 WINADVAPI BOOL WINAPI CredGetSessionTypes(DWORD persistCount, LPDWORD persists)
1652 TRACE("(%u, %p)\n", persistCount, persists);
1654 memset(persists, CRED_PERSIST_NONE, persistCount*sizeof(*persists));
1655 if (CRED_TYPE_GENERIC < persistCount)
1657 persists[CRED_TYPE_GENERIC] = CRED_PERSIST_ENTERPRISE;
1659 if (CRED_TYPE_DOMAIN_PASSWORD < persistCount)
1661 persists[CRED_TYPE_DOMAIN_PASSWORD] = CRED_PERSIST_ENTERPRISE;
1664 return TRUE;
1667 /******************************************************************************
1668 * CredMarshalCredentialA [ADVAPI32.@]
1670 BOOL WINAPI CredMarshalCredentialA( CRED_MARSHAL_TYPE type, PVOID cred, LPSTR *out )
1672 BOOL ret;
1673 WCHAR *outW;
1675 TRACE("%u, %p, %p\n", type, cred, out);
1677 if ((ret = CredMarshalCredentialW( type, cred, &outW )))
1679 int len = WideCharToMultiByte( CP_ACP, 0, outW, -1, NULL, 0, NULL, NULL );
1680 if (!(*out = heap_alloc( len )))
1682 heap_free( outW );
1683 return FALSE;
1685 WideCharToMultiByte( CP_ACP, 0, outW, -1, *out, len, NULL, NULL );
1686 heap_free( outW );
1688 return ret;
1691 static UINT cred_encode( const char *bin, unsigned int len, WCHAR *cred )
1693 static const char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#-";
1694 UINT n = 0, x;
1696 while (len > 0)
1698 cred[n++] = enc[bin[0] & 0x3f];
1699 x = (bin[0] & 0xc0) >> 6;
1700 if (len == 1)
1702 cred[n++] = enc[x];
1703 break;
1705 cred[n++] = enc[((bin[1] & 0xf) << 2) | x];
1706 x = (bin[1] & 0xf0) >> 4;
1707 if (len == 2)
1709 cred[n++] = enc[x];
1710 break;
1712 cred[n++] = enc[((bin[2] & 0x3) << 4) | x];
1713 cred[n++] = enc[(bin[2] & 0xfc) >> 2];
1714 bin += 3;
1715 len -= 3;
1717 return n;
1720 /******************************************************************************
1721 * CredMarshalCredentialW [ADVAPI32.@]
1723 BOOL WINAPI CredMarshalCredentialW( CRED_MARSHAL_TYPE type, PVOID cred, LPWSTR *out )
1725 CERT_CREDENTIAL_INFO *cert = cred;
1726 USERNAME_TARGET_CREDENTIAL_INFO *target = cred;
1727 DWORD len, size;
1728 WCHAR *p;
1730 TRACE("%u, %p, %p\n", type, cred, out);
1732 if (!cred || (type == CertCredential && cert->cbSize < sizeof(*cert)) ||
1733 (type != CertCredential && type != UsernameTargetCredential && type != BinaryBlobCredential) ||
1734 (type == UsernameTargetCredential && (!target->UserName || !target->UserName[0])))
1736 SetLastError( ERROR_INVALID_PARAMETER );
1737 return FALSE;
1739 switch (type)
1741 case CertCredential:
1743 size = (sizeof(cert->rgbHashOfCert) + 2) * 4 / 3;
1744 if (!(p = heap_alloc( (size + 4) * sizeof(WCHAR) ))) return FALSE;
1745 p[0] = '@';
1746 p[1] = '@';
1747 p[2] = 'A' + type;
1748 len = cred_encode( (const char *)cert->rgbHashOfCert, sizeof(cert->rgbHashOfCert), p + 3 );
1749 p[len + 3] = 0;
1750 break;
1752 case UsernameTargetCredential:
1754 len = lstrlenW( target->UserName );
1755 size = (sizeof(DWORD) + len * sizeof(WCHAR) + 2) * 4 / 3;
1756 if (!(p = heap_alloc( (size + 4) * sizeof(WCHAR) ))) return FALSE;
1757 p[0] = '@';
1758 p[1] = '@';
1759 p[2] = 'A' + type;
1760 size = len * sizeof(WCHAR);
1761 len = cred_encode( (const char *)&size, sizeof(DWORD), p + 3 );
1762 len += cred_encode( (const char *)target->UserName, size, p + 3 + len );
1763 p[len + 3] = 0;
1764 break;
1766 case BinaryBlobCredential:
1767 FIXME("BinaryBlobCredential not implemented\n");
1768 return FALSE;
1769 default:
1770 return FALSE;
1772 *out = p;
1773 return TRUE;
1776 /******************************************************************************
1777 * CredUnmarshalCredentialA [ADVAPI32.@]
1779 BOOL WINAPI CredUnmarshalCredentialA( LPCSTR cred, PCRED_MARSHAL_TYPE type, PVOID *out )
1781 BOOL ret;
1782 WCHAR *credW = NULL;
1784 TRACE("%s, %p, %p\n", debugstr_a(cred), type, out);
1786 if (cred)
1788 int len = MultiByteToWideChar( CP_ACP, 0, cred, -1, NULL, 0 );
1789 if (!(credW = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
1790 MultiByteToWideChar( CP_ACP, 0, cred, -1, credW, len );
1792 ret = CredUnmarshalCredentialW( credW, type, out );
1793 heap_free( credW );
1794 return ret;
1797 static inline char char_decode( WCHAR c )
1799 if (c >= 'A' && c <= 'Z') return c - 'A';
1800 if (c >= 'a' && c <= 'z') return c - 'a' + 26;
1801 if (c >= '0' && c <= '9') return c - '0' + 52;
1802 if (c == '#') return 62;
1803 if (c == '-') return 63;
1804 return 64;
1807 static BOOL cred_decode( const WCHAR *cred, unsigned int len, char *buf )
1809 unsigned int i = 0;
1810 char c0, c1, c2, c3;
1811 const WCHAR *p = cred;
1813 while (len >= 4)
1815 if ((c0 = char_decode( p[0] )) > 63) return FALSE;
1816 if ((c1 = char_decode( p[1] )) > 63) return FALSE;
1817 if ((c2 = char_decode( p[2] )) > 63) return FALSE;
1818 if ((c3 = char_decode( p[3] )) > 63) return FALSE;
1820 buf[i + 0] = (c1 << 6) | c0;
1821 buf[i + 1] = (c2 << 4) | (c1 >> 2);
1822 buf[i + 2] = (c3 << 2) | (c2 >> 4);
1823 len -= 4;
1824 i += 3;
1825 p += 4;
1827 if (len == 3)
1829 if ((c0 = char_decode( p[0] )) > 63) return FALSE;
1830 if ((c1 = char_decode( p[1] )) > 63) return FALSE;
1831 if ((c2 = char_decode( p[2] )) > 63) return FALSE;
1833 buf[i + 0] = (c1 << 6) | c0;
1834 buf[i + 1] = (c2 << 4) | (c1 >> 2);
1836 else if (len == 2)
1838 if ((c0 = char_decode( p[0] )) > 63) return FALSE;
1839 if ((c1 = char_decode( p[1] )) > 63) return FALSE;
1841 buf[i + 0] = (c1 << 6) | c0;
1843 else if (len == 1)
1845 return FALSE;
1847 return TRUE;
1850 /******************************************************************************
1851 * CredUnmarshalCredentialW [ADVAPI32.@]
1853 BOOL WINAPI CredUnmarshalCredentialW( LPCWSTR cred, PCRED_MARSHAL_TYPE type, PVOID *out )
1855 unsigned int len, buflen;
1857 TRACE("%s, %p, %p\n", debugstr_w(cred), type, out);
1859 if (!cred || cred[0] != '@' || cred[1] != '@' ||
1860 char_decode( cred[2] ) > 63)
1862 SetLastError( ERROR_INVALID_PARAMETER );
1863 return FALSE;
1865 len = lstrlenW( cred + 3 );
1866 *type = char_decode( cred[2] );
1867 switch (*type)
1869 case CertCredential:
1871 char hash[CERT_HASH_LENGTH];
1872 CERT_CREDENTIAL_INFO *cert;
1874 if (len != 27 || !cred_decode( cred + 3, len, hash ))
1876 SetLastError( ERROR_INVALID_PARAMETER );
1877 return FALSE;
1879 if (!(cert = heap_alloc( sizeof(*cert) ))) return FALSE;
1880 memcpy( cert->rgbHashOfCert, hash, sizeof(cert->rgbHashOfCert) );
1881 cert->cbSize = sizeof(*cert);
1882 *out = cert;
1883 break;
1885 case UsernameTargetCredential:
1887 USERNAME_TARGET_CREDENTIAL_INFO *target;
1888 DWORD size;
1890 if (len < 9 || !cred_decode( cred + 3, 6, (char *)&size ) ||
1891 size % sizeof(WCHAR) || len - 6 != (size * 4 + 2) / 3)
1893 SetLastError( ERROR_INVALID_PARAMETER );
1894 return FALSE;
1896 buflen = sizeof(*target) + size + sizeof(WCHAR);
1897 if (!(target = heap_alloc( buflen ))) return FALSE;
1898 if (!cred_decode( cred + 9, len - 6, (char *)(target + 1) ))
1900 heap_free( target );
1901 return FALSE;
1903 target->UserName = (WCHAR *)(target + 1);
1904 target->UserName[size / sizeof(WCHAR)] = 0;
1905 *out = target;
1906 break;
1908 case BinaryBlobCredential:
1909 FIXME("BinaryBlobCredential not implemented\n");
1910 return FALSE;
1911 default:
1912 WARN("unhandled type %u\n", *type);
1913 SetLastError( ERROR_INVALID_PARAMETER );
1914 return FALSE;
1916 return TRUE;
1919 /******************************************************************************
1920 * CredIsMarshaledCredentialW [ADVAPI32.@]
1922 * Check, if the name parameter is a marshaled credential, hash or binary blob
1924 * PARAMS
1925 * name the name to check
1927 * RETURNS
1928 * TRUE: the name parameter is a marshaled credential, hash or binary blob
1929 * FALSE: the name is a plain username
1931 BOOL WINAPI CredIsMarshaledCredentialW(LPCWSTR name)
1933 TRACE("(%s)\n", debugstr_w(name));
1935 if (name && name[0] == '@' && name[1] == '@' && name[2] > 'A' && name[3])
1937 char hash[CERT_HASH_LENGTH];
1938 int len = lstrlenW(name + 3 );
1939 DWORD size;
1941 if ((name[2] - 'A') == CertCredential && (len == 27) && cred_decode(name + 3, len, hash))
1942 return TRUE;
1944 if (((name[2] - 'A') == UsernameTargetCredential) &&
1945 (len >= 9) && cred_decode(name + 3, 6, (char *)&size) && size)
1946 return TRUE;
1948 if ((name[2] - 'A') == BinaryBlobCredential)
1949 FIXME("BinaryBlobCredential not checked\n");
1951 if ((name[2] - 'A') > BinaryBlobCredential)
1952 TRACE("unknown type: %d\n", (name[2] - 'A'));
1955 SetLastError(ERROR_INVALID_PARAMETER);
1956 return FALSE;
1959 /******************************************************************************
1960 * CredIsMarshaledCredentialA [ADVAPI32.@]
1962 * See CredIsMarshaledCredentialW
1965 BOOL WINAPI CredIsMarshaledCredentialA(LPCSTR name)
1967 LPWSTR nameW = NULL;
1968 BOOL res;
1969 int len;
1971 TRACE("(%s)\n", debugstr_a(name));
1973 if (name)
1975 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
1976 nameW = heap_alloc(len * sizeof(WCHAR));
1977 MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, len);
1980 res = CredIsMarshaledCredentialW(nameW);
1981 heap_free(nameW);
1982 return res;