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