1 /* 2 * Credentials User Interface 3 * 4 * Copyright 2006 Robert Shearman (for CodeWeavers) 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <stdarg.h> 22 #ifdef __REACTOS__ 23 #include <wchar.h> 24 #endif 25 26 #include "windef.h" 27 #include "winbase.h" 28 #include "winnt.h" 29 #include "winuser.h" 30 #include "wincred.h" 31 #include "rpc.h" 32 #include "sspi.h" 33 #include "commctrl.h" 34 35 #include "credui_resources.h" 36 37 #include "wine/debug.h" 38 #include "wine/list.h" 39 40 WINE_DEFAULT_DEBUG_CHANNEL(credui); 41 42 #define TOOLID_INCORRECTPASSWORD 1 43 #define TOOLID_CAPSLOCKON 2 44 45 #define ID_CAPSLOCKPOP 1 46 47 struct pending_credentials 48 { 49 struct list entry; 50 PWSTR pszTargetName; 51 PWSTR pszUsername; 52 PWSTR pszPassword; 53 BOOL generic; 54 }; 55 56 static HINSTANCE hinstCredUI; 57 58 static struct list pending_credentials_list = LIST_INIT(pending_credentials_list); 59 60 static CRITICAL_SECTION csPendingCredentials; 61 static CRITICAL_SECTION_DEBUG critsect_debug = 62 { 63 0, 0, &csPendingCredentials, 64 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, 65 0, 0, { (DWORD_PTR)(__FILE__ ": csPendingCredentials") } 66 }; 67 static CRITICAL_SECTION csPendingCredentials = { &critsect_debug, -1, 0, 0, 0, 0 }; 68 69 70 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 71 { 72 struct pending_credentials *entry, *cursor2; 73 TRACE("(0x%p, %d, %p)\n",hinstDLL,fdwReason,lpvReserved); 74 75 switch (fdwReason) 76 { 77 case DLL_WINE_PREATTACH: 78 return FALSE; /* prefer native version */ 79 80 case DLL_PROCESS_ATTACH: 81 DisableThreadLibraryCalls(hinstDLL); 82 hinstCredUI = hinstDLL; 83 InitCommonControls(); 84 break; 85 86 case DLL_PROCESS_DETACH: 87 if (lpvReserved) break; 88 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &pending_credentials_list, struct pending_credentials, entry) 89 { 90 list_remove(&entry->entry); 91 92 HeapFree(GetProcessHeap(), 0, entry->pszTargetName); 93 HeapFree(GetProcessHeap(), 0, entry->pszUsername); 94 SecureZeroMemory(entry->pszPassword, lstrlenW(entry->pszPassword) * sizeof(WCHAR)); 95 HeapFree(GetProcessHeap(), 0, entry->pszPassword); 96 HeapFree(GetProcessHeap(), 0, entry); 97 } 98 DeleteCriticalSection(&csPendingCredentials); 99 break; 100 } 101 102 return TRUE; 103 } 104 105 static DWORD save_credentials(PCWSTR pszTargetName, PCWSTR pszUsername, 106 PCWSTR pszPassword, BOOL generic) 107 { 108 CREDENTIALW cred; 109 110 TRACE("saving servername %s with username %s\n", debugstr_w(pszTargetName), debugstr_w(pszUsername)); 111 112 cred.Flags = 0; 113 cred.Type = generic ? CRED_TYPE_GENERIC : CRED_TYPE_DOMAIN_PASSWORD; 114 cred.TargetName = (LPWSTR)pszTargetName; 115 cred.Comment = NULL; 116 cred.CredentialBlobSize = lstrlenW(pszPassword) * sizeof(WCHAR); 117 cred.CredentialBlob = (LPBYTE)pszPassword; 118 cred.Persist = CRED_PERSIST_ENTERPRISE; 119 cred.AttributeCount = 0; 120 cred.Attributes = NULL; 121 cred.TargetAlias = NULL; 122 cred.UserName = (LPWSTR)pszUsername; 123 124 if (CredWriteW(&cred, 0)) 125 return ERROR_SUCCESS; 126 else 127 { 128 DWORD ret = GetLastError(); 129 ERR("CredWriteW failed with error %d\n", ret); 130 return ret; 131 } 132 } 133 134 struct cred_dialog_params 135 { 136 PCWSTR pszTargetName; 137 PCWSTR pszMessageText; 138 PCWSTR pszCaptionText; 139 HBITMAP hbmBanner; 140 PWSTR pszUsername; 141 ULONG ulUsernameMaxChars; 142 PWSTR pszPassword; 143 ULONG ulPasswordMaxChars; 144 BOOL fSave; 145 DWORD dwFlags; 146 HWND hwndBalloonTip; 147 BOOL fBalloonTipActive; 148 }; 149 150 static void CredDialogFillUsernameCombo(HWND hwndUsername, const struct cred_dialog_params *params) 151 { 152 DWORD count; 153 DWORD i; 154 PCREDENTIALW *credentials; 155 156 if (!CredEnumerateW(NULL, 0, &count, &credentials)) 157 return; 158 159 for (i = 0; i < count; i++) 160 { 161 COMBOBOXEXITEMW comboitem; 162 DWORD j; 163 BOOL duplicate = FALSE; 164 165 if (!credentials[i]->UserName) 166 continue; 167 168 if (params->dwFlags & CREDUI_FLAGS_GENERIC_CREDENTIALS) 169 { 170 if (credentials[i]->Type != CRED_TYPE_GENERIC) 171 { 172 credentials[i]->UserName = NULL; 173 continue; 174 } 175 } 176 else if (credentials[i]->Type == CRED_TYPE_GENERIC) 177 { 178 credentials[i]->UserName = NULL; 179 continue; 180 } 181 182 /* don't add another item with the same name if we've already added it */ 183 for (j = 0; j < i; j++) 184 if (credentials[j]->UserName 185 && !lstrcmpW(credentials[i]->UserName, credentials[j]->UserName)) 186 { 187 duplicate = TRUE; 188 break; 189 } 190 191 if (duplicate) 192 continue; 193 194 comboitem.mask = CBEIF_TEXT; 195 comboitem.iItem = -1; 196 comboitem.pszText = credentials[i]->UserName; 197 SendMessageW(hwndUsername, CBEM_INSERTITEMW, 0, (LPARAM)&comboitem); 198 } 199 200 CredFree(credentials); 201 } 202 203 static void CredDialogCreateBalloonTip(HWND hwndDlg, struct cred_dialog_params *params) 204 { 205 TTTOOLINFOW toolinfo; 206 WCHAR wszText[256]; 207 208 if (params->hwndBalloonTip) 209 return; 210 211 params->hwndBalloonTip = CreateWindowExW(WS_EX_TOOLWINDOW, TOOLTIPS_CLASSW, 212 NULL, WS_POPUP | TTS_NOPREFIX | TTS_BALLOON, CW_USEDEFAULT, 213 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hwndDlg, NULL, 214 hinstCredUI, NULL); 215 SetWindowPos(params->hwndBalloonTip, HWND_TOPMOST, 0, 0, 0, 0, 216 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); 217 218 if (!LoadStringW(hinstCredUI, IDS_INCORRECTPASSWORD, wszText, ARRAY_SIZE(wszText))) 219 { 220 ERR("failed to load IDS_INCORRECTPASSWORD\n"); 221 return; 222 } 223 224 toolinfo.cbSize = sizeof(toolinfo); 225 toolinfo.uFlags = TTF_TRACK; 226 toolinfo.hwnd = hwndDlg; 227 toolinfo.uId = TOOLID_INCORRECTPASSWORD; 228 SetRectEmpty(&toolinfo.rect); 229 toolinfo.hinst = NULL; 230 toolinfo.lpszText = wszText; 231 toolinfo.lParam = 0; 232 toolinfo.lpReserved = NULL; 233 SendMessageW(params->hwndBalloonTip, TTM_ADDTOOLW, 0, (LPARAM)&toolinfo); 234 235 if (!LoadStringW(hinstCredUI, IDS_CAPSLOCKON, wszText, ARRAY_SIZE(wszText))) 236 { 237 ERR("failed to load IDS_CAPSLOCKON\n"); 238 return; 239 } 240 241 toolinfo.uId = TOOLID_CAPSLOCKON; 242 SendMessageW(params->hwndBalloonTip, TTM_ADDTOOLW, 0, (LPARAM)&toolinfo); 243 } 244 245 static void CredDialogShowIncorrectPasswordBalloon(HWND hwndDlg, struct cred_dialog_params *params) 246 { 247 TTTOOLINFOW toolinfo; 248 RECT rcPassword; 249 INT x; 250 INT y; 251 WCHAR wszTitle[256]; 252 253 /* user name likely wrong so balloon would be confusing. focus is also 254 * not set to the password edit box, so more notification would need to be 255 * handled */ 256 if (!params->pszUsername[0]) 257 return; 258 259 /* don't show two balloon tips at once */ 260 if (params->fBalloonTipActive) 261 return; 262 263 if (!LoadStringW(hinstCredUI, IDS_INCORRECTPASSWORDTITLE, wszTitle, ARRAY_SIZE(wszTitle))) 264 { 265 ERR("failed to load IDS_INCORRECTPASSWORDTITLE\n"); 266 return; 267 } 268 269 CredDialogCreateBalloonTip(hwndDlg, params); 270 271 memset(&toolinfo, 0, sizeof(toolinfo)); 272 toolinfo.cbSize = sizeof(toolinfo); 273 toolinfo.hwnd = hwndDlg; 274 toolinfo.uId = TOOLID_INCORRECTPASSWORD; 275 276 SendMessageW(params->hwndBalloonTip, TTM_SETTITLEW, TTI_ERROR, (LPARAM)wszTitle); 277 278 GetWindowRect(GetDlgItem(hwndDlg, IDC_PASSWORD), &rcPassword); 279 /* centered vertically and in the right side of the password edit control */ 280 x = rcPassword.right - 12; 281 y = (rcPassword.top + rcPassword.bottom) / 2; 282 SendMessageW(params->hwndBalloonTip, TTM_TRACKPOSITION, 0, MAKELONG(x, y)); 283 284 SendMessageW(params->hwndBalloonTip, TTM_TRACKACTIVATE, TRUE, (LPARAM)&toolinfo); 285 286 params->fBalloonTipActive = TRUE; 287 } 288 289 static void CredDialogShowCapsLockBalloon(HWND hwndDlg, struct cred_dialog_params *params) 290 { 291 TTTOOLINFOW toolinfo; 292 RECT rcPassword; 293 INT x; 294 INT y; 295 WCHAR wszTitle[256]; 296 297 /* don't show two balloon tips at once */ 298 if (params->fBalloonTipActive) 299 return; 300 301 if (!LoadStringW(hinstCredUI, IDS_CAPSLOCKONTITLE, wszTitle, ARRAY_SIZE(wszTitle))) 302 { 303 ERR("failed to load IDS_IDSCAPSLOCKONTITLE\n"); 304 return; 305 } 306 307 CredDialogCreateBalloonTip(hwndDlg, params); 308 309 memset(&toolinfo, 0, sizeof(toolinfo)); 310 toolinfo.cbSize = sizeof(toolinfo); 311 toolinfo.hwnd = hwndDlg; 312 toolinfo.uId = TOOLID_CAPSLOCKON; 313 314 SendMessageW(params->hwndBalloonTip, TTM_SETTITLEW, TTI_WARNING, (LPARAM)wszTitle); 315 316 GetWindowRect(GetDlgItem(hwndDlg, IDC_PASSWORD), &rcPassword); 317 /* just inside the left side of the password edit control */ 318 x = rcPassword.left + 12; 319 y = rcPassword.bottom - 3; 320 SendMessageW(params->hwndBalloonTip, TTM_TRACKPOSITION, 0, MAKELONG(x, y)); 321 322 SendMessageW(params->hwndBalloonTip, TTM_TRACKACTIVATE, TRUE, (LPARAM)&toolinfo); 323 324 SetTimer(hwndDlg, ID_CAPSLOCKPOP, 325 SendMessageW(params->hwndBalloonTip, TTM_GETDELAYTIME, TTDT_AUTOPOP, 0), 326 NULL); 327 328 params->fBalloonTipActive = TRUE; 329 } 330 331 static void CredDialogHideBalloonTip(HWND hwndDlg, struct cred_dialog_params *params) 332 { 333 TTTOOLINFOW toolinfo; 334 335 if (!params->hwndBalloonTip) 336 return; 337 338 memset(&toolinfo, 0, sizeof(toolinfo)); 339 340 toolinfo.cbSize = sizeof(toolinfo); 341 toolinfo.hwnd = hwndDlg; 342 toolinfo.uId = 0; 343 SendMessageW(params->hwndBalloonTip, TTM_TRACKACTIVATE, FALSE, (LPARAM)&toolinfo); 344 toolinfo.uId = 1; 345 SendMessageW(params->hwndBalloonTip, TTM_TRACKACTIVATE, FALSE, (LPARAM)&toolinfo); 346 347 params->fBalloonTipActive = FALSE; 348 } 349 350 static inline BOOL CredDialogCapsLockOn(void) 351 { 352 return (GetKeyState(VK_CAPITAL) & 0x1) != 0; 353 } 354 355 static LRESULT CALLBACK CredDialogPasswordSubclassProc(HWND hwnd, UINT uMsg, 356 WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) 357 { 358 struct cred_dialog_params *params = (struct cred_dialog_params *)dwRefData; 359 switch (uMsg) 360 { 361 case WM_KEYDOWN: 362 if (wParam == VK_CAPITAL) 363 { 364 HWND hwndDlg = GetParent(hwnd); 365 if (CredDialogCapsLockOn()) 366 CredDialogShowCapsLockBalloon(hwndDlg, params); 367 else 368 CredDialogHideBalloonTip(hwndDlg, params); 369 } 370 break; 371 case WM_DESTROY: 372 RemoveWindowSubclass(hwnd, CredDialogPasswordSubclassProc, uIdSubclass); 373 break; 374 } 375 return DefSubclassProc(hwnd, uMsg, wParam, lParam); 376 } 377 378 static BOOL CredDialogInit(HWND hwndDlg, struct cred_dialog_params *params) 379 { 380 HWND hwndUsername = GetDlgItem(hwndDlg, IDC_USERNAME); 381 HWND hwndPassword = GetDlgItem(hwndDlg, IDC_PASSWORD); 382 383 SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)params); 384 385 if (params->hbmBanner) 386 SendMessageW(GetDlgItem(hwndDlg, IDB_BANNER), STM_SETIMAGE, 387 IMAGE_BITMAP, (LPARAM)params->hbmBanner); 388 389 if (params->pszMessageText) 390 SetDlgItemTextW(hwndDlg, IDC_MESSAGE, params->pszMessageText); 391 else 392 { 393 WCHAR format[256]; 394 WCHAR message[256]; 395 LoadStringW(hinstCredUI, IDS_MESSAGEFORMAT, format, ARRAY_SIZE(format)); 396 swprintf(message, format, params->pszTargetName); 397 SetDlgItemTextW(hwndDlg, IDC_MESSAGE, message); 398 } 399 SetWindowTextW(hwndUsername, params->pszUsername); 400 SetWindowTextW(hwndPassword, params->pszPassword); 401 402 CredDialogFillUsernameCombo(hwndUsername, params); 403 404 if (params->pszUsername[0]) 405 { 406 /* prevent showing a balloon tip here */ 407 params->fBalloonTipActive = TRUE; 408 SetFocus(hwndPassword); 409 params->fBalloonTipActive = FALSE; 410 } 411 else 412 SetFocus(hwndUsername); 413 414 if (params->pszCaptionText) 415 SetWindowTextW(hwndDlg, params->pszCaptionText); 416 else 417 { 418 WCHAR format[256]; 419 WCHAR title[256]; 420 LoadStringW(hinstCredUI, IDS_TITLEFORMAT, format, ARRAY_SIZE(format)); 421 swprintf(title, format, params->pszTargetName); 422 SetWindowTextW(hwndDlg, title); 423 } 424 425 if (params->dwFlags & CREDUI_FLAGS_PERSIST || 426 (params->dwFlags & CREDUI_FLAGS_DO_NOT_PERSIST && 427 !(params->dwFlags & CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX))) 428 ShowWindow(GetDlgItem(hwndDlg, IDC_SAVE), SW_HIDE); 429 else if (params->fSave) 430 CheckDlgButton(hwndDlg, IDC_SAVE, BST_CHECKED); 431 432 /* setup subclassing for Caps Lock detection */ 433 SetWindowSubclass(hwndPassword, CredDialogPasswordSubclassProc, 1, (DWORD_PTR)params); 434 435 if (params->dwFlags & CREDUI_FLAGS_INCORRECT_PASSWORD) 436 CredDialogShowIncorrectPasswordBalloon(hwndDlg, params); 437 else if ((GetFocus() == hwndPassword) && CredDialogCapsLockOn()) 438 CredDialogShowCapsLockBalloon(hwndDlg, params); 439 440 return FALSE; 441 } 442 443 static void CredDialogCommandOk(HWND hwndDlg, struct cred_dialog_params *params) 444 { 445 HWND hwndUsername = GetDlgItem(hwndDlg, IDC_USERNAME); 446 LPWSTR user; 447 INT len; 448 INT len2; 449 450 len = GetWindowTextLengthW(hwndUsername); 451 user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); 452 GetWindowTextW(hwndUsername, user, len + 1); 453 454 if (!user[0]) 455 { 456 HeapFree(GetProcessHeap(), 0, user); 457 return; 458 } 459 460 if (!wcschr(user, '\\') && !wcschr(user, '@')) 461 { 462 ULONG len_target = lstrlenW(params->pszTargetName); 463 memcpy(params->pszUsername, params->pszTargetName, 464 min(len_target, params->ulUsernameMaxChars) * sizeof(WCHAR)); 465 if (len_target + 1 < params->ulUsernameMaxChars) 466 params->pszUsername[len_target] = '\\'; 467 if (len_target + 2 < params->ulUsernameMaxChars) 468 params->pszUsername[len_target + 1] = '\0'; 469 } 470 else if (params->ulUsernameMaxChars > 0) 471 params->pszUsername[0] = '\0'; 472 473 len2 = lstrlenW(params->pszUsername); 474 memcpy(params->pszUsername + len2, user, min(len, params->ulUsernameMaxChars - len2) * sizeof(WCHAR)); 475 if (params->ulUsernameMaxChars) 476 params->pszUsername[len2 + min(len, params->ulUsernameMaxChars - len2 - 1)] = '\0'; 477 478 HeapFree(GetProcessHeap(), 0, user); 479 480 GetDlgItemTextW(hwndDlg, IDC_PASSWORD, params->pszPassword, 481 params->ulPasswordMaxChars); 482 483 params->fSave = IsDlgButtonChecked(hwndDlg, IDC_SAVE) == BST_CHECKED; 484 485 EndDialog(hwndDlg, IDOK); 486 } 487 488 static INT_PTR CALLBACK CredDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, 489 LPARAM lParam) 490 { 491 switch (uMsg) 492 { 493 case WM_INITDIALOG: 494 { 495 struct cred_dialog_params *params = (struct cred_dialog_params *)lParam; 496 497 return CredDialogInit(hwndDlg, params); 498 } 499 case WM_COMMAND: 500 switch (wParam) 501 { 502 case MAKELONG(IDOK, BN_CLICKED): 503 { 504 struct cred_dialog_params *params = 505 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER); 506 CredDialogCommandOk(hwndDlg, params); 507 return TRUE; 508 } 509 case MAKELONG(IDCANCEL, BN_CLICKED): 510 EndDialog(hwndDlg, IDCANCEL); 511 return TRUE; 512 case MAKELONG(IDC_PASSWORD, EN_SETFOCUS): 513 if (CredDialogCapsLockOn()) 514 { 515 struct cred_dialog_params *params = 516 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER); 517 CredDialogShowCapsLockBalloon(hwndDlg, params); 518 } 519 /* don't allow another window to steal focus while the 520 * user is typing their password */ 521 LockSetForegroundWindow(LSFW_LOCK); 522 return TRUE; 523 case MAKELONG(IDC_PASSWORD, EN_KILLFOCUS): 524 { 525 struct cred_dialog_params *params = 526 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER); 527 /* the user is no longer typing their password, so allow 528 * other windows to become foreground ones */ 529 LockSetForegroundWindow(LSFW_UNLOCK); 530 CredDialogHideBalloonTip(hwndDlg, params); 531 return TRUE; 532 } 533 case MAKELONG(IDC_PASSWORD, EN_CHANGE): 534 { 535 struct cred_dialog_params *params = 536 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER); 537 CredDialogHideBalloonTip(hwndDlg, params); 538 return TRUE; 539 } 540 } 541 return FALSE; 542 case WM_TIMER: 543 if (wParam == ID_CAPSLOCKPOP) 544 { 545 struct cred_dialog_params *params = 546 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER); 547 CredDialogHideBalloonTip(hwndDlg, params); 548 return TRUE; 549 } 550 return FALSE; 551 case WM_DESTROY: 552 { 553 struct cred_dialog_params *params = 554 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER); 555 if (params->hwndBalloonTip) DestroyWindow(params->hwndBalloonTip); 556 return TRUE; 557 } 558 default: 559 return FALSE; 560 } 561 } 562 563 static BOOL find_existing_credential(const WCHAR *target, WCHAR *username, ULONG len_username, 564 WCHAR *password, ULONG len_password) 565 { 566 DWORD count, i; 567 CREDENTIALW **credentials; 568 569 if (!CredEnumerateW(target, 0, &count, &credentials)) return FALSE; 570 for (i = 0; i < count; i++) 571 { 572 if (credentials[i]->Type != CRED_TYPE_DOMAIN_PASSWORD && 573 credentials[i]->Type != CRED_TYPE_GENERIC) 574 { 575 FIXME("no support for type %u credentials\n", credentials[i]->Type); 576 continue; 577 } 578 if ((!*username || !lstrcmpW(username, credentials[i]->UserName)) && 579 lstrlenW(credentials[i]->UserName) < len_username && 580 credentials[i]->CredentialBlobSize / sizeof(WCHAR) < len_password) 581 { 582 TRACE("found existing credential for %s\n", debugstr_w(credentials[i]->UserName)); 583 584 lstrcpyW(username, credentials[i]->UserName); 585 memcpy(password, credentials[i]->CredentialBlob, credentials[i]->CredentialBlobSize); 586 password[credentials[i]->CredentialBlobSize / sizeof(WCHAR)] = 0; 587 588 CredFree(credentials); 589 return TRUE; 590 } 591 } 592 CredFree(credentials); 593 return FALSE; 594 } 595 596 /****************************************************************************** 597 * CredUIPromptForCredentialsW [CREDUI.@] 598 */ 599 DWORD WINAPI CredUIPromptForCredentialsW(PCREDUI_INFOW pUIInfo, 600 PCWSTR pszTargetName, 601 PCtxtHandle Reserved, 602 DWORD dwAuthError, 603 PWSTR pszUsername, 604 ULONG ulUsernameMaxChars, 605 PWSTR pszPassword, 606 ULONG ulPasswordMaxChars, PBOOL pfSave, 607 DWORD dwFlags) 608 { 609 INT_PTR ret; 610 struct cred_dialog_params params; 611 DWORD result = ERROR_SUCCESS; 612 613 TRACE("(%p, %s, %p, %d, %s, %d, %p, %d, %p, 0x%08x)\n", pUIInfo, 614 debugstr_w(pszTargetName), Reserved, dwAuthError, debugstr_w(pszUsername), 615 ulUsernameMaxChars, pszPassword, ulPasswordMaxChars, pfSave, dwFlags); 616 617 if ((dwFlags & (CREDUI_FLAGS_ALWAYS_SHOW_UI|CREDUI_FLAGS_GENERIC_CREDENTIALS)) == CREDUI_FLAGS_ALWAYS_SHOW_UI) 618 return ERROR_INVALID_FLAGS; 619 620 if (!pszTargetName) 621 return ERROR_INVALID_PARAMETER; 622 623 if ((dwFlags & CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX) && !pfSave) 624 return ERROR_INVALID_PARAMETER; 625 626 if (!(dwFlags & CREDUI_FLAGS_ALWAYS_SHOW_UI) && 627 !(dwFlags & CREDUI_FLAGS_INCORRECT_PASSWORD) && 628 find_existing_credential(pszTargetName, pszUsername, ulUsernameMaxChars, pszPassword, ulPasswordMaxChars)) 629 return ERROR_SUCCESS; 630 631 params.pszTargetName = pszTargetName; 632 if (pUIInfo) 633 { 634 params.pszMessageText = pUIInfo->pszMessageText; 635 params.pszCaptionText = pUIInfo->pszCaptionText; 636 params.hbmBanner = pUIInfo->hbmBanner; 637 } 638 else 639 { 640 params.pszMessageText = NULL; 641 params.pszCaptionText = NULL; 642 params.hbmBanner = NULL; 643 } 644 params.pszUsername = pszUsername; 645 params.ulUsernameMaxChars = ulUsernameMaxChars; 646 params.pszPassword = pszPassword; 647 params.ulPasswordMaxChars = ulPasswordMaxChars; 648 params.fSave = pfSave ? *pfSave : FALSE; 649 params.dwFlags = dwFlags; 650 params.hwndBalloonTip = NULL; 651 params.fBalloonTipActive = FALSE; 652 653 ret = DialogBoxParamW(hinstCredUI, MAKEINTRESOURCEW(IDD_CREDDIALOG), 654 pUIInfo ? pUIInfo->hwndParent : NULL, 655 CredDialogProc, (LPARAM)¶ms); 656 if (ret <= 0) 657 return GetLastError(); 658 659 if (ret == IDCANCEL) 660 { 661 TRACE("dialog cancelled\n"); 662 return ERROR_CANCELLED; 663 } 664 665 if (pfSave) 666 *pfSave = params.fSave; 667 668 if (params.fSave) 669 { 670 if (dwFlags & CREDUI_FLAGS_EXPECT_CONFIRMATION) 671 { 672 BOOL found = FALSE; 673 struct pending_credentials *entry; 674 int len; 675 676 EnterCriticalSection(&csPendingCredentials); 677 678 /* find existing pending credentials for the same target and overwrite */ 679 /* FIXME: is this correct? */ 680 LIST_FOR_EACH_ENTRY(entry, &pending_credentials_list, struct pending_credentials, entry) 681 if (!lstrcmpW(pszTargetName, entry->pszTargetName)) 682 { 683 found = TRUE; 684 HeapFree(GetProcessHeap(), 0, entry->pszUsername); 685 SecureZeroMemory(entry->pszPassword, lstrlenW(entry->pszPassword) * sizeof(WCHAR)); 686 HeapFree(GetProcessHeap(), 0, entry->pszPassword); 687 } 688 689 if (!found) 690 { 691 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry)); 692 len = lstrlenW(pszTargetName); 693 entry->pszTargetName = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR)); 694 memcpy(entry->pszTargetName, pszTargetName, (len + 1)*sizeof(WCHAR)); 695 list_add_tail(&pending_credentials_list, &entry->entry); 696 } 697 698 len = lstrlenW(params.pszUsername); 699 entry->pszUsername = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR)); 700 memcpy(entry->pszUsername, params.pszUsername, (len + 1)*sizeof(WCHAR)); 701 len = lstrlenW(params.pszPassword); 702 entry->pszPassword = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR)); 703 memcpy(entry->pszPassword, params.pszPassword, (len + 1)*sizeof(WCHAR)); 704 entry->generic = (dwFlags & CREDUI_FLAGS_GENERIC_CREDENTIALS) != 0; 705 706 LeaveCriticalSection(&csPendingCredentials); 707 } 708 else if (!(dwFlags & CREDUI_FLAGS_DO_NOT_PERSIST)) 709 result = save_credentials(pszTargetName, pszUsername, pszPassword, 710 (dwFlags & CREDUI_FLAGS_GENERIC_CREDENTIALS) != 0); 711 } 712 713 return result; 714 } 715 716 /****************************************************************************** 717 * CredUIConfirmCredentialsW [CREDUI.@] 718 */ 719 DWORD WINAPI CredUIConfirmCredentialsW(PCWSTR pszTargetName, BOOL bConfirm) 720 { 721 struct pending_credentials *entry; 722 DWORD result = ERROR_NOT_FOUND; 723 724 TRACE("(%s, %s)\n", debugstr_w(pszTargetName), bConfirm ? "TRUE" : "FALSE"); 725 726 if (!pszTargetName) 727 return ERROR_INVALID_PARAMETER; 728 729 EnterCriticalSection(&csPendingCredentials); 730 731 LIST_FOR_EACH_ENTRY(entry, &pending_credentials_list, struct pending_credentials, entry) 732 { 733 if (!lstrcmpW(pszTargetName, entry->pszTargetName)) 734 { 735 if (bConfirm) 736 result = save_credentials(entry->pszTargetName, entry->pszUsername, 737 entry->pszPassword, entry->generic); 738 else 739 result = ERROR_SUCCESS; 740 741 list_remove(&entry->entry); 742 743 HeapFree(GetProcessHeap(), 0, entry->pszTargetName); 744 HeapFree(GetProcessHeap(), 0, entry->pszUsername); 745 SecureZeroMemory(entry->pszPassword, lstrlenW(entry->pszPassword) * sizeof(WCHAR)); 746 HeapFree(GetProcessHeap(), 0, entry->pszPassword); 747 HeapFree(GetProcessHeap(), 0, entry); 748 749 break; 750 } 751 } 752 753 LeaveCriticalSection(&csPendingCredentials); 754 755 return result; 756 } 757 758 /****************************************************************************** 759 * CredUIParseUserNameW [CREDUI.@] 760 */ 761 DWORD WINAPI CredUIParseUserNameW(PCWSTR pszUserName, PWSTR pszUser, 762 ULONG ulMaxUserChars, PWSTR pszDomain, 763 ULONG ulMaxDomainChars) 764 { 765 PWSTR p; 766 767 TRACE("(%s, %p, %d, %p, %d)\n", debugstr_w(pszUserName), pszUser, 768 ulMaxUserChars, pszDomain, ulMaxDomainChars); 769 770 if (!pszUserName || !pszUser || !ulMaxUserChars || !pszDomain || 771 !ulMaxDomainChars) 772 return ERROR_INVALID_PARAMETER; 773 774 /* FIXME: handle marshaled credentials */ 775 776 p = wcschr(pszUserName, '\\'); 777 if (p) 778 { 779 if (p - pszUserName > ulMaxDomainChars - 1) 780 return ERROR_INSUFFICIENT_BUFFER; 781 if (lstrlenW(p + 1) > ulMaxUserChars - 1) 782 return ERROR_INSUFFICIENT_BUFFER; 783 lstrcpyW(pszUser, p + 1); 784 memcpy(pszDomain, pszUserName, (p - pszUserName)*sizeof(WCHAR)); 785 pszDomain[p - pszUserName] = '\0'; 786 787 return ERROR_SUCCESS; 788 } 789 790 p = wcsrchr(pszUserName, '@'); 791 if (p) 792 { 793 if (p + 1 - pszUserName > ulMaxUserChars - 1) 794 return ERROR_INSUFFICIENT_BUFFER; 795 if (lstrlenW(p + 1) > ulMaxDomainChars - 1) 796 return ERROR_INSUFFICIENT_BUFFER; 797 lstrcpyW(pszDomain, p + 1); 798 memcpy(pszUser, pszUserName, (p - pszUserName)*sizeof(WCHAR)); 799 pszUser[p - pszUserName] = '\0'; 800 801 return ERROR_SUCCESS; 802 } 803 804 if (lstrlenW(pszUserName) > ulMaxUserChars - 1) 805 return ERROR_INSUFFICIENT_BUFFER; 806 lstrcpyW(pszUser, pszUserName); 807 pszDomain[0] = '\0'; 808 809 return ERROR_SUCCESS; 810 } 811 812 /****************************************************************************** 813 * CredUIStoreSSOCredA [CREDUI.@] 814 */ 815 DWORD WINAPI CredUIStoreSSOCredA(PCSTR pszRealm, PCSTR pszUsername, 816 PCSTR pszPassword, BOOL bPersist) 817 { 818 FIXME("(%s, %s, %p, %d)\n", debugstr_a(pszRealm), debugstr_a(pszUsername), 819 pszPassword, bPersist); 820 return ERROR_SUCCESS; 821 } 822 823 /****************************************************************************** 824 * CredUIStoreSSOCredW [CREDUI.@] 825 */ 826 DWORD WINAPI CredUIStoreSSOCredW(PCWSTR pszRealm, PCWSTR pszUsername, 827 PCWSTR pszPassword, BOOL bPersist) 828 { 829 FIXME("(%s, %s, %p, %d)\n", debugstr_w(pszRealm), debugstr_w(pszUsername), 830 pszPassword, bPersist); 831 return ERROR_SUCCESS; 832 } 833 834 /****************************************************************************** 835 * CredUIReadSSOCredA [CREDUI.@] 836 */ 837 DWORD WINAPI CredUIReadSSOCredA(PCSTR pszRealm, PSTR *ppszUsername) 838 { 839 FIXME("(%s, %p)\n", debugstr_a(pszRealm), ppszUsername); 840 if (ppszUsername) 841 *ppszUsername = NULL; 842 return ERROR_NOT_FOUND; 843 } 844 845 /****************************************************************************** 846 * CredUIReadSSOCredW [CREDUI.@] 847 */ 848 DWORD WINAPI CredUIReadSSOCredW(PCWSTR pszRealm, PWSTR *ppszUsername) 849 { 850 FIXME("(%s, %p)\n", debugstr_w(pszRealm), ppszUsername); 851 if (ppszUsername) 852 *ppszUsername = NULL; 853 return ERROR_NOT_FOUND; 854 } 855 856 /****************************************************************************** 857 * CredUIInitControls [CREDUI.@] 858 */ 859 BOOL WINAPI CredUIInitControls(void) 860 { 861 FIXME("() stub\n"); 862 return TRUE; 863 } 864 865 /****************************************************************************** 866 * SspiPromptForCredentialsW [CREDUI.@] 867 */ 868 ULONG SEC_ENTRY SspiPromptForCredentialsW( PCWSTR target, void *info, 869 DWORD error, PCWSTR package, 870 PSEC_WINNT_AUTH_IDENTITY_OPAQUE input_id, 871 PSEC_WINNT_AUTH_IDENTITY_OPAQUE *output_id, 872 BOOL *save, DWORD sspi_flags ) 873 { 874 static const WCHAR basicW[] = {'B','a','s','i','c',0}; 875 static const WCHAR ntlmW[] = {'N','T','L','M',0}; 876 static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',0}; 877 WCHAR username[CREDUI_MAX_USERNAME_LENGTH + 1] = {0}; 878 WCHAR password[CREDUI_MAX_PASSWORD_LENGTH + 1] = {0}; 879 DWORD len_username = ARRAY_SIZE(username); 880 DWORD len_password = ARRAY_SIZE(password); 881 DWORD ret, flags; 882 CREDUI_INFOW *cred_info = info; 883 SEC_WINNT_AUTH_IDENTITY_W *id = input_id; 884 885 FIXME( "(%s, %p, %u, %s, %p, %p, %p, %x) stub\n", debugstr_w(target), info, 886 error, debugstr_w(package), input_id, output_id, save, sspi_flags ); 887 888 if (!target) return ERROR_INVALID_PARAMETER; 889 if (!package || (wcsicmp( package, basicW ) && wcsicmp( package, ntlmW ) && 890 wcsicmp( package, negotiateW ))) 891 { 892 FIXME( "package %s not supported\n", debugstr_w(package) ); 893 return ERROR_NO_SUCH_PACKAGE; 894 } 895 896 flags = CREDUI_FLAGS_ALWAYS_SHOW_UI | CREDUI_FLAGS_GENERIC_CREDENTIALS; 897 898 if (sspi_flags & SSPIPFC_CREDPROV_DO_NOT_SAVE) 899 flags |= CREDUI_FLAGS_DO_NOT_PERSIST; 900 901 if (!(sspi_flags & SSPIPFC_NO_CHECKBOX)) 902 flags |= CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX; 903 904 if (!id) find_existing_credential( target, username, len_username, password, len_password ); 905 else 906 { 907 if (id->User && id->UserLength > 0 && id->UserLength <= CREDUI_MAX_USERNAME_LENGTH) 908 { 909 memcpy( username, id->User, id->UserLength * sizeof(WCHAR) ); 910 username[id->UserLength] = 0; 911 } 912 if (id->Password && id->PasswordLength > 0 && id->PasswordLength <= CREDUI_MAX_PASSWORD_LENGTH) 913 { 914 memcpy( password, id->Password, id->PasswordLength * sizeof(WCHAR) ); 915 password[id->PasswordLength] = 0; 916 } 917 } 918 919 if (!(ret = CredUIPromptForCredentialsW( cred_info, target, NULL, error, username, 920 len_username, password, len_password, save, flags ))) 921 { 922 DWORD size = sizeof(*id), len_domain = 0; 923 WCHAR *ptr, *user = username, *domain = NULL; 924 925 if ((ptr = wcschr( username, '\\' ))) 926 { 927 user = ptr + 1; 928 len_username = lstrlenW( user ); 929 if (!wcsicmp( package, ntlmW ) || !wcsicmp( package, negotiateW )) 930 { 931 domain = username; 932 len_domain = ptr - username; 933 } 934 *ptr = 0; 935 } 936 else len_username = lstrlenW( username ); 937 len_password = lstrlenW( password ); 938 939 size += (len_username + 1) * sizeof(WCHAR); 940 size += (len_domain + 1) * sizeof(WCHAR); 941 size += (len_password + 1) * sizeof(WCHAR); 942 if (!(id = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY; 943 ptr = (WCHAR *)(id + 1); 944 945 memcpy( ptr, user, (len_username + 1) * sizeof(WCHAR) ); 946 id->User = ptr; 947 id->UserLength = len_username; 948 ptr += len_username + 1; 949 if (len_domain) 950 { 951 memcpy( ptr, domain, (len_domain + 1) * sizeof(WCHAR) ); 952 id->Domain = ptr; 953 id->DomainLength = len_domain; 954 ptr += len_domain + 1; 955 } 956 else 957 { 958 id->Domain = NULL; 959 id->DomainLength = 0; 960 } 961 memcpy( ptr, password, (len_password + 1) * sizeof(WCHAR) ); 962 id->Password = ptr; 963 id->PasswordLength = len_password; 964 id->Flags = 0; 965 966 *output_id = id; 967 } 968 969 return ret; 970 } 971 972 /****************************************************************************** 973 * CredUIPromptForWindowsCredentialsW [CREDUI.@] 974 */ 975 DWORD WINAPI CredUIPromptForWindowsCredentialsW( CREDUI_INFOW *info, DWORD error, ULONG *package, 976 const void *in_buf, ULONG in_buf_size, void **out_buf, 977 ULONG *out_buf_size, BOOL *save, DWORD flags ) 978 { 979 FIXME( "(%p, %u, %p, %p, %u, %p, %p, %p, %08x) stub\n", info, error, package, in_buf, in_buf_size, 980 out_buf, out_buf_size, save, flags ); 981 return ERROR_CALL_NOT_IMPLEMENTED; 982 } 983 984 /****************************************************************************** 985 * CredPackAuthenticationBufferW [CREDUI.@] 986 */ 987 BOOL WINAPI CredPackAuthenticationBufferW( DWORD flags, WCHAR *username, WCHAR *password, BYTE *buf, 988 DWORD *size ) 989 { 990 FIXME( "(%08x, %s, %p, %p, %p) stub\n", flags, debugstr_w(username), password, buf, size ); 991 return ERROR_CALL_NOT_IMPLEMENTED; 992 } 993 994 /****************************************************************************** 995 * CredUnPackAuthenticationBufferW [CREDUI.@] 996 */ 997 BOOL WINAPI CredUnPackAuthenticationBufferW( DWORD flags, void *buf, DWORD size, WCHAR *username, 998 DWORD *len_username, WCHAR *domain, DWORD *len_domain, 999 WCHAR *password, DWORD *len_password ) 1000 { 1001 FIXME( "(%08x, %p, %u, %p, %p, %p, %p, %p, %p) stub\n", flags, buf, size, username, len_username, 1002 domain, len_domain, password, len_password ); 1003 return ERROR_CALL_NOT_IMPLEMENTED; 1004 } 1005