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