source: trunk/src/advapi32/cred.c@ 21916

Last change on this file since 21916 was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

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