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