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