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