Revert tree-restructure attempt: r66583, r66582, r66581, r66578, sauf ntdll changes...
[reactos.git] / reactos / dll / win32 / advapi32 / wine / cred.c
1 /*
2 * Credential Management APIs
3 *
4 * Copyright 2007 Robert Shearman for CodeWeavers
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include <advapi32.h>
22
23 #include <wincred.h>
24
25 WINE_DEFAULT_DEBUG_CHANNEL(cred);
26
27 /* the size of the ARC4 key used to encrypt the password data */
28 #define KEY_SIZE 8
29
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};
33
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};
42
43 static DWORD read_credential_blob(HKEY hkey, const BYTE key_data[KEY_SIZE],
44 LPBYTE credential_blob,
45 DWORD *credential_blob_size)
46 {
47 DWORD ret;
48 DWORD type;
49
50 *credential_blob_size = 0;
51 ret = RegQueryValueExW(hkey, wszPasswordValue, 0, &type, NULL, credential_blob_size);
52 if (ret != ERROR_SUCCESS)
53 return ret;
54 else if (type != REG_BINARY)
55 return ERROR_REGISTRY_CORRUPT;
56 if (credential_blob)
57 {
58 struct ustring data;
59 struct ustring key;
60
61 ret = RegQueryValueExW(hkey, wszPasswordValue, 0, &type, credential_blob,
62 credential_blob_size);
63 if (ret != ERROR_SUCCESS)
64 return ret;
65 else if (type != REG_BINARY)
66 return ERROR_REGISTRY_CORRUPT;
67
68 key.Length = key.MaximumLength = KEY_SIZE;
69 key.Buffer = (unsigned char *)key_data;
70
71 data.Length = data.MaximumLength = *credential_blob_size;
72 data.Buffer = credential_blob;
73 SystemFunction032(&data, &key);
74 }
75 return ERROR_SUCCESS;
76 }
77
78 static DWORD registry_read_credential(HKEY hkey, PCREDENTIALW credential,
79 const BYTE key_data[KEY_SIZE],
80 char *buffer, DWORD *len)
81 {
82 DWORD type;
83 DWORD ret;
84 DWORD count;
85
86 ret = RegQueryValueExW(hkey, NULL, 0, &type, NULL, &count);
87 if (ret != ERROR_SUCCESS)
88 return ret;
89 else if (type != REG_SZ)
90 return ERROR_REGISTRY_CORRUPT;
91 *len += count;
92 if (credential)
93 {
94 credential->TargetName = (LPWSTR)buffer;
95 ret = RegQueryValueExW(hkey, NULL, 0, &type, (LPVOID)credential->TargetName,
96 &count);
97 if (ret != ERROR_SUCCESS)
98 return ret;
99 else if (type != REG_SZ)
100 return ERROR_REGISTRY_CORRUPT;
101 buffer += count;
102 }
103
104 ret = RegQueryValueExW(hkey, wszCommentValue, 0, &type, NULL, &count);
105 if (ret != ERROR_FILE_NOT_FOUND)
106 {
107 if (ret != ERROR_SUCCESS)
108 return ret;
109 else if (type != REG_SZ)
110 return ERROR_REGISTRY_CORRUPT;
111 *len += count;
112 }
113 if (credential)
114 {
115 credential->Comment = (LPWSTR)buffer;
116 ret = RegQueryValueExW(hkey, wszCommentValue, 0, &type, (LPVOID)credential->Comment,
117 &count);
118 if (ret == ERROR_FILE_NOT_FOUND)
119 credential->Comment = NULL;
120 else if (ret != ERROR_SUCCESS)
121 return ret;
122 else if (type != REG_SZ)
123 return ERROR_REGISTRY_CORRUPT;
124 else
125 buffer += count;
126 }
127
128 ret = RegQueryValueExW(hkey, wszTargetAliasValue, 0, &type, NULL, &count);
129 if (ret != ERROR_FILE_NOT_FOUND)
130 {
131 if (ret != ERROR_SUCCESS)
132 return ret;
133 else if (type != REG_SZ)
134 return ERROR_REGISTRY_CORRUPT;
135 *len += count;
136 }
137 if (credential)
138 {
139 credential->TargetAlias = (LPWSTR)buffer;
140 ret = RegQueryValueExW(hkey, wszTargetAliasValue, 0, &type, (LPVOID)credential->TargetAlias,
141 &count);
142 if (ret == ERROR_FILE_NOT_FOUND)
143 credential->TargetAlias = NULL;
144 else if (ret != ERROR_SUCCESS)
145 return ret;
146 else if (type != REG_SZ)
147 return ERROR_REGISTRY_CORRUPT;
148 else
149 buffer += count;
150 }
151
152 ret = RegQueryValueExW(hkey, wszUserNameValue, 0, &type, NULL, &count);
153 if (ret != ERROR_FILE_NOT_FOUND)
154 {
155 if (ret != ERROR_SUCCESS)
156 return ret;
157 else if (type != REG_SZ)
158 return ERROR_REGISTRY_CORRUPT;
159 *len += count;
160 }
161 if (credential)
162 {
163 credential->UserName = (LPWSTR)buffer;
164 ret = RegQueryValueExW(hkey, wszUserNameValue, 0, &type, (LPVOID)credential->UserName,
165 &count);
166 if (ret == ERROR_FILE_NOT_FOUND)
167 credential->UserName = NULL;
168 else if (ret != ERROR_SUCCESS)
169 return ret;
170 else if (type != REG_SZ)
171 return ERROR_REGISTRY_CORRUPT;
172 else
173 buffer += count;
174 }
175
176 ret = read_credential_blob(hkey, key_data, NULL, &count);
177 if (ret != ERROR_FILE_NOT_FOUND)
178 {
179 if (ret != ERROR_SUCCESS)
180 return ret;
181 *len += count;
182 }
183 if (credential)
184 {
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)
190 return ret;
191 credential->CredentialBlobSize = count;
192 }
193
194 /* FIXME: Attributes */
195 if (credential)
196 {
197 credential->AttributeCount = 0;
198 credential->Attributes = NULL;
199 }
200
201 if (!credential) return ERROR_SUCCESS;
202
203 count = sizeof(credential->Flags);
204 ret = RegQueryValueExW(hkey, wszFlagsValue, NULL, &type, (LPVOID)&credential->Flags,
205 &count);
206 if (ret != ERROR_SUCCESS)
207 return ret;
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,
212 &count);
213 if (ret != ERROR_SUCCESS)
214 return ret;
215 else if (type != REG_DWORD)
216 return ERROR_REGISTRY_CORRUPT;
217
218 count = sizeof(credential->LastWritten);
219 ret = RegQueryValueExW(hkey, wszLastWrittenValue, NULL, &type, (LPVOID)&credential->LastWritten,
220 &count);
221 if (ret != ERROR_SUCCESS)
222 return ret;
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,
227 &count);
228 if (ret == ERROR_SUCCESS && type != REG_DWORD)
229 return ERROR_REGISTRY_CORRUPT;
230 return ret;
231 }
232
233 #ifdef __APPLE__
234 static DWORD mac_read_credential_from_item(SecKeychainItemRef item, BOOL require_password,
235 PCREDENTIALW credential, char *buffer,
236 DWORD *len)
237 {
238 OSStatus status;
239 UInt32 i, cred_blob_len;
240 void *cred_blob;
241 WCHAR *user = NULL;
242 BOOL user_name_present = FALSE;
243 SecKeychainAttributeInfo info;
244 SecKeychainAttributeList *attr_list;
245 UInt32 info_tags[] = { kSecServiceItemAttr, kSecAccountItemAttr,
246 kSecCommentItemAttr, kSecCreationDateItemAttr };
247 info.count = sizeof(info_tags)/sizeof(info_tags[0]);
248 info.tag = info_tags;
249 info.format = NULL;
250 status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, &cred_blob_len, &cred_blob);
251 if (status == errSecAuthFailed && !require_password)
252 {
253 cred_blob_len = 0;
254 cred_blob = NULL;
255 status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, &cred_blob_len, NULL);
256 }
257 if (status != noErr)
258 {
259 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status);
260 return ERROR_NOT_FOUND;
261 }
262
263 for (i = 0; i < attr_list->count; i++)
264 if (attr_list->attr[i].tag == kSecAccountItemAttr && attr_list->attr[i].data)
265 {
266 user_name_present = TRUE;
267 break;
268 }
269 if (!user_name_present)
270 {
271 WARN("no kSecAccountItemAttr for item\n");
272 SecKeychainItemFreeAttributesAndData(attr_list, cred_blob);
273 return ERROR_NOT_FOUND;
274 }
275
276 if (buffer)
277 {
278 credential->Flags = 0;
279 credential->Type = CRED_TYPE_DOMAIN_PASSWORD;
280 credential->TargetName = NULL;
281 credential->Comment = NULL;
282 memset(&credential->LastWritten, 0, sizeof(credential->LastWritten));
283 credential->CredentialBlobSize = 0;
284 credential->CredentialBlob = NULL;
285 credential->Persist = CRED_PERSIST_LOCAL_MACHINE;
286 credential->AttributeCount = 0;
287 credential->Attributes = NULL;
288 credential->TargetAlias = NULL;
289 credential->UserName = NULL;
290 }
291 for (i = 0; i < attr_list->count; i++)
292 {
293 switch (attr_list->attr[i].tag)
294 {
295 case kSecServiceItemAttr:
296 TRACE("kSecServiceItemAttr: %.*s\n", (int)attr_list->attr[i].length,
297 (char *)attr_list->attr[i].data);
298 if (!attr_list->attr[i].data) continue;
299 if (buffer)
300 {
301 INT str_len;
302 credential->TargetName = (LPWSTR)buffer;
303 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
304 attr_list->attr[i].length, (LPWSTR)buffer, 0xffff);
305 credential->TargetName[str_len] = '\0';
306 buffer += (str_len + 1) * sizeof(WCHAR);
307 *len += (str_len + 1) * sizeof(WCHAR);
308 }
309 else
310 {
311 INT str_len;
312 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
313 attr_list->attr[i].length, NULL, 0);
314 *len += (str_len + 1) * sizeof(WCHAR);
315 }
316 break;
317 case kSecAccountItemAttr:
318 {
319 INT str_len;
320 TRACE("kSecAccountItemAttr: %.*s\n", (int)attr_list->attr[i].length,
321 (char *)attr_list->attr[i].data);
322 if (!attr_list->attr[i].data) continue;
323 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
324 attr_list->attr[i].length, NULL, 0);
325 user = heap_alloc((str_len + 1) * sizeof(WCHAR));
326 MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
327 attr_list->attr[i].length, user, str_len);
328 user[str_len] = '\0';
329 break;
330 }
331 case kSecCommentItemAttr:
332 TRACE("kSecCommentItemAttr: %.*s\n", (int)attr_list->attr[i].length,
333 (char *)attr_list->attr[i].data);
334 if (!attr_list->attr[i].data) continue;
335 if (buffer)
336 {
337 INT str_len;
338 credential->Comment = (LPWSTR)buffer;
339 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
340 attr_list->attr[i].length, (LPWSTR)buffer, 0xffff);
341 credential->Comment[str_len] = '\0';
342 buffer += (str_len + 1) * sizeof(WCHAR);
343 *len += (str_len + 1) * sizeof(WCHAR);
344 }
345 else
346 {
347 INT str_len;
348 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
349 attr_list->attr[i].length, NULL, 0);
350 *len += (str_len + 1) * sizeof(WCHAR);
351 }
352 break;
353 case kSecCreationDateItemAttr:
354 TRACE("kSecCreationDateItemAttr: %.*s\n", (int)attr_list->attr[i].length,
355 (char *)attr_list->attr[i].data);
356 if (buffer)
357 {
358 LARGE_INTEGER win_time;
359 struct tm tm;
360 time_t time;
361 memset(&tm, 0, sizeof(tm));
362 strptime(attr_list->attr[i].data, "%Y%m%d%H%M%SZ", &tm);
363 time = mktime(&tm);
364 RtlSecondsSince1970ToTime(time, &win_time);
365 credential->LastWritten.dwLowDateTime = win_time.u.LowPart;
366 credential->LastWritten.dwHighDateTime = win_time.u.HighPart;
367 }
368 break;
369 default:
370 FIXME("unhandled attribute %lu\n", attr_list->attr[i].tag);
371 break;
372 }
373 }
374
375 if (user)
376 {
377 INT str_len;
378 if (buffer)
379 credential->UserName = (LPWSTR)buffer;
380 str_len = strlenW(user);
381 *len += (str_len + 1) * sizeof(WCHAR);
382 if (buffer)
383 {
384 memcpy(buffer, user, (str_len + 1) * sizeof(WCHAR));
385 buffer += (str_len + 1) * sizeof(WCHAR);
386 TRACE("UserName = %s\n", debugstr_w(credential->UserName));
387 }
388 }
389 heap_free(user);
390
391 if (cred_blob)
392 {
393 if (buffer)
394 {
395 INT str_len;
396 credential->CredentialBlob = (BYTE *)buffer;
397 str_len = MultiByteToWideChar(CP_UTF8, 0, cred_blob, cred_blob_len,
398 (LPWSTR)buffer, 0xffff);
399 credential->CredentialBlobSize = str_len * sizeof(WCHAR);
400 *len += str_len * sizeof(WCHAR);
401 }
402 else
403 {
404 INT str_len;
405 str_len = MultiByteToWideChar(CP_UTF8, 0, cred_blob, cred_blob_len,
406 NULL, 0);
407 *len += str_len * sizeof(WCHAR);
408 }
409 }
410 SecKeychainItemFreeAttributesAndData(attr_list, cred_blob);
411 return ERROR_SUCCESS;
412 }
413 #endif
414
415 static DWORD write_credential_blob(HKEY hkey, LPCWSTR target_name, DWORD type,
416 const BYTE key_data[KEY_SIZE],
417 const BYTE *credential_blob, DWORD credential_blob_size)
418 {
419 LPBYTE encrypted_credential_blob;
420 struct ustring data;
421 struct ustring key;
422 DWORD ret;
423
424 key.Length = key.MaximumLength = KEY_SIZE;
425 key.Buffer = (unsigned char *)key_data;
426
427 encrypted_credential_blob = heap_alloc(credential_blob_size);
428 if (!encrypted_credential_blob) return ERROR_OUTOFMEMORY;
429
430 memcpy(encrypted_credential_blob, credential_blob, credential_blob_size);
431 data.Length = data.MaximumLength = credential_blob_size;
432 data.Buffer = encrypted_credential_blob;
433 SystemFunction032(&data, &key);
434
435 ret = RegSetValueExW(hkey, wszPasswordValue, 0, REG_BINARY, encrypted_credential_blob, credential_blob_size);
436 heap_free(encrypted_credential_blob);
437
438 return ret;
439 }
440
441 static DWORD registry_write_credential(HKEY hkey, const CREDENTIALW *credential,
442 const BYTE key_data[KEY_SIZE], BOOL preserve_blob)
443 {
444 DWORD ret;
445 FILETIME LastWritten;
446
447 GetSystemTimeAsFileTime(&LastWritten);
448
449 ret = RegSetValueExW(hkey, wszFlagsValue, 0, REG_DWORD, (const BYTE*)&credential->Flags,
450 sizeof(credential->Flags));
451 if (ret != ERROR_SUCCESS) return ret;
452 ret = RegSetValueExW(hkey, wszTypeValue, 0, REG_DWORD, (const BYTE*)&credential->Type,
453 sizeof(credential->Type));
454 if (ret != ERROR_SUCCESS) return ret;
455 ret = RegSetValueExW(hkey, NULL, 0, REG_SZ, (LPVOID)credential->TargetName,
456 sizeof(WCHAR)*(strlenW(credential->TargetName)+1));
457 if (ret != ERROR_SUCCESS) return ret;
458 if (credential->Comment)
459 {
460 ret = RegSetValueExW(hkey, wszCommentValue, 0, REG_SZ, (LPVOID)credential->Comment,
461 sizeof(WCHAR)*(strlenW(credential->Comment)+1));
462 if (ret != ERROR_SUCCESS) return ret;
463 }
464 ret = RegSetValueExW(hkey, wszLastWrittenValue, 0, REG_BINARY, (LPVOID)&LastWritten,
465 sizeof(LastWritten));
466 if (ret != ERROR_SUCCESS) return ret;
467 ret = RegSetValueExW(hkey, wszPersistValue, 0, REG_DWORD, (const BYTE*)&credential->Persist,
468 sizeof(credential->Persist));
469 if (ret != ERROR_SUCCESS) return ret;
470 /* FIXME: Attributes */
471 if (credential->TargetAlias)
472 {
473 ret = RegSetValueExW(hkey, wszTargetAliasValue, 0, REG_SZ, (LPVOID)credential->TargetAlias,
474 sizeof(WCHAR)*(strlenW(credential->TargetAlias)+1));
475 if (ret != ERROR_SUCCESS) return ret;
476 }
477 if (credential->UserName)
478 {
479 ret = RegSetValueExW(hkey, wszUserNameValue, 0, REG_SZ, (LPVOID)credential->UserName,
480 sizeof(WCHAR)*(strlenW(credential->UserName)+1));
481 if (ret != ERROR_SUCCESS) return ret;
482 }
483 if (!preserve_blob)
484 {
485 ret = write_credential_blob(hkey, credential->TargetName, credential->Type,
486 key_data, credential->CredentialBlob,
487 credential->CredentialBlobSize);
488 }
489 return ret;
490 }
491
492 #ifdef __APPLE__
493 static DWORD mac_write_credential(const CREDENTIALW *credential, BOOL preserve_blob)
494 {
495 OSStatus status;
496 SecKeychainItemRef keychain_item;
497 char *username, *password, *servername;
498 UInt32 userlen, pwlen, serverlen;
499 SecKeychainAttribute attrs[1];
500 SecKeychainAttributeList attr_list;
501
502 if (credential->Flags)
503 FIXME("Flags 0x%x not written\n", credential->Flags);
504 if (credential->Type != CRED_TYPE_DOMAIN_PASSWORD)
505 FIXME("credential type of %d not supported\n", credential->Type);
506 if (credential->Persist != CRED_PERSIST_LOCAL_MACHINE)
507 FIXME("persist value of %d not supported\n", credential->Persist);
508 if (credential->AttributeCount)
509 FIXME("custom attributes not supported\n");
510
511 userlen = WideCharToMultiByte(CP_UTF8, 0, credential->UserName, -1, NULL, 0, NULL, NULL);
512 username = heap_alloc(userlen * sizeof(*username));
513 WideCharToMultiByte(CP_UTF8, 0, credential->UserName, -1, username, userlen, NULL, NULL);
514
515 serverlen = WideCharToMultiByte(CP_UTF8, 0, credential->TargetName, -1, NULL, 0, NULL, NULL);
516 servername = heap_alloc(serverlen * sizeof(*servername));
517 WideCharToMultiByte(CP_UTF8, 0, credential->TargetName, -1, servername, serverlen, NULL, NULL);
518 pwlen = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)credential->CredentialBlob,
519 credential->CredentialBlobSize / sizeof(WCHAR), NULL, 0, NULL, NULL);
520 password = heap_alloc(pwlen * sizeof(*password));
521 WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)credential->CredentialBlob,
522 credential->CredentialBlobSize / sizeof(WCHAR), password, pwlen, NULL, NULL);
523
524 TRACE("adding server %s, username %s using Keychain\n", servername, username);
525 status = SecKeychainAddGenericPassword(NULL, strlen(servername), servername, strlen(username),
526 username, strlen(password), password, &keychain_item);
527 if (status != noErr)
528 ERR("SecKeychainAddGenericPassword returned %ld\n", status);
529 if (status == errSecDuplicateItem)
530 {
531 status = SecKeychainFindGenericPassword(NULL, strlen(servername), servername, strlen(username),
532 username, NULL, NULL, &keychain_item);
533 if (status != noErr)
534 ERR("SecKeychainFindGenericPassword returned %ld\n", status);
535 }
536 heap_free(username);
537 heap_free(servername);
538 if (status != noErr)
539 {
540 heap_free(password);
541 return ERROR_GEN_FAILURE;
542 }
543 if (credential->Comment)
544 {
545 attr_list.count = 1;
546 attr_list.attr = attrs;
547 attrs[0].tag = kSecCommentItemAttr;
548 attrs[0].length = WideCharToMultiByte(CP_UTF8, 0, credential->Comment, -1, NULL, 0, NULL, NULL);
549 if (attrs[0].length) attrs[0].length--;
550 attrs[0].data = heap_alloc(attrs[0].length);
551 WideCharToMultiByte(CP_UTF8, 0, credential->Comment, -1, attrs[0].data, attrs[0].length, NULL, NULL);
552 }
553 else
554 {
555 attr_list.count = 0;
556 attr_list.attr = NULL;
557 }
558 status = SecKeychainItemModifyAttributesAndData(keychain_item, &attr_list,
559 preserve_blob ? 0 : strlen(password),
560 preserve_blob ? NULL : password);
561 if (credential->Comment)
562 heap_free(attrs[0].data);
563 heap_free(password);
564 /* FIXME: set TargetAlias attribute */
565 CFRelease(keychain_item);
566 if (status != noErr)
567 return ERROR_GEN_FAILURE;
568 return ERROR_SUCCESS;
569 }
570 #endif
571
572 static DWORD open_cred_mgr_key(HKEY *hkey, BOOL open_for_write)
573 {
574 return RegCreateKeyExW(HKEY_CURRENT_USER, wszCredentialManagerKey, 0,
575 NULL, REG_OPTION_NON_VOLATILE,
576 KEY_READ | (open_for_write ? KEY_WRITE : 0), NULL, hkey, NULL);
577 }
578
579 static DWORD get_cred_mgr_encryption_key(HKEY hkeyMgr, BYTE key_data[KEY_SIZE])
580 {
581 static const BYTE my_key_data[KEY_SIZE] = { 0 };
582 DWORD type;
583 DWORD count;
584 FILETIME ft;
585 ULONG seed;
586 ULONG value;
587 DWORD ret;
588
589 memcpy(key_data, my_key_data, KEY_SIZE);
590
591 count = KEY_SIZE;
592 ret = RegQueryValueExW(hkeyMgr, wszEncryptionKeyValue, NULL, &type, key_data,
593 &count);
594 if (ret == ERROR_SUCCESS)
595 {
596 if (type != REG_BINARY)
597 return ERROR_REGISTRY_CORRUPT;
598 else
599 return ERROR_SUCCESS;
600 }
601 if (ret != ERROR_FILE_NOT_FOUND)
602 return ret;
603
604 GetSystemTimeAsFileTime(&ft);
605 seed = ft.dwLowDateTime;
606 value = RtlUniform(&seed);
607 *(DWORD *)key_data = value;
608 seed = ft.dwHighDateTime;
609 value = RtlUniform(&seed);
610 *(DWORD *)(key_data + 4) = value;
611
612 ret = RegSetValueExW(hkeyMgr, wszEncryptionKeyValue, 0, REG_BINARY,
613 key_data, KEY_SIZE);
614 if (ret == ERROR_ACCESS_DENIED)
615 {
616 ret = open_cred_mgr_key(&hkeyMgr, TRUE);
617 if (ret == ERROR_SUCCESS)
618 {
619 ret = RegSetValueExW(hkeyMgr, wszEncryptionKeyValue, 0, REG_BINARY,
620 key_data, KEY_SIZE);
621 RegCloseKey(hkeyMgr);
622 }
623 }
624 return ret;
625 }
626
627 static LPWSTR get_key_name_for_target(LPCWSTR target_name, DWORD type)
628 {
629 static const WCHAR wszGenericPrefix[] = {'G','e','n','e','r','i','c',':',' ',0};
630 static const WCHAR wszDomPasswdPrefix[] = {'D','o','m','P','a','s','s','w','d',':',' ',0};
631 INT len;
632 LPCWSTR prefix = NULL;
633 LPWSTR key_name, p;
634
635 len = strlenW(target_name);
636 if (type == CRED_TYPE_GENERIC)
637 {
638 prefix = wszGenericPrefix;
639 len += sizeof(wszGenericPrefix)/sizeof(wszGenericPrefix[0]);
640 }
641 else
642 {
643 prefix = wszDomPasswdPrefix;
644 len += sizeof(wszDomPasswdPrefix)/sizeof(wszDomPasswdPrefix[0]);
645 }
646
647 key_name = heap_alloc(len * sizeof(WCHAR));
648 if (!key_name) return NULL;
649
650 strcpyW(key_name, prefix);
651 strcatW(key_name, target_name);
652
653 for (p = key_name; *p; p++)
654 if (*p == '\\') *p = '_';
655
656 return key_name;
657 }
658
659 static BOOL registry_credential_matches_filter(HKEY hkeyCred, LPCWSTR filter)
660 {
661 LPWSTR target_name;
662 DWORD ret;
663 DWORD type;
664 DWORD count;
665 LPCWSTR p;
666
667 if (!filter) return TRUE;
668
669 ret = RegQueryValueExW(hkeyCred, NULL, 0, &type, NULL, &count);
670 if (ret != ERROR_SUCCESS)
671 return FALSE;
672 else if (type != REG_SZ)
673 return FALSE;
674
675 target_name = heap_alloc(count);
676 if (!target_name)
677 return FALSE;
678 ret = RegQueryValueExW(hkeyCred, NULL, 0, &type, (LPVOID)target_name, &count);
679 if (ret != ERROR_SUCCESS || type != REG_SZ)
680 {
681 heap_free(target_name);
682 return FALSE;
683 }
684
685 TRACE("comparing filter %s to target name %s\n", debugstr_w(filter),
686 debugstr_w(target_name));
687
688 p = strchrW(filter, '*');
689 ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, filter,
690 (p && !p[1] ? p - filter : -1), target_name,
691 (p && !p[1] ? p - filter : -1)) == CSTR_EQUAL;
692
693 heap_free(target_name);
694 return ret;
695 }
696
697 static DWORD registry_enumerate_credentials(HKEY hkeyMgr, LPCWSTR filter,
698 LPWSTR target_name,
699 DWORD target_name_len, const BYTE key_data[KEY_SIZE],
700 PCREDENTIALW *credentials, char **buffer,
701 DWORD *len, DWORD *count)
702 {
703 DWORD i;
704 DWORD ret;
705 for (i = 0;; i++)
706 {
707 HKEY hkeyCred;
708 ret = RegEnumKeyW(hkeyMgr, i, target_name, target_name_len+1);
709 if (ret == ERROR_NO_MORE_ITEMS)
710 {
711 ret = ERROR_SUCCESS;
712 break;
713 }
714 else if (ret != ERROR_SUCCESS)
715 continue;
716 TRACE("target_name = %s\n", debugstr_w(target_name));
717 ret = RegOpenKeyExW(hkeyMgr, target_name, 0, KEY_QUERY_VALUE, &hkeyCred);
718 if (ret != ERROR_SUCCESS)
719 continue;
720 if (!registry_credential_matches_filter(hkeyCred, filter))
721 {
722 RegCloseKey(hkeyCred);
723 continue;
724 }
725 if (buffer)
726 {
727 *len = sizeof(CREDENTIALW);
728 credentials[*count] = (PCREDENTIALW)*buffer;
729 }
730 else
731 *len += sizeof(CREDENTIALW);
732 ret = registry_read_credential(hkeyCred, buffer ? credentials[*count] : NULL,
733 key_data, buffer ? *buffer + sizeof(CREDENTIALW) : NULL,
734 len);
735 RegCloseKey(hkeyCred);
736 if (ret != ERROR_SUCCESS) break;
737 if (buffer) *buffer += *len;
738 (*count)++;
739 }
740 return ret;
741 }
742
743 #ifdef __APPLE__
744 static BOOL mac_credential_matches_filter(void *data, UInt32 data_len, const WCHAR *filter)
745 {
746 int len;
747 WCHAR *target_name;
748 const WCHAR *p;
749 BOOL ret;
750
751 if (!filter) return TRUE;
752
753 len = MultiByteToWideChar(CP_UTF8, 0, data, data_len, NULL, 0);
754 if (!(target_name = heap_alloc((len + 1) * sizeof(WCHAR)))) return FALSE;
755 MultiByteToWideChar(CP_UTF8, 0, data, data_len, target_name, len);
756 target_name[len] = 0;
757
758 TRACE("comparing filter %s to target name %s\n", debugstr_w(filter), debugstr_w(target_name));
759
760 p = strchrW(filter, '*');
761 ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, filter,
762 (p && !p[1] ? p - filter : -1), target_name,
763 (p && !p[1] ? p - filter : -1)) == CSTR_EQUAL;
764 heap_free(target_name);
765 return ret;
766 }
767
768 static DWORD mac_enumerate_credentials(LPCWSTR filter, PCREDENTIALW *credentials,
769 char *buffer, DWORD *len, DWORD *count)
770 {
771 SecKeychainSearchRef search;
772 SecKeychainItemRef item;
773 OSStatus status;
774 Boolean saved_user_interaction_allowed;
775 DWORD ret;
776
777 SecKeychainGetUserInteractionAllowed(&saved_user_interaction_allowed);
778 SecKeychainSetUserInteractionAllowed(false);
779
780 status = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, NULL, &search);
781 if (status == noErr)
782 {
783 while (SecKeychainSearchCopyNext(search, &item) == noErr)
784 {
785 SecKeychainAttributeInfo info;
786 SecKeychainAttributeList *attr_list;
787 UInt32 info_tags[] = { kSecServiceItemAttr };
788 BOOL match;
789
790 info.count = sizeof(info_tags)/sizeof(info_tags[0]);
791 info.tag = info_tags;
792 info.format = NULL;
793 status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, NULL, NULL);
794 if (status != noErr)
795 {
796 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status);
797 continue;
798 }
799 if (buffer)
800 {
801 *len = sizeof(CREDENTIALW);
802 credentials[*count] = (PCREDENTIALW)buffer;
803 }
804 else
805 *len += sizeof(CREDENTIALW);
806 if (attr_list->count != 1 || attr_list->attr[0].tag != kSecServiceItemAttr)
807 {
808 SecKeychainItemFreeAttributesAndData(attr_list, NULL);
809 continue;
810 }
811 TRACE("service item: %.*s\n", (int)attr_list->attr[0].length, (char *)attr_list->attr[0].data);
812 match = mac_credential_matches_filter(attr_list->attr[0].data, attr_list->attr[0].length, filter);
813 SecKeychainItemFreeAttributesAndData(attr_list, NULL);
814 if (!match) continue;
815 ret = mac_read_credential_from_item(item, FALSE,
816 buffer ? credentials[*count] : NULL,
817 buffer ? buffer + sizeof(CREDENTIALW) : NULL,
818 len);
819 CFRelease(item);
820 if (ret == ERROR_SUCCESS)
821 {
822 (*count)++;
823 if (buffer) buffer += *len;
824 }
825 }
826 CFRelease(search);
827 }
828 else
829 ERR("SecKeychainSearchCreateFromAttributes returned status %ld\n", status);
830 SecKeychainSetUserInteractionAllowed(saved_user_interaction_allowed);
831 return ERROR_SUCCESS;
832 }
833
834 static DWORD mac_delete_credential(LPCWSTR TargetName)
835 {
836 OSStatus status;
837 SecKeychainSearchRef search;
838 status = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, NULL, &search);
839 if (status == noErr)
840 {
841 SecKeychainItemRef item;
842 while (SecKeychainSearchCopyNext(search, &item) == noErr)
843 {
844 SecKeychainAttributeInfo info;
845 SecKeychainAttributeList *attr_list;
846 UInt32 info_tags[] = { kSecServiceItemAttr };
847 LPWSTR target_name;
848 INT str_len;
849 info.count = sizeof(info_tags)/sizeof(info_tags[0]);
850 info.tag = info_tags;
851 info.format = NULL;
852 status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, NULL, NULL);
853 if (status != noErr)
854 {
855 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status);
856 continue;
857 }
858 if (attr_list->count != 1 || attr_list->attr[0].tag != kSecServiceItemAttr)
859 {
860 CFRelease(item);
861 continue;
862 }
863 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, NULL, 0);
864 target_name = heap_alloc((str_len + 1) * sizeof(WCHAR));
865 MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, target_name, str_len);
866 /* nul terminate */
867 target_name[str_len] = '\0';
868 if (strcmpiW(TargetName, target_name))
869 {
870 CFRelease(item);
871 heap_free(target_name);
872 continue;
873 }
874 heap_free(target_name);
875 SecKeychainItemFreeAttributesAndData(attr_list, NULL);
876 SecKeychainItemDelete(item);
877 CFRelease(item);
878 CFRelease(search);
879
880 return ERROR_SUCCESS;
881 }
882 CFRelease(search);
883 }
884 return ERROR_NOT_FOUND;
885 }
886 #endif
887
888 /******************************************************************************
889 * convert_PCREDENTIALW_to_PCREDENTIALA [internal]
890 *
891 * convert a Credential struct from UNICODE to ANSI and return the needed size in Bytes
892 *
893 */
894
895 static INT convert_PCREDENTIALW_to_PCREDENTIALA(const CREDENTIALW *CredentialW, PCREDENTIALA CredentialA, DWORD len)
896 {
897 char *buffer;
898 INT string_len;
899 INT needed = sizeof(CREDENTIALA);
900
901 if (!CredentialA)
902 {
903 if (CredentialW->TargetName)
904 needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetName, -1, NULL, 0, NULL, NULL);
905 if (CredentialW->Comment)
906 needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->Comment, -1, NULL, 0, NULL, NULL);
907 needed += CredentialW->CredentialBlobSize;
908 if (CredentialW->TargetAlias)
909 needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetAlias, -1, NULL, 0, NULL, NULL);
910 if (CredentialW->UserName)
911 needed += WideCharToMultiByte(CP_ACP, 0, CredentialW->UserName, -1, NULL, 0, NULL, NULL);
912
913 return needed;
914 }
915
916
917 buffer = (char *)CredentialA + sizeof(CREDENTIALA);
918 len -= sizeof(CREDENTIALA);
919 CredentialA->Flags = CredentialW->Flags;
920 CredentialA->Type = CredentialW->Type;
921
922 if (CredentialW->TargetName)
923 {
924 CredentialA->TargetName = buffer;
925 string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetName, -1, buffer, len, NULL, NULL);
926 buffer += string_len;
927 needed += string_len;
928 len -= string_len;
929 }
930 else
931 CredentialA->TargetName = NULL;
932 if (CredentialW->Comment)
933 {
934 CredentialA->Comment = buffer;
935 string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->Comment, -1, buffer, len, NULL, NULL);
936 buffer += string_len;
937 needed += string_len;
938 len -= string_len;
939 }
940 else
941 CredentialA->Comment = NULL;
942 CredentialA->LastWritten = CredentialW->LastWritten;
943 CredentialA->CredentialBlobSize = CredentialW->CredentialBlobSize;
944 if (CredentialW->CredentialBlobSize && (CredentialW->CredentialBlobSize <= len))
945 {
946 CredentialA->CredentialBlob =(LPBYTE)buffer;
947 memcpy(CredentialA->CredentialBlob, CredentialW->CredentialBlob,
948 CredentialW->CredentialBlobSize);
949 buffer += CredentialW->CredentialBlobSize;
950 needed += CredentialW->CredentialBlobSize;
951 len -= CredentialW->CredentialBlobSize;
952 }
953 else
954 CredentialA->CredentialBlob = NULL;
955 CredentialA->Persist = CredentialW->Persist;
956 CredentialA->AttributeCount = 0;
957 CredentialA->Attributes = NULL; /* FIXME */
958 if (CredentialW->TargetAlias)
959 {
960 CredentialA->TargetAlias = buffer;
961 string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetAlias, -1, buffer, len, NULL, NULL);
962 buffer += string_len;
963 needed += string_len;
964 len -= string_len;
965 }
966 else
967 CredentialA->TargetAlias = NULL;
968 if (CredentialW->UserName)
969 {
970 CredentialA->UserName = buffer;
971 string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->UserName, -1, buffer, len, NULL, NULL);
972 needed += string_len;
973 }
974 else
975 CredentialA->UserName = NULL;
976
977 return needed;
978 }
979
980 /******************************************************************************
981 * convert_PCREDENTIALA_to_PCREDENTIALW [internal]
982 *
983 * convert a Credential struct from ANSI to UNICODE and return the needed size in Bytes
984 *
985 */
986 static INT convert_PCREDENTIALA_to_PCREDENTIALW(const CREDENTIALA *CredentialA, PCREDENTIALW CredentialW, INT len)
987 {
988 char *buffer;
989 INT string_len;
990 INT needed = sizeof(CREDENTIALW);
991
992 if (!CredentialW)
993 {
994 if (CredentialA->TargetName)
995 needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetName, -1, NULL, 0);
996 if (CredentialA->Comment)
997 needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->Comment, -1, NULL, 0);
998 needed += CredentialA->CredentialBlobSize;
999 if (CredentialA->TargetAlias)
1000 needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetAlias, -1, NULL, 0);
1001 if (CredentialA->UserName)
1002 needed += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->UserName, -1, NULL, 0);
1003
1004 return needed;
1005 }
1006
1007 buffer = (char *)CredentialW + sizeof(CREDENTIALW);
1008 len -= sizeof(CREDENTIALW);
1009 CredentialW->Flags = CredentialA->Flags;
1010 CredentialW->Type = CredentialA->Type;
1011 if (CredentialA->TargetName)
1012 {
1013 CredentialW->TargetName = (LPWSTR)buffer;
1014 string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetName, -1, CredentialW->TargetName, len / sizeof(WCHAR));
1015 buffer += sizeof(WCHAR) * string_len;
1016 needed += sizeof(WCHAR) * string_len;
1017 len -= sizeof(WCHAR) * string_len;
1018 }
1019 else
1020 CredentialW->TargetName = NULL;
1021 if (CredentialA->Comment)
1022 {
1023 CredentialW->Comment = (LPWSTR)buffer;
1024 string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->Comment, -1, CredentialW->Comment, len / sizeof(WCHAR));
1025 buffer += sizeof(WCHAR) * string_len;
1026 needed += sizeof(WCHAR) * string_len;
1027 len -= sizeof(WCHAR) * string_len;
1028 }
1029 else
1030 CredentialW->Comment = NULL;
1031 CredentialW->LastWritten = CredentialA->LastWritten;
1032 CredentialW->CredentialBlobSize = CredentialA->CredentialBlobSize;
1033 if (CredentialA->CredentialBlobSize)
1034 {
1035 CredentialW->CredentialBlob =(LPBYTE)buffer;
1036 memcpy(CredentialW->CredentialBlob, CredentialA->CredentialBlob,
1037 CredentialA->CredentialBlobSize);
1038 buffer += CredentialA->CredentialBlobSize;
1039 needed += CredentialA->CredentialBlobSize;
1040 len -= CredentialA->CredentialBlobSize;
1041 }
1042 else
1043 CredentialW->CredentialBlob = NULL;
1044 CredentialW->Persist = CredentialA->Persist;
1045 CredentialW->AttributeCount = 0;
1046 CredentialW->Attributes = NULL; /* FIXME */
1047 if (CredentialA->TargetAlias)
1048 {
1049 CredentialW->TargetAlias = (LPWSTR)buffer;
1050 string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetAlias, -1, CredentialW->TargetAlias, len / sizeof(WCHAR));
1051 buffer += sizeof(WCHAR) * string_len;
1052 needed += sizeof(WCHAR) * string_len;
1053 len -= sizeof(WCHAR) * string_len;
1054 }
1055 else
1056 CredentialW->TargetAlias = NULL;
1057 if (CredentialA->UserName)
1058 {
1059 CredentialW->UserName = (LPWSTR)buffer;
1060 string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->UserName, -1, CredentialW->UserName, len / sizeof(WCHAR));
1061 needed += sizeof(WCHAR) * string_len;
1062 }
1063 else
1064 CredentialW->UserName = NULL;
1065
1066 return needed;
1067 }
1068
1069 /******************************************************************************
1070 * CredDeleteA [ADVAPI32.@]
1071 */
1072 BOOL WINAPI CredDeleteA(LPCSTR TargetName, DWORD Type, DWORD Flags)
1073 {
1074 LPWSTR TargetNameW;
1075 DWORD len;
1076 BOOL ret;
1077
1078 TRACE("(%s, %d, 0x%x)\n", debugstr_a(TargetName), Type, Flags);
1079
1080 if (!TargetName)
1081 {
1082 SetLastError(ERROR_INVALID_PARAMETER);
1083 return FALSE;
1084 }
1085
1086 len = MultiByteToWideChar(CP_ACP, 0, TargetName, -1, NULL, 0);
1087 TargetNameW = heap_alloc(len * sizeof(WCHAR));
1088 if (!TargetNameW)
1089 {
1090 SetLastError(ERROR_OUTOFMEMORY);
1091 return FALSE;
1092 }
1093 MultiByteToWideChar(CP_ACP, 0, TargetName, -1, TargetNameW, len);
1094
1095 ret = CredDeleteW(TargetNameW, Type, Flags);
1096
1097 heap_free(TargetNameW);
1098
1099 return ret;
1100 }
1101
1102 /******************************************************************************
1103 * CredDeleteW [ADVAPI32.@]
1104 */
1105 BOOL WINAPI CredDeleteW(LPCWSTR TargetName, DWORD Type, DWORD Flags)
1106 {
1107 HKEY hkeyMgr;
1108 DWORD ret;
1109 LPWSTR key_name;
1110
1111 TRACE("(%s, %d, 0x%x)\n", debugstr_w(TargetName), Type, Flags);
1112
1113 if (!TargetName)
1114 {
1115 SetLastError(ERROR_INVALID_PARAMETER);
1116 return FALSE;
1117 }
1118
1119 if (Type != CRED_TYPE_GENERIC && Type != CRED_TYPE_DOMAIN_PASSWORD)
1120 {
1121 FIXME("unhandled type %d\n", Type);
1122 SetLastError(ERROR_INVALID_PARAMETER);
1123 return FALSE;
1124 }
1125
1126 if (Flags)
1127 {
1128 FIXME("unhandled flags 0x%x\n", Flags);
1129 SetLastError(ERROR_INVALID_FLAGS);
1130 return FALSE;
1131 }
1132
1133 #ifdef __APPLE__
1134 if (Type == CRED_TYPE_DOMAIN_PASSWORD)
1135 {
1136 ret = mac_delete_credential(TargetName);
1137 if (ret == ERROR_SUCCESS)
1138 return TRUE;
1139 }
1140 #endif
1141
1142 ret = open_cred_mgr_key(&hkeyMgr, TRUE);
1143 if (ret != ERROR_SUCCESS)
1144 {
1145 WARN("couldn't open/create manager key, error %d\n", ret);
1146 SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1147 return FALSE;
1148 }
1149
1150 key_name = get_key_name_for_target(TargetName, Type);
1151 ret = RegDeleteKeyW(hkeyMgr, key_name);
1152 heap_free(key_name);
1153 RegCloseKey(hkeyMgr);
1154 if (ret != ERROR_SUCCESS)
1155 {
1156 SetLastError(ERROR_NOT_FOUND);
1157 return FALSE;
1158 }
1159
1160 return TRUE;
1161 }
1162
1163 /******************************************************************************
1164 * CredEnumerateA [ADVAPI32.@]
1165 */
1166 BOOL WINAPI CredEnumerateA(LPCSTR Filter, DWORD Flags, DWORD *Count,
1167 PCREDENTIALA **Credentials)
1168 {
1169 LPWSTR FilterW;
1170 PCREDENTIALW *CredentialsW;
1171 DWORD i;
1172 INT len;
1173 INT needed;
1174 char *buffer;
1175
1176 TRACE("(%s, 0x%x, %p, %p)\n", debugstr_a(Filter), Flags, Count, Credentials);
1177
1178 if (Filter)
1179 {
1180 len = MultiByteToWideChar(CP_ACP, 0, Filter, -1, NULL, 0);
1181 FilterW = heap_alloc(len * sizeof(WCHAR));
1182 if (!FilterW)
1183 {
1184 SetLastError(ERROR_OUTOFMEMORY);
1185 return FALSE;
1186 }
1187 MultiByteToWideChar(CP_ACP, 0, Filter, -1, FilterW, len);
1188 }
1189 else
1190 FilterW = NULL;
1191
1192 if (!CredEnumerateW(FilterW, Flags, Count, &CredentialsW))
1193 {
1194 heap_free(FilterW);
1195 return FALSE;
1196 }
1197 heap_free(FilterW);
1198
1199 len = *Count * sizeof(PCREDENTIALA);
1200 for (i = 0; i < *Count; i++)
1201 len += convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], NULL, 0);
1202
1203 *Credentials = heap_alloc(len);
1204 if (!*Credentials)
1205 {
1206 CredFree(CredentialsW);
1207 SetLastError(ERROR_OUTOFMEMORY);
1208 return FALSE;
1209 }
1210
1211 buffer = (char *)&(*Credentials)[*Count];
1212 len -= *Count * sizeof(PCREDENTIALA);
1213 for (i = 0; i < *Count; i++)
1214 {
1215 (*Credentials)[i] = (PCREDENTIALA)buffer;
1216 needed = convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], (*Credentials)[i], len);
1217 buffer += needed;
1218 len -= needed;
1219 }
1220
1221 CredFree(CredentialsW);
1222
1223 return TRUE;
1224 }
1225
1226 /******************************************************************************
1227 * CredEnumerateW [ADVAPI32.@]
1228 */
1229 BOOL WINAPI CredEnumerateW(LPCWSTR Filter, DWORD Flags, DWORD *Count,
1230 PCREDENTIALW **Credentials)
1231 {
1232 HKEY hkeyMgr;
1233 DWORD ret;
1234 LPWSTR target_name;
1235 DWORD target_name_len;
1236 DWORD len;
1237 char *buffer;
1238 BYTE key_data[KEY_SIZE];
1239
1240 TRACE("(%s, 0x%x, %p, %p)\n", debugstr_w(Filter), Flags, Count, Credentials);
1241
1242 if (Flags)
1243 {
1244 SetLastError(ERROR_INVALID_FLAGS);
1245 return FALSE;
1246 }
1247
1248 ret = open_cred_mgr_key(&hkeyMgr, FALSE);
1249 if (ret != ERROR_SUCCESS)
1250 {
1251 WARN("couldn't open/create manager key, error %d\n", ret);
1252 SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1253 return FALSE;
1254 }
1255
1256 ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
1257 if (ret != ERROR_SUCCESS)
1258 {
1259 RegCloseKey(hkeyMgr);
1260 SetLastError(ret);
1261 return FALSE;
1262 }
1263
1264 ret = RegQueryInfoKeyW(hkeyMgr, NULL, NULL, NULL, NULL, &target_name_len, NULL, NULL, NULL, NULL, NULL, NULL);
1265 if (ret != ERROR_SUCCESS)
1266 {
1267 RegCloseKey(hkeyMgr);
1268 SetLastError(ret);
1269 return FALSE;
1270 }
1271
1272 target_name = heap_alloc((target_name_len+1)*sizeof(WCHAR));
1273 if (!target_name)
1274 {
1275 RegCloseKey(hkeyMgr);
1276 SetLastError(ERROR_OUTOFMEMORY);
1277 return FALSE;
1278 }
1279
1280 *Count = 0;
1281 len = 0;
1282 ret = registry_enumerate_credentials(hkeyMgr, Filter, target_name, target_name_len,
1283 key_data, NULL, NULL, &len, Count);
1284 #ifdef __APPLE__
1285 if (ret == ERROR_SUCCESS)
1286 ret = mac_enumerate_credentials(Filter, NULL, NULL, &len, Count);
1287 #endif
1288 if (ret == ERROR_SUCCESS && *Count == 0)
1289 ret = ERROR_NOT_FOUND;
1290 if (ret != ERROR_SUCCESS)
1291 {
1292 heap_free(target_name);
1293 RegCloseKey(hkeyMgr);
1294 SetLastError(ret);
1295 return FALSE;
1296 }
1297 len += *Count * sizeof(PCREDENTIALW);
1298
1299 if (ret == ERROR_SUCCESS)
1300 {
1301 buffer = heap_alloc(len);
1302 *Credentials = (PCREDENTIALW *)buffer;
1303 if (buffer)
1304 {
1305 buffer += *Count * sizeof(PCREDENTIALW);
1306 *Count = 0;
1307 ret = registry_enumerate_credentials(hkeyMgr, Filter, target_name,
1308 target_name_len, key_data,
1309 *Credentials, &buffer, &len,
1310 Count);
1311 #ifdef __APPLE__
1312 if (ret == ERROR_SUCCESS)
1313 ret = mac_enumerate_credentials(Filter, *Credentials,
1314 buffer, &len, Count);
1315 #endif
1316 }
1317 else
1318 ret = ERROR_OUTOFMEMORY;
1319 }
1320
1321 heap_free(target_name);
1322 RegCloseKey(hkeyMgr);
1323
1324 if (ret != ERROR_SUCCESS)
1325 {
1326 SetLastError(ret);
1327 return FALSE;
1328 }
1329 return TRUE;
1330 }
1331
1332 /******************************************************************************
1333 * CredFree [ADVAPI32.@]
1334 */
1335 VOID WINAPI CredFree(PVOID Buffer)
1336 {
1337 heap_free(Buffer);
1338 }
1339
1340 /******************************************************************************
1341 * CredReadA [ADVAPI32.@]
1342 */
1343 BOOL WINAPI CredReadA(LPCSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALA *Credential)
1344 {
1345 LPWSTR TargetNameW;
1346 PCREDENTIALW CredentialW;
1347 INT len;
1348
1349 TRACE("(%s, %d, 0x%x, %p)\n", debugstr_a(TargetName), Type, Flags, Credential);
1350
1351 if (!TargetName)
1352 {
1353 SetLastError(ERROR_INVALID_PARAMETER);
1354 return FALSE;
1355 }
1356
1357 len = MultiByteToWideChar(CP_ACP, 0, TargetName, -1, NULL, 0);
1358 TargetNameW = heap_alloc(len * sizeof(WCHAR));
1359 if (!TargetNameW)
1360 {
1361 SetLastError(ERROR_OUTOFMEMORY);
1362 return FALSE;
1363 }
1364 MultiByteToWideChar(CP_ACP, 0, TargetName, -1, TargetNameW, len);
1365
1366 if (!CredReadW(TargetNameW, Type, Flags, &CredentialW))
1367 {
1368 heap_free(TargetNameW);
1369 return FALSE;
1370 }
1371 heap_free(TargetNameW);
1372
1373 len = convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW, NULL, 0);
1374 *Credential = heap_alloc(len);
1375 if (!*Credential)
1376 {
1377 SetLastError(ERROR_OUTOFMEMORY);
1378 return FALSE;
1379 }
1380 convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW, *Credential, len);
1381
1382 CredFree(CredentialW);
1383
1384 return TRUE;
1385 }
1386
1387 /******************************************************************************
1388 * CredReadW [ADVAPI32.@]
1389 */
1390 BOOL WINAPI CredReadW(LPCWSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALW *Credential)
1391 {
1392 HKEY hkeyMgr;
1393 HKEY hkeyCred;
1394 DWORD ret;
1395 LPWSTR key_name;
1396 DWORD len;
1397 BYTE key_data[KEY_SIZE];
1398
1399 TRACE("(%s, %d, 0x%x, %p)\n", debugstr_w(TargetName), Type, Flags, Credential);
1400
1401 if (!TargetName)
1402 {
1403 SetLastError(ERROR_INVALID_PARAMETER);
1404 return FALSE;
1405 }
1406
1407 if (Type != CRED_TYPE_GENERIC && Type != CRED_TYPE_DOMAIN_PASSWORD)
1408 {
1409 FIXME("unhandled type %d\n", Type);
1410 SetLastError(ERROR_INVALID_PARAMETER);
1411 return FALSE;
1412 }
1413
1414 if (Flags)
1415 {
1416 FIXME("unhandled flags 0x%x\n", Flags);
1417 SetLastError(ERROR_INVALID_FLAGS);
1418 return FALSE;
1419 }
1420
1421 #ifdef __APPLE__
1422 if (Type == CRED_TYPE_DOMAIN_PASSWORD)
1423 {
1424 OSStatus status;
1425 SecKeychainSearchRef search;
1426 status = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, NULL, &search);
1427 if (status == noErr)
1428 {
1429 SecKeychainItemRef item;
1430 while (SecKeychainSearchCopyNext(search, &item) == noErr)
1431 {
1432 SecKeychainAttributeInfo info;
1433 SecKeychainAttributeList *attr_list;
1434 UInt32 info_tags[] = { kSecServiceItemAttr };
1435 LPWSTR target_name;
1436 INT str_len;
1437 info.count = sizeof(info_tags)/sizeof(info_tags[0]);
1438 info.tag = info_tags;
1439 info.format = NULL;
1440 status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, NULL, NULL);
1441 len = sizeof(**Credential);
1442 if (status != noErr)
1443 {
1444 WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status);
1445 continue;
1446 }
1447 if (attr_list->count != 1 || attr_list->attr[0].tag != kSecServiceItemAttr)
1448 {
1449 CFRelease(item);
1450 continue;
1451 }
1452 str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, NULL, 0);
1453 target_name = heap_alloc((str_len + 1) * sizeof(WCHAR));
1454 MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, target_name, str_len);
1455 /* nul terminate */
1456 target_name[str_len] = '\0';
1457 if (strcmpiW(TargetName, target_name))
1458 {
1459 CFRelease(item);
1460 heap_free(target_name);
1461 continue;
1462 }
1463 heap_free(target_name);
1464 SecKeychainItemFreeAttributesAndData(attr_list, NULL);
1465 ret = mac_read_credential_from_item(item, TRUE, NULL, NULL, &len);
1466 if (ret == ERROR_SUCCESS)
1467 {
1468 *Credential = heap_alloc(len);
1469 if (*Credential)
1470 {
1471 len = sizeof(**Credential);
1472 ret = mac_read_credential_from_item(item, TRUE, *Credential,
1473 (char *)(*Credential + 1), &len);
1474 }
1475 else
1476 ret = ERROR_OUTOFMEMORY;
1477 CFRelease(item);
1478 CFRelease(search);
1479 if (ret != ERROR_SUCCESS)
1480 {
1481 SetLastError(ret);
1482 return FALSE;
1483 }
1484 return TRUE;
1485 }
1486 CFRelease(item);
1487 }
1488 CFRelease(search);
1489 }
1490 }
1491 #endif
1492
1493 ret = open_cred_mgr_key(&hkeyMgr, FALSE);
1494 if (ret != ERROR_SUCCESS)
1495 {
1496 WARN("couldn't open/create manager key, error %d\n", ret);
1497 SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1498 return FALSE;
1499 }
1500
1501 ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
1502 if (ret != ERROR_SUCCESS)
1503 {
1504 RegCloseKey(hkeyMgr);
1505 SetLastError(ret);
1506 return FALSE;
1507 }
1508
1509 key_name = get_key_name_for_target(TargetName, Type);
1510 ret = RegOpenKeyExW(hkeyMgr, key_name, 0, KEY_QUERY_VALUE, &hkeyCred);
1511 heap_free(key_name);
1512 if (ret != ERROR_SUCCESS)
1513 {
1514 TRACE("credentials for target name %s not found\n", debugstr_w(TargetName));
1515 SetLastError(ERROR_NOT_FOUND);
1516 return FALSE;
1517 }
1518
1519 len = sizeof(**Credential);
1520 ret = registry_read_credential(hkeyCred, NULL, key_data, NULL, &len);
1521 if (ret == ERROR_SUCCESS)
1522 {
1523 *Credential = heap_alloc(len);
1524 if (*Credential)
1525 {
1526 len = sizeof(**Credential);
1527 ret = registry_read_credential(hkeyCred, *Credential, key_data,
1528 (char *)(*Credential + 1), &len);
1529 }
1530 else
1531 ret = ERROR_OUTOFMEMORY;
1532 }
1533
1534 RegCloseKey(hkeyCred);
1535 RegCloseKey(hkeyMgr);
1536
1537 if (ret != ERROR_SUCCESS)
1538 {
1539 SetLastError(ret);
1540 return FALSE;
1541 }
1542 return TRUE;
1543 }
1544
1545 /******************************************************************************
1546 * CredReadDomainCredentialsA [ADVAPI32.@]
1547 */
1548 BOOL WINAPI CredReadDomainCredentialsA(PCREDENTIAL_TARGET_INFORMATIONA TargetInformation,
1549 DWORD Flags, DWORD *Size, PCREDENTIALA **Credentials)
1550 {
1551 PCREDENTIAL_TARGET_INFORMATIONW TargetInformationW;
1552 INT len;
1553 DWORD i;
1554 WCHAR *buffer, *end;
1555 BOOL ret;
1556 PCREDENTIALW* CredentialsW;
1557
1558 TRACE("(%p, 0x%x, %p, %p)\n", TargetInformation, Flags, Size, Credentials);
1559
1560 /* follow Windows behavior - do not test for NULL, initialize early */
1561 *Size = 0;
1562 *Credentials = NULL;
1563
1564 if (!TargetInformation)
1565 {
1566 SetLastError(ERROR_INVALID_PARAMETER);
1567 return FALSE;
1568 }
1569
1570 len = sizeof(*TargetInformationW);
1571 if (TargetInformation->TargetName)
1572 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->TargetName, -1, NULL, 0) * sizeof(WCHAR);
1573 if (TargetInformation->NetbiosServerName)
1574 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosServerName, -1, NULL, 0) * sizeof(WCHAR);
1575 if (TargetInformation->DnsServerName)
1576 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsServerName, -1, NULL, 0) * sizeof(WCHAR);
1577 if (TargetInformation->NetbiosDomainName)
1578 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosDomainName, -1, NULL, 0) * sizeof(WCHAR);
1579 if (TargetInformation->DnsDomainName)
1580 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsDomainName, -1, NULL, 0) * sizeof(WCHAR);
1581 if (TargetInformation->DnsTreeName)
1582 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsTreeName, -1, NULL, 0) * sizeof(WCHAR);
1583 if (TargetInformation->PackageName)
1584 len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->PackageName, -1, NULL, 0) * sizeof(WCHAR);
1585
1586 TargetInformationW = heap_alloc(len);
1587 if (!TargetInformationW)
1588 {
1589 SetLastError(ERROR_OUTOFMEMORY);
1590 return FALSE;
1591 }
1592 buffer = (WCHAR*)(TargetInformationW + 1);
1593 end = (WCHAR *)((char *)TargetInformationW + len);
1594
1595 if (TargetInformation->TargetName)
1596 {
1597 TargetInformationW->TargetName = buffer;
1598 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->TargetName, -1,
1599 TargetInformationW->TargetName, end - buffer);
1600 } else
1601 TargetInformationW->TargetName = NULL;
1602
1603 if (TargetInformation->NetbiosServerName)
1604 {
1605 TargetInformationW->NetbiosServerName = buffer;
1606 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosServerName, -1,
1607 TargetInformationW->NetbiosServerName, end - buffer);
1608 } else
1609 TargetInformationW->NetbiosServerName = NULL;
1610
1611 if (TargetInformation->DnsServerName)
1612 {
1613 TargetInformationW->DnsServerName = buffer;
1614 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsServerName, -1,
1615 TargetInformationW->DnsServerName, end - buffer);
1616 } else
1617 TargetInformationW->DnsServerName = NULL;
1618
1619 if (TargetInformation->NetbiosDomainName)
1620 {
1621 TargetInformationW->NetbiosDomainName = buffer;
1622 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosDomainName, -1,
1623 TargetInformationW->NetbiosDomainName, end - buffer);
1624 } else
1625 TargetInformationW->NetbiosDomainName = NULL;
1626
1627 if (TargetInformation->DnsDomainName)
1628 {
1629 TargetInformationW->DnsDomainName = buffer;
1630 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsDomainName, -1,
1631 TargetInformationW->DnsDomainName, end - buffer);
1632 } else
1633 TargetInformationW->DnsDomainName = NULL;
1634
1635 if (TargetInformation->DnsTreeName)
1636 {
1637 TargetInformationW->DnsTreeName = buffer;
1638 buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsTreeName, -1,
1639 TargetInformationW->DnsTreeName, end - buffer);
1640 } else
1641 TargetInformationW->DnsTreeName = NULL;
1642
1643 if (TargetInformation->PackageName)
1644 {
1645 TargetInformationW->PackageName = buffer;
1646 MultiByteToWideChar(CP_ACP, 0, TargetInformation->PackageName, -1,
1647 TargetInformationW->PackageName, end - buffer);
1648 } else
1649 TargetInformationW->PackageName = NULL;
1650
1651 TargetInformationW->Flags = TargetInformation->Flags;
1652 TargetInformationW->CredTypeCount = TargetInformation->CredTypeCount;
1653 TargetInformationW->CredTypes = TargetInformation->CredTypes;
1654
1655 ret = CredReadDomainCredentialsW(TargetInformationW, Flags, Size, &CredentialsW);
1656
1657 heap_free(TargetInformationW);
1658
1659 if (ret)
1660 {
1661 char *buf;
1662 INT needed;
1663
1664 len = *Size * sizeof(PCREDENTIALA);
1665 for (i = 0; i < *Size; i++)
1666 len += convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], NULL, 0);
1667
1668 *Credentials = heap_alloc(len);
1669 if (!*Credentials)
1670 {
1671 CredFree(CredentialsW);
1672 SetLastError(ERROR_OUTOFMEMORY);
1673 return FALSE;
1674 }
1675
1676 buf = (char *)&(*Credentials)[*Size];
1677 len -= *Size * sizeof(PCREDENTIALA);
1678 for (i = 0; i < *Size; i++)
1679 {
1680 (*Credentials)[i] = (PCREDENTIALA)buf;
1681 needed = convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], (*Credentials)[i], len);
1682 buf += needed;
1683 len -= needed;
1684 }
1685
1686 CredFree(CredentialsW);
1687 }
1688 return ret;
1689 }
1690
1691 /******************************************************************************
1692 * CredReadDomainCredentialsW [ADVAPI32.@]
1693 */
1694 BOOL WINAPI CredReadDomainCredentialsW(PCREDENTIAL_TARGET_INFORMATIONW TargetInformation, DWORD Flags,
1695 DWORD *Size, PCREDENTIALW **Credentials)
1696 {
1697 FIXME("(%p, 0x%x, %p, %p) stub\n", TargetInformation, Flags, Size, Credentials);
1698
1699 /* follow Windows behavior - do not test for NULL, initialize early */
1700 *Size = 0;
1701 *Credentials = NULL;
1702 if (!TargetInformation)
1703 {
1704 SetLastError(ERROR_INVALID_PARAMETER);
1705 return FALSE;
1706 }
1707
1708 SetLastError(ERROR_NOT_FOUND);
1709 return FALSE;
1710 }
1711
1712 /******************************************************************************
1713 * CredWriteA [ADVAPI32.@]
1714 */
1715 BOOL WINAPI CredWriteA(PCREDENTIALA Credential, DWORD Flags)
1716 {
1717 BOOL ret;
1718 INT len;
1719 PCREDENTIALW CredentialW;
1720
1721 TRACE("(%p, 0x%x)\n", Credential, Flags);
1722
1723 if (!Credential || !Credential->TargetName)
1724 {
1725 SetLastError(ERROR_INVALID_PARAMETER);
1726 return FALSE;
1727 }
1728
1729 len = convert_PCREDENTIALA_to_PCREDENTIALW(Credential, NULL, 0);
1730 CredentialW = heap_alloc(len);
1731 if (!CredentialW)
1732 {
1733 SetLastError(ERROR_OUTOFMEMORY);
1734 return FALSE;
1735 }
1736
1737 convert_PCREDENTIALA_to_PCREDENTIALW(Credential, CredentialW, len);
1738
1739 ret = CredWriteW(CredentialW, Flags);
1740
1741 heap_free(CredentialW);
1742
1743 return ret;
1744 }
1745
1746 /******************************************************************************
1747 * CredWriteW [ADVAPI32.@]
1748 */
1749 BOOL WINAPI CredWriteW(PCREDENTIALW Credential, DWORD Flags)
1750 {
1751 HKEY hkeyMgr;
1752 HKEY hkeyCred;
1753 DWORD ret;
1754 LPWSTR key_name;
1755 BYTE key_data[KEY_SIZE];
1756
1757 TRACE("(%p, 0x%x)\n", Credential, Flags);
1758
1759 if (!Credential || !Credential->TargetName)
1760 {
1761 SetLastError(ERROR_INVALID_PARAMETER);
1762 return FALSE;
1763 }
1764
1765 if (Flags & ~CRED_PRESERVE_CREDENTIAL_BLOB)
1766 {
1767 FIXME("unhandled flags 0x%x\n", Flags);
1768 SetLastError(ERROR_INVALID_FLAGS);
1769 return FALSE;
1770 }
1771
1772 if (Credential->Type != CRED_TYPE_GENERIC && Credential->Type != CRED_TYPE_DOMAIN_PASSWORD)
1773 {
1774 FIXME("unhandled type %d\n", Credential->Type);
1775 SetLastError(ERROR_INVALID_PARAMETER);
1776 return FALSE;
1777 }
1778
1779 TRACE("Credential->Flags = 0x%08x\n", Credential->Flags);
1780 TRACE("Credential->Type = %u\n", Credential->Type);
1781 TRACE("Credential->TargetName = %s\n", debugstr_w(Credential->TargetName));
1782 TRACE("Credential->Comment = %s\n", debugstr_w(Credential->Comment));
1783 TRACE("Credential->Persist = %u\n", Credential->Persist);
1784 TRACE("Credential->TargetAlias = %s\n", debugstr_w(Credential->TargetAlias));
1785 TRACE("Credential->UserName = %s\n", debugstr_w(Credential->UserName));
1786
1787 if (Credential->Type == CRED_TYPE_DOMAIN_PASSWORD)
1788 {
1789 if (!Credential->UserName ||
1790 (Credential->Persist == CRED_PERSIST_ENTERPRISE &&
1791 (!strchrW(Credential->UserName, '\\') && !strchrW(Credential->UserName, '@'))))
1792 {
1793 ERR("bad username %s\n", debugstr_w(Credential->UserName));
1794 SetLastError(ERROR_BAD_USERNAME);
1795 return FALSE;
1796 }
1797 }
1798
1799 #ifdef __APPLE__
1800 if (!Credential->AttributeCount &&
1801 Credential->Type == CRED_TYPE_DOMAIN_PASSWORD &&
1802 (Credential->Persist == CRED_PERSIST_LOCAL_MACHINE || Credential->Persist == CRED_PERSIST_ENTERPRISE))
1803 {
1804 ret = mac_write_credential(Credential, Flags & CRED_PRESERVE_CREDENTIAL_BLOB);
1805 if (ret != ERROR_SUCCESS)
1806 {
1807 SetLastError(ret);
1808 return FALSE;
1809 }
1810 return TRUE;
1811 }
1812 #endif
1813
1814 ret = open_cred_mgr_key(&hkeyMgr, FALSE);
1815 if (ret != ERROR_SUCCESS)
1816 {
1817 WARN("couldn't open/create manager key, error %d\n", ret);
1818 SetLastError(ERROR_NO_SUCH_LOGON_SESSION);
1819 return FALSE;
1820 }
1821
1822 ret = get_cred_mgr_encryption_key(hkeyMgr, key_data);
1823 if (ret != ERROR_SUCCESS)
1824 {
1825 RegCloseKey(hkeyMgr);
1826 SetLastError(ret);
1827 return FALSE;
1828 }
1829
1830 key_name = get_key_name_for_target(Credential->TargetName, Credential->Type);
1831 ret = RegCreateKeyExW(hkeyMgr, key_name, 0, NULL,
1832 Credential->Persist == CRED_PERSIST_SESSION ? REG_OPTION_VOLATILE : REG_OPTION_NON_VOLATILE,
1833 KEY_READ|KEY_WRITE, NULL, &hkeyCred, NULL);
1834 heap_free(key_name);
1835 if (ret != ERROR_SUCCESS)
1836 {
1837 TRACE("credentials for target name %s not found\n",
1838 debugstr_w(Credential->TargetName));
1839 SetLastError(ERROR_NOT_FOUND);
1840 return FALSE;
1841 }
1842
1843 ret = registry_write_credential(hkeyCred, Credential, key_data,
1844 Flags & CRED_PRESERVE_CREDENTIAL_BLOB);
1845
1846 RegCloseKey(hkeyCred);
1847 RegCloseKey(hkeyMgr);
1848
1849 if (ret != ERROR_SUCCESS)
1850 {
1851 SetLastError(ret);
1852 return FALSE;
1853 }
1854 return TRUE;
1855 }
1856
1857 /******************************************************************************
1858 * CredGetSessionTypes [ADVAPI32.@]
1859 */
1860 WINADVAPI BOOL WINAPI CredGetSessionTypes(DWORD persistCount, LPDWORD persists)
1861 {
1862 TRACE("(%u, %p)\n", persistCount, persists);
1863
1864 memset(persists, CRED_PERSIST_NONE, persistCount*sizeof(*persists));
1865 if (CRED_TYPE_GENERIC < persistCount)
1866 {
1867 persists[CRED_TYPE_GENERIC] = CRED_PERSIST_ENTERPRISE;
1868
1869 if (CRED_TYPE_DOMAIN_PASSWORD < persistCount)
1870 {
1871 persists[CRED_TYPE_DOMAIN_PASSWORD] = CRED_PERSIST_ENTERPRISE;
1872 }
1873 }
1874 return TRUE;
1875 }
1876
1877 /******************************************************************************
1878 * CredMarshalCredentialA [ADVAPI32.@]
1879 */
1880 BOOL WINAPI CredMarshalCredentialA( CRED_MARSHAL_TYPE type, PVOID cred, LPSTR *out )
1881 {
1882 BOOL ret;
1883 WCHAR *outW;
1884
1885 TRACE("%u, %p, %p\n", type, cred, out);
1886
1887 if ((ret = CredMarshalCredentialW( type, cred, &outW )))
1888 {
1889 int len = WideCharToMultiByte( CP_ACP, 0, outW, -1, NULL, 0, NULL, NULL );
1890 if (!(*out = heap_alloc( len )))
1891 {
1892 heap_free( outW );
1893 return FALSE;
1894 }
1895 WideCharToMultiByte( CP_ACP, 0, outW, -1, *out, len, NULL, NULL );
1896 heap_free( outW );
1897 }
1898 return ret;
1899 }
1900
1901 static UINT cred_encode( const char *bin, unsigned int len, WCHAR *cred )
1902 {
1903 static const char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#-";
1904 UINT n = 0, x;
1905
1906 while (len > 0)
1907 {
1908 cred[n++] = enc[bin[0] & 0x3f];
1909 x = (bin[0] & 0xc0) >> 6;
1910 if (len == 1)
1911 {
1912 cred[n++] = enc[x];
1913 break;
1914 }
1915 cred[n++] = enc[((bin[1] & 0xf) << 2) | x];
1916 x = (bin[1] & 0xf0) >> 4;
1917 if (len == 2)
1918 {
1919 cred[n++] = enc[x];
1920 break;
1921 }
1922 cred[n++] = enc[((bin[2] & 0x3) << 4) | x];
1923 cred[n++] = enc[(bin[2] & 0xfc) >> 2];
1924 bin += 3;
1925 len -= 3;
1926 }
1927 return n;
1928 }
1929
1930 /******************************************************************************
1931 * CredMarshalCredentialW [ADVAPI32.@]
1932 */
1933 BOOL WINAPI CredMarshalCredentialW( CRED_MARSHAL_TYPE type, PVOID cred, LPWSTR *out )
1934 {
1935 CERT_CREDENTIAL_INFO *cert = cred;
1936 USERNAME_TARGET_CREDENTIAL_INFO *target = cred;
1937 DWORD len, size;
1938 WCHAR *p;
1939
1940 TRACE("%u, %p, %p\n", type, cred, out);
1941
1942 if (!cred || (type == CertCredential && cert->cbSize < sizeof(*cert)) ||
1943 (type != CertCredential && type != UsernameTargetCredential && type != BinaryBlobCredential) ||
1944 (type == UsernameTargetCredential && (!target->UserName || !target->UserName[0])))
1945 {
1946 SetLastError( ERROR_INVALID_PARAMETER );
1947 return FALSE;
1948 }
1949 switch (type)
1950 {
1951 case CertCredential:
1952 {
1953 size = (sizeof(cert->rgbHashOfCert) + 2) * 4 / 3;
1954 if (!(p = heap_alloc( (size + 4) * sizeof(WCHAR) ))) return FALSE;
1955 p[0] = '@';
1956 p[1] = '@';
1957 p[2] = 'A' + type;
1958 len = cred_encode( (const char *)cert->rgbHashOfCert, sizeof(cert->rgbHashOfCert), p + 3 );
1959 p[len + 3] = 0;
1960 break;
1961 }
1962 case UsernameTargetCredential:
1963 {
1964 len = strlenW( target->UserName );
1965 size = (sizeof(DWORD) + len * sizeof(WCHAR) + 2) * 4 / 3;
1966 if (!(p = heap_alloc( (size + 4) * sizeof(WCHAR) ))) return FALSE;
1967 p[0] = '@';
1968 p[1] = '@';
1969 p[2] = 'A' + type;
1970 size = len * sizeof(WCHAR);
1971 len = cred_encode( (const char *)&size, sizeof(DWORD), p + 3 );
1972 len += cred_encode( (const char *)target->UserName, size, p + 3 + len );
1973 p[len + 3] = 0;
1974 break;
1975 }
1976 case BinaryBlobCredential:
1977 FIXME("BinaryBlobCredential not implemented\n");
1978 return FALSE;
1979 default:
1980 return FALSE;
1981 }
1982 *out = p;
1983 return TRUE;
1984 }
1985
1986 /******************************************************************************
1987 * CredUnmarshalCredentialA [ADVAPI32.@]
1988 */
1989 BOOL WINAPI CredUnmarshalCredentialA( LPCSTR cred, PCRED_MARSHAL_TYPE type, PVOID *out )
1990 {
1991 BOOL ret;
1992 WCHAR *credW = NULL;
1993
1994 TRACE("%s, %p, %p\n", debugstr_a(cred), type, out);
1995
1996 if (cred)
1997 {
1998 int len = MultiByteToWideChar( CP_ACP, 0, cred, -1, NULL, 0 );
1999 if (!(credW = heap_alloc( len * sizeof(WCHAR) ))) return FALSE;
2000 MultiByteToWideChar( CP_ACP, 0, cred, -1, credW, len );
2001 }
2002 ret = CredUnmarshalCredentialW( credW, type, out );
2003 heap_free( credW );
2004 return ret;
2005 }
2006
2007 static inline char char_decode( WCHAR c )
2008 {
2009 if (c >= 'A' && c <= 'Z') return c - 'A';
2010 if (c >= 'a' && c <= 'z') return c - 'a' + 26;
2011 if (c >= '0' && c <= '9') return c - '0' + 52;
2012 if (c == '#') return 62;
2013 if (c == '-') return 63;
2014 return 64;
2015 }
2016
2017 static BOOL cred_decode( const WCHAR *cred, unsigned int len, char *buf )
2018 {
2019 unsigned int i = 0;
2020 char c0, c1, c2, c3;
2021 const WCHAR *p = cred;
2022
2023 while (len >= 4)
2024 {
2025 if ((c0 = char_decode( p[0] )) > 63) return FALSE;
2026 if ((c1 = char_decode( p[1] )) > 63) return FALSE;
2027 if ((c2 = char_decode( p[2] )) > 63) return FALSE;
2028 if ((c3 = char_decode( p[3] )) > 63) return FALSE;
2029
2030 buf[i + 0] = (c1 << 6) | c0;
2031 buf[i + 1] = (c2 << 4) | (c1 >> 2);
2032 buf[i + 2] = (c3 << 2) | (c2 >> 4);
2033 len -= 4;
2034 i += 3;
2035 p += 4;
2036 }
2037 if (len == 3)
2038 {
2039 if ((c0 = char_decode( p[0] )) > 63) return FALSE;
2040 if ((c1 = char_decode( p[1] )) > 63) return FALSE;
2041 if ((c2 = char_decode( p[2] )) > 63) return FALSE;
2042
2043 buf[i + 0] = (c1 << 6) | c0;
2044 buf[i + 1] = (c2 << 4) | (c1 >> 2);
2045 }
2046 else if (len == 2)
2047 {
2048 if ((c0 = char_decode( p[0] )) > 63) return FALSE;
2049 if ((c1 = char_decode( p[1] )) > 63) return FALSE;
2050
2051 buf[i + 0] = (c1 << 6) | c0;
2052 }
2053 else if (len == 1)
2054 {
2055 return FALSE;
2056 }
2057 return TRUE;
2058 }
2059
2060 /******************************************************************************
2061 * CredUnmarshalCredentialW [ADVAPI32.@]
2062 */
2063 BOOL WINAPI CredUnmarshalCredentialW( LPCWSTR cred, PCRED_MARSHAL_TYPE type, PVOID *out )
2064 {
2065 unsigned int len, buflen;
2066
2067 TRACE("%s, %p, %p\n", debugstr_w(cred), type, out);
2068
2069 if (!cred || cred[0] != '@' || cred[1] != '@' ||
2070 char_decode( cred[2] ) > 63)
2071 {
2072 SetLastError( ERROR_INVALID_PARAMETER );
2073 return FALSE;
2074 }
2075 len = strlenW( cred + 3 );
2076 *type = char_decode( cred[2] );
2077 switch (*type)
2078 {
2079 case CertCredential:
2080 {
2081 char hash[CERT_HASH_LENGTH];
2082 CERT_CREDENTIAL_INFO *cert;
2083
2084 if (len != 27 || !cred_decode( cred + 3, len, hash ))
2085 {
2086 SetLastError( ERROR_INVALID_PARAMETER );
2087 return FALSE;
2088 }
2089 if (!(cert = heap_alloc( sizeof(*cert) ))) return FALSE;
2090 memcpy( cert->rgbHashOfCert, hash, sizeof(cert->rgbHashOfCert) );
2091 cert->cbSize = sizeof(*cert);
2092 *out = cert;
2093 break;
2094 }
2095 case UsernameTargetCredential:
2096 {
2097 USERNAME_TARGET_CREDENTIAL_INFO *target;
2098 DWORD size;
2099
2100 if (len < 9 || !cred_decode( cred + 3, 6, (char *)&size ) ||
2101 size % sizeof(WCHAR) || len - 6 != (size * 4 + 2) / 3)
2102 {
2103 SetLastError( ERROR_INVALID_PARAMETER );
2104 return FALSE;
2105 }
2106 buflen = sizeof(*target) + size + sizeof(WCHAR);
2107 if (!(target = heap_alloc( buflen ))) return FALSE;
2108 if (!cred_decode( cred + 9, len - 6, (char *)(target + 1) ))
2109 {
2110 heap_free( target );
2111 return FALSE;
2112 }
2113 target->UserName = (WCHAR *)(target + 1);
2114 target->UserName[size / sizeof(WCHAR)] = 0;
2115 *out = target;
2116 break;
2117 }
2118 case BinaryBlobCredential:
2119 FIXME("BinaryBlobCredential not implemented\n");
2120 return FALSE;
2121 default:
2122 WARN("unhandled type %u\n", *type);
2123 SetLastError( ERROR_INVALID_PARAMETER );
2124 return FALSE;
2125 }
2126 return TRUE;
2127 }
2128
2129 /******************************************************************************
2130 * CredIsMarshaledCredentialW [ADVAPI32.@]
2131 *
2132 * Check, if the name parameter is a marshaled credential, hash or binary blob
2133 *
2134 * PARAMS
2135 * name the name to check
2136 *
2137 * RETURNS
2138 * TRUE: the name parameter is a marshaled credential, hash or binary blob
2139 * FALSE: the name is a plain username
2140 */
2141 BOOL WINAPI CredIsMarshaledCredentialW(LPCWSTR name)
2142 {
2143 TRACE("(%s)\n", debugstr_w(name));
2144
2145 if (name && name[0] == '@' && name[1] == '@' && name[2] > 'A' && name[3])
2146 {
2147 char hash[CERT_HASH_LENGTH];
2148 int len = strlenW(name + 3 );
2149 DWORD size;
2150
2151 if ((name[2] - 'A') == CertCredential && (len == 27) && cred_decode(name + 3, len, hash))
2152 return TRUE;
2153
2154 if (((name[2] - 'A') == UsernameTargetCredential) &&
2155 (len >= 9) && cred_decode(name + 3, 6, (char *)&size) && size)
2156 return TRUE;
2157
2158 if ((name[2] - 'A') == BinaryBlobCredential)
2159 FIXME("BinaryBlobCredential not checked\n");
2160
2161 if ((name[2] - 'A') > BinaryBlobCredential)
2162 TRACE("unknown type: %d\n", (name[2] - 'A'));
2163 }
2164
2165 SetLastError(ERROR_INVALID_PARAMETER);
2166 return FALSE;
2167 }
2168
2169 /******************************************************************************
2170 * CredIsMarshaledCredentialA [ADVAPI32.@]
2171 *
2172 * See CredIsMarshaledCredentialW
2173 *
2174 */
2175 BOOL WINAPI CredIsMarshaledCredentialA(LPCSTR name)
2176 {
2177 LPWSTR nameW = NULL;
2178 BOOL res;
2179 int len;
2180
2181 TRACE("(%s)\n", debugstr_a(name));
2182
2183 if (name)
2184 {
2185 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
2186 nameW = heap_alloc(len * sizeof(WCHAR));
2187 MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, len);
2188 }
2189
2190 res = CredIsMarshaledCredentialW(nameW);
2191 heap_free(nameW);
2192 return res;
2193 }