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