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