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