wined3d: Don't use persistent BOs from the client thread if we might need to do verte...
[wine.git] / dlls / credui / credui_main.c
blob221965f618267f7f90d33d42e66b893c740f8132
1 /*
2 * Credentials User Interface
4 * Copyright 2006 Robert Shearman (for CodeWeavers)
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.
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.
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
21 #include <stdarg.h>
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"
32 #include "credui_resources.h"
34 #include "wine/debug.h"
35 #include "wine/list.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(credui);
39 #define TOOLID_INCORRECTPASSWORD 1
40 #define TOOLID_CAPSLOCKON 2
42 #define ID_CAPSLOCKPOP 1
44 struct pending_credentials
46 struct list entry;
47 PWSTR pszTargetName;
48 PWSTR pszUsername;
49 PWSTR pszPassword;
50 BOOL generic;
53 static HINSTANCE hinstCredUI;
55 static struct list pending_credentials_list = LIST_INIT(pending_credentials_list);
57 static CRITICAL_SECTION csPendingCredentials;
58 static CRITICAL_SECTION_DEBUG critsect_debug =
60 0, 0, &csPendingCredentials,
61 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
62 0, 0, { (DWORD_PTR)(__FILE__ ": csPendingCredentials") }
64 static CRITICAL_SECTION csPendingCredentials = { &critsect_debug, -1, 0, 0, 0, 0 };
67 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
69 struct pending_credentials *entry, *cursor2;
70 TRACE("(0x%p, %ld, %p)\n",hinstDLL,fdwReason,lpvReserved);
72 switch (fdwReason)
74 case DLL_PROCESS_ATTACH:
75 DisableThreadLibraryCalls(hinstDLL);
76 hinstCredUI = hinstDLL;
77 InitCommonControls();
78 break;
80 case DLL_PROCESS_DETACH:
81 if (lpvReserved) break;
82 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &pending_credentials_list, struct pending_credentials, entry)
84 list_remove(&entry->entry);
86 HeapFree(GetProcessHeap(), 0, entry->pszTargetName);
87 HeapFree(GetProcessHeap(), 0, entry->pszUsername);
88 SecureZeroMemory(entry->pszPassword, lstrlenW(entry->pszPassword) * sizeof(WCHAR));
89 HeapFree(GetProcessHeap(), 0, entry->pszPassword);
90 HeapFree(GetProcessHeap(), 0, entry);
92 DeleteCriticalSection(&csPendingCredentials);
93 break;
96 return TRUE;
99 static DWORD save_credentials(PCWSTR pszTargetName, PCWSTR pszUsername,
100 PCWSTR pszPassword, BOOL generic)
102 CREDENTIALW cred;
104 TRACE("saving servername %s with username %s\n", debugstr_w(pszTargetName), debugstr_w(pszUsername));
106 cred.Flags = 0;
107 cred.Type = generic ? CRED_TYPE_GENERIC : CRED_TYPE_DOMAIN_PASSWORD;
108 cred.TargetName = (LPWSTR)pszTargetName;
109 cred.Comment = NULL;
110 cred.CredentialBlobSize = lstrlenW(pszPassword) * sizeof(WCHAR);
111 cred.CredentialBlob = (LPBYTE)pszPassword;
112 cred.Persist = CRED_PERSIST_ENTERPRISE;
113 cred.AttributeCount = 0;
114 cred.Attributes = NULL;
115 cred.TargetAlias = NULL;
116 cred.UserName = (LPWSTR)pszUsername;
118 if (CredWriteW(&cred, 0))
119 return ERROR_SUCCESS;
120 else
122 DWORD ret = GetLastError();
123 ERR("CredWriteW failed with error %ld\n", ret);
124 return ret;
128 struct cred_dialog_params
130 PCWSTR pszTargetName;
131 PCWSTR pszMessageText;
132 PCWSTR pszCaptionText;
133 HBITMAP hbmBanner;
134 PWSTR pszUsername;
135 ULONG ulUsernameMaxChars;
136 PWSTR pszPassword;
137 ULONG ulPasswordMaxChars;
138 BOOL fSave;
139 DWORD dwFlags;
140 HWND hwndBalloonTip;
141 BOOL fBalloonTipActive;
144 static void CredDialogFillUsernameCombo(HWND hwndUsername, const struct cred_dialog_params *params)
146 DWORD count;
147 DWORD i;
148 PCREDENTIALW *credentials;
150 if (!CredEnumerateW(NULL, 0, &count, &credentials))
151 return;
153 for (i = 0; i < count; i++)
155 COMBOBOXEXITEMW comboitem;
156 DWORD j;
157 BOOL duplicate = FALSE;
159 if (!credentials[i]->UserName)
160 continue;
162 if (params->dwFlags & CREDUI_FLAGS_GENERIC_CREDENTIALS)
164 if (credentials[i]->Type != CRED_TYPE_GENERIC)
166 credentials[i]->UserName = NULL;
167 continue;
170 else if (credentials[i]->Type == CRED_TYPE_GENERIC)
172 credentials[i]->UserName = NULL;
173 continue;
176 /* don't add another item with the same name if we've already added it */
177 for (j = 0; j < i; j++)
178 if (credentials[j]->UserName
179 && !lstrcmpW(credentials[i]->UserName, credentials[j]->UserName))
181 duplicate = TRUE;
182 break;
185 if (duplicate)
186 continue;
188 comboitem.mask = CBEIF_TEXT;
189 comboitem.iItem = -1;
190 comboitem.pszText = credentials[i]->UserName;
191 SendMessageW(hwndUsername, CBEM_INSERTITEMW, 0, (LPARAM)&comboitem);
194 CredFree(credentials);
197 static void CredDialogCreateBalloonTip(HWND hwndDlg, struct cred_dialog_params *params)
199 TTTOOLINFOW toolinfo;
200 WCHAR wszText[256];
202 if (params->hwndBalloonTip)
203 return;
205 params->hwndBalloonTip = CreateWindowExW(WS_EX_TOOLWINDOW, TOOLTIPS_CLASSW,
206 NULL, WS_POPUP | TTS_NOPREFIX | TTS_BALLOON, CW_USEDEFAULT,
207 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hwndDlg, NULL,
208 hinstCredUI, NULL);
209 SetWindowPos(params->hwndBalloonTip, HWND_TOPMOST, 0, 0, 0, 0,
210 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
212 if (!LoadStringW(hinstCredUI, IDS_INCORRECTPASSWORD, wszText, ARRAY_SIZE(wszText)))
214 ERR("failed to load IDS_INCORRECTPASSWORD\n");
215 return;
218 toolinfo.cbSize = sizeof(toolinfo);
219 toolinfo.uFlags = TTF_TRACK;
220 toolinfo.hwnd = hwndDlg;
221 toolinfo.uId = TOOLID_INCORRECTPASSWORD;
222 SetRectEmpty(&toolinfo.rect);
223 toolinfo.hinst = NULL;
224 toolinfo.lpszText = wszText;
225 toolinfo.lParam = 0;
226 toolinfo.lpReserved = NULL;
227 SendMessageW(params->hwndBalloonTip, TTM_ADDTOOLW, 0, (LPARAM)&toolinfo);
229 if (!LoadStringW(hinstCredUI, IDS_CAPSLOCKON, wszText, ARRAY_SIZE(wszText)))
231 ERR("failed to load IDS_CAPSLOCKON\n");
232 return;
235 toolinfo.uId = TOOLID_CAPSLOCKON;
236 SendMessageW(params->hwndBalloonTip, TTM_ADDTOOLW, 0, (LPARAM)&toolinfo);
239 static void CredDialogShowIncorrectPasswordBalloon(HWND hwndDlg, struct cred_dialog_params *params)
241 TTTOOLINFOW toolinfo;
242 RECT rcPassword;
243 INT x;
244 INT y;
245 WCHAR wszTitle[256];
247 /* user name likely wrong so balloon would be confusing. focus is also
248 * not set to the password edit box, so more notification would need to be
249 * handled */
250 if (!params->pszUsername[0])
251 return;
253 /* don't show two balloon tips at once */
254 if (params->fBalloonTipActive)
255 return;
257 if (!LoadStringW(hinstCredUI, IDS_INCORRECTPASSWORDTITLE, wszTitle, ARRAY_SIZE(wszTitle)))
259 ERR("failed to load IDS_INCORRECTPASSWORDTITLE\n");
260 return;
263 CredDialogCreateBalloonTip(hwndDlg, params);
265 memset(&toolinfo, 0, sizeof(toolinfo));
266 toolinfo.cbSize = sizeof(toolinfo);
267 toolinfo.hwnd = hwndDlg;
268 toolinfo.uId = TOOLID_INCORRECTPASSWORD;
270 SendMessageW(params->hwndBalloonTip, TTM_SETTITLEW, TTI_ERROR, (LPARAM)wszTitle);
272 GetWindowRect(GetDlgItem(hwndDlg, IDC_PASSWORD), &rcPassword);
273 /* centered vertically and in the right side of the password edit control */
274 x = rcPassword.right - 12;
275 y = (rcPassword.top + rcPassword.bottom) / 2;
276 SendMessageW(params->hwndBalloonTip, TTM_TRACKPOSITION, 0, MAKELONG(x, y));
278 SendMessageW(params->hwndBalloonTip, TTM_TRACKACTIVATE, TRUE, (LPARAM)&toolinfo);
280 params->fBalloonTipActive = TRUE;
283 static void CredDialogShowCapsLockBalloon(HWND hwndDlg, struct cred_dialog_params *params)
285 TTTOOLINFOW toolinfo;
286 RECT rcPassword;
287 INT x;
288 INT y;
289 WCHAR wszTitle[256];
291 /* don't show two balloon tips at once */
292 if (params->fBalloonTipActive)
293 return;
295 if (!LoadStringW(hinstCredUI, IDS_CAPSLOCKONTITLE, wszTitle, ARRAY_SIZE(wszTitle)))
297 ERR("failed to load IDS_IDSCAPSLOCKONTITLE\n");
298 return;
301 CredDialogCreateBalloonTip(hwndDlg, params);
303 memset(&toolinfo, 0, sizeof(toolinfo));
304 toolinfo.cbSize = sizeof(toolinfo);
305 toolinfo.hwnd = hwndDlg;
306 toolinfo.uId = TOOLID_CAPSLOCKON;
308 SendMessageW(params->hwndBalloonTip, TTM_SETTITLEW, TTI_WARNING, (LPARAM)wszTitle);
310 GetWindowRect(GetDlgItem(hwndDlg, IDC_PASSWORD), &rcPassword);
311 /* just inside the left side of the password edit control */
312 x = rcPassword.left + 12;
313 y = rcPassword.bottom - 3;
314 SendMessageW(params->hwndBalloonTip, TTM_TRACKPOSITION, 0, MAKELONG(x, y));
316 SendMessageW(params->hwndBalloonTip, TTM_TRACKACTIVATE, TRUE, (LPARAM)&toolinfo);
318 SetTimer(hwndDlg, ID_CAPSLOCKPOP,
319 SendMessageW(params->hwndBalloonTip, TTM_GETDELAYTIME, TTDT_AUTOPOP, 0),
320 NULL);
322 params->fBalloonTipActive = TRUE;
325 static void CredDialogHideBalloonTip(HWND hwndDlg, struct cred_dialog_params *params)
327 TTTOOLINFOW toolinfo;
329 if (!params->hwndBalloonTip)
330 return;
332 memset(&toolinfo, 0, sizeof(toolinfo));
334 toolinfo.cbSize = sizeof(toolinfo);
335 toolinfo.hwnd = hwndDlg;
336 toolinfo.uId = 0;
337 SendMessageW(params->hwndBalloonTip, TTM_TRACKACTIVATE, FALSE, (LPARAM)&toolinfo);
338 toolinfo.uId = 1;
339 SendMessageW(params->hwndBalloonTip, TTM_TRACKACTIVATE, FALSE, (LPARAM)&toolinfo);
341 params->fBalloonTipActive = FALSE;
344 static inline BOOL CredDialogCapsLockOn(void)
346 return (GetKeyState(VK_CAPITAL) & 0x1) != 0;
349 static LRESULT CALLBACK CredDialogPasswordSubclassProc(HWND hwnd, UINT uMsg,
350 WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
352 struct cred_dialog_params *params = (struct cred_dialog_params *)dwRefData;
353 switch (uMsg)
355 case WM_KEYDOWN:
356 if (wParam == VK_CAPITAL)
358 HWND hwndDlg = GetParent(hwnd);
359 if (CredDialogCapsLockOn())
360 CredDialogShowCapsLockBalloon(hwndDlg, params);
361 else
362 CredDialogHideBalloonTip(hwndDlg, params);
364 break;
365 case WM_DESTROY:
366 RemoveWindowSubclass(hwnd, CredDialogPasswordSubclassProc, uIdSubclass);
367 break;
369 return DefSubclassProc(hwnd, uMsg, wParam, lParam);
372 static BOOL CredDialogInit(HWND hwndDlg, struct cred_dialog_params *params)
374 HWND hwndUsername = GetDlgItem(hwndDlg, IDC_USERNAME);
375 HWND hwndPassword = GetDlgItem(hwndDlg, IDC_PASSWORD);
377 SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)params);
379 if (params->hbmBanner)
380 SendMessageW(GetDlgItem(hwndDlg, IDB_BANNER), STM_SETIMAGE,
381 IMAGE_BITMAP, (LPARAM)params->hbmBanner);
383 if (params->pszMessageText)
384 SetDlgItemTextW(hwndDlg, IDC_MESSAGE, params->pszMessageText);
385 else
387 WCHAR format[256];
388 WCHAR message[256];
389 LoadStringW(hinstCredUI, IDS_MESSAGEFORMAT, format, ARRAY_SIZE(format));
390 swprintf(message, ARRAY_SIZE(message), format, params->pszTargetName);
391 SetDlgItemTextW(hwndDlg, IDC_MESSAGE, message);
393 SetWindowTextW(hwndUsername, params->pszUsername);
394 SetWindowTextW(hwndPassword, params->pszPassword);
396 CredDialogFillUsernameCombo(hwndUsername, params);
398 if (params->pszUsername[0])
400 /* prevent showing a balloon tip here */
401 params->fBalloonTipActive = TRUE;
402 SetFocus(hwndPassword);
403 params->fBalloonTipActive = FALSE;
405 else
406 SetFocus(hwndUsername);
408 if (params->pszCaptionText)
409 SetWindowTextW(hwndDlg, params->pszCaptionText);
410 else
412 WCHAR format[256];
413 WCHAR title[256];
414 LoadStringW(hinstCredUI, IDS_TITLEFORMAT, format, ARRAY_SIZE(format));
415 swprintf(title, ARRAY_SIZE(title), format, params->pszTargetName);
416 SetWindowTextW(hwndDlg, title);
419 if (params->dwFlags & CREDUI_FLAGS_PERSIST ||
420 (params->dwFlags & CREDUI_FLAGS_DO_NOT_PERSIST &&
421 !(params->dwFlags & CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX)))
422 ShowWindow(GetDlgItem(hwndDlg, IDC_SAVE), SW_HIDE);
423 else if (params->fSave)
424 CheckDlgButton(hwndDlg, IDC_SAVE, BST_CHECKED);
426 /* setup subclassing for Caps Lock detection */
427 SetWindowSubclass(hwndPassword, CredDialogPasswordSubclassProc, 1, (DWORD_PTR)params);
429 if (params->dwFlags & CREDUI_FLAGS_INCORRECT_PASSWORD)
430 CredDialogShowIncorrectPasswordBalloon(hwndDlg, params);
431 else if ((GetFocus() == hwndPassword) && CredDialogCapsLockOn())
432 CredDialogShowCapsLockBalloon(hwndDlg, params);
434 return FALSE;
437 static void CredDialogCommandOk(HWND hwndDlg, struct cred_dialog_params *params)
439 HWND hwndUsername = GetDlgItem(hwndDlg, IDC_USERNAME);
440 LPWSTR user;
441 INT len;
442 INT len2;
444 len = GetWindowTextLengthW(hwndUsername);
445 user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
446 GetWindowTextW(hwndUsername, user, len + 1);
448 if (!user[0])
450 HeapFree(GetProcessHeap(), 0, user);
451 return;
454 if (!wcschr(user, '\\') && !wcschr(user, '@'))
456 ULONG len_target = lstrlenW(params->pszTargetName);
457 memcpy(params->pszUsername, params->pszTargetName,
458 min(len_target, params->ulUsernameMaxChars) * sizeof(WCHAR));
459 if (len_target + 1 < params->ulUsernameMaxChars)
460 params->pszUsername[len_target] = '\\';
461 if (len_target + 2 < params->ulUsernameMaxChars)
462 params->pszUsername[len_target + 1] = '\0';
464 else if (params->ulUsernameMaxChars > 0)
465 params->pszUsername[0] = '\0';
467 len2 = lstrlenW(params->pszUsername);
468 memcpy(params->pszUsername + len2, user, min(len, params->ulUsernameMaxChars - len2) * sizeof(WCHAR));
469 if (params->ulUsernameMaxChars)
470 params->pszUsername[len2 + min(len, params->ulUsernameMaxChars - len2 - 1)] = '\0';
472 HeapFree(GetProcessHeap(), 0, user);
474 GetDlgItemTextW(hwndDlg, IDC_PASSWORD, params->pszPassword,
475 params->ulPasswordMaxChars);
477 params->fSave = IsDlgButtonChecked(hwndDlg, IDC_SAVE) == BST_CHECKED;
479 EndDialog(hwndDlg, IDOK);
482 static INT_PTR CALLBACK CredDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
483 LPARAM lParam)
485 switch (uMsg)
487 case WM_INITDIALOG:
489 struct cred_dialog_params *params = (struct cred_dialog_params *)lParam;
491 return CredDialogInit(hwndDlg, params);
493 case WM_COMMAND:
494 switch (wParam)
496 case MAKELONG(IDOK, BN_CLICKED):
498 struct cred_dialog_params *params =
499 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
500 CredDialogCommandOk(hwndDlg, params);
501 return TRUE;
503 case MAKELONG(IDCANCEL, BN_CLICKED):
504 EndDialog(hwndDlg, IDCANCEL);
505 return TRUE;
506 case MAKELONG(IDC_PASSWORD, EN_SETFOCUS):
507 if (CredDialogCapsLockOn())
509 struct cred_dialog_params *params =
510 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
511 CredDialogShowCapsLockBalloon(hwndDlg, params);
513 /* don't allow another window to steal focus while the
514 * user is typing their password */
515 LockSetForegroundWindow(LSFW_LOCK);
516 return TRUE;
517 case MAKELONG(IDC_PASSWORD, EN_KILLFOCUS):
519 struct cred_dialog_params *params =
520 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
521 /* the user is no longer typing their password, so allow
522 * other windows to become foreground ones */
523 LockSetForegroundWindow(LSFW_UNLOCK);
524 CredDialogHideBalloonTip(hwndDlg, params);
525 return TRUE;
527 case MAKELONG(IDC_PASSWORD, EN_CHANGE):
529 struct cred_dialog_params *params =
530 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
531 CredDialogHideBalloonTip(hwndDlg, params);
532 return TRUE;
535 return FALSE;
536 case WM_TIMER:
537 if (wParam == ID_CAPSLOCKPOP)
539 struct cred_dialog_params *params =
540 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
541 CredDialogHideBalloonTip(hwndDlg, params);
542 return TRUE;
544 return FALSE;
545 case WM_DESTROY:
547 struct cred_dialog_params *params =
548 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
549 if (params->hwndBalloonTip) DestroyWindow(params->hwndBalloonTip);
550 return TRUE;
552 default:
553 return FALSE;
557 static BOOL find_existing_credential(const WCHAR *target, WCHAR *username, ULONG len_username,
558 WCHAR *password, ULONG len_password)
560 DWORD count, i;
561 CREDENTIALW **credentials;
563 if (!CredEnumerateW(target, 0, &count, &credentials)) return FALSE;
564 for (i = 0; i < count; i++)
566 if (credentials[i]->Type != CRED_TYPE_DOMAIN_PASSWORD &&
567 credentials[i]->Type != CRED_TYPE_GENERIC)
569 FIXME("no support for type %lu credentials\n", credentials[i]->Type);
570 continue;
572 if ((!*username || !lstrcmpW(username, credentials[i]->UserName)) &&
573 lstrlenW(credentials[i]->UserName) < len_username &&
574 credentials[i]->CredentialBlobSize / sizeof(WCHAR) < len_password)
576 TRACE("found existing credential for %s\n", debugstr_w(credentials[i]->UserName));
578 lstrcpyW(username, credentials[i]->UserName);
579 memcpy(password, credentials[i]->CredentialBlob, credentials[i]->CredentialBlobSize);
580 password[credentials[i]->CredentialBlobSize / sizeof(WCHAR)] = 0;
582 CredFree(credentials);
583 return TRUE;
586 CredFree(credentials);
587 return FALSE;
590 /******************************************************************************
591 * CredUIPromptForCredentialsW [CREDUI.@]
593 DWORD WINAPI CredUIPromptForCredentialsW(PCREDUI_INFOW pUIInfo,
594 PCWSTR pszTargetName,
595 PCtxtHandle Reserved,
596 DWORD dwAuthError,
597 PWSTR pszUsername,
598 ULONG ulUsernameMaxChars,
599 PWSTR pszPassword,
600 ULONG ulPasswordMaxChars, PBOOL pfSave,
601 DWORD dwFlags)
603 INT_PTR ret;
604 struct cred_dialog_params params;
605 DWORD result = ERROR_SUCCESS;
607 TRACE("(%p, %s, %p, %ld, %s, %ld, %p, %ld, %p, 0x%08lx)\n", pUIInfo,
608 debugstr_w(pszTargetName), Reserved, dwAuthError, debugstr_w(pszUsername),
609 ulUsernameMaxChars, pszPassword, ulPasswordMaxChars, pfSave, dwFlags);
611 if ((dwFlags & (CREDUI_FLAGS_ALWAYS_SHOW_UI|CREDUI_FLAGS_GENERIC_CREDENTIALS)) == CREDUI_FLAGS_ALWAYS_SHOW_UI)
612 return ERROR_INVALID_FLAGS;
614 if (!pszTargetName)
615 return ERROR_INVALID_PARAMETER;
617 if ((dwFlags & CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX) && !pfSave)
618 return ERROR_INVALID_PARAMETER;
620 if (!(dwFlags & CREDUI_FLAGS_ALWAYS_SHOW_UI) &&
621 !(dwFlags & CREDUI_FLAGS_INCORRECT_PASSWORD) &&
622 find_existing_credential(pszTargetName, pszUsername, ulUsernameMaxChars, pszPassword, ulPasswordMaxChars))
623 return ERROR_SUCCESS;
625 params.pszTargetName = pszTargetName;
626 if (pUIInfo)
628 params.pszMessageText = pUIInfo->pszMessageText;
629 params.pszCaptionText = pUIInfo->pszCaptionText;
630 params.hbmBanner = pUIInfo->hbmBanner;
632 else
634 params.pszMessageText = NULL;
635 params.pszCaptionText = NULL;
636 params.hbmBanner = NULL;
638 params.pszUsername = pszUsername;
639 params.ulUsernameMaxChars = ulUsernameMaxChars;
640 params.pszPassword = pszPassword;
641 params.ulPasswordMaxChars = ulPasswordMaxChars;
642 params.fSave = pfSave ? *pfSave : FALSE;
643 params.dwFlags = dwFlags;
644 params.hwndBalloonTip = NULL;
645 params.fBalloonTipActive = FALSE;
647 ret = DialogBoxParamW(hinstCredUI, MAKEINTRESOURCEW(IDD_CREDDIALOG),
648 pUIInfo ? pUIInfo->hwndParent : NULL,
649 CredDialogProc, (LPARAM)&params);
650 if (ret <= 0)
651 return GetLastError();
653 if (ret == IDCANCEL)
655 TRACE("dialog cancelled\n");
656 return ERROR_CANCELLED;
659 if (pfSave)
660 *pfSave = params.fSave;
662 if (params.fSave)
664 if (dwFlags & CREDUI_FLAGS_EXPECT_CONFIRMATION)
666 BOOL found = FALSE;
667 struct pending_credentials *entry;
668 int len;
670 EnterCriticalSection(&csPendingCredentials);
672 /* find existing pending credentials for the same target and overwrite */
673 /* FIXME: is this correct? */
674 LIST_FOR_EACH_ENTRY(entry, &pending_credentials_list, struct pending_credentials, entry)
675 if (!lstrcmpW(pszTargetName, entry->pszTargetName))
677 found = TRUE;
678 HeapFree(GetProcessHeap(), 0, entry->pszUsername);
679 SecureZeroMemory(entry->pszPassword, lstrlenW(entry->pszPassword) * sizeof(WCHAR));
680 HeapFree(GetProcessHeap(), 0, entry->pszPassword);
683 if (!found)
685 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
686 len = lstrlenW(pszTargetName);
687 entry->pszTargetName = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
688 memcpy(entry->pszTargetName, pszTargetName, (len + 1)*sizeof(WCHAR));
689 list_add_tail(&pending_credentials_list, &entry->entry);
692 len = lstrlenW(params.pszUsername);
693 entry->pszUsername = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
694 memcpy(entry->pszUsername, params.pszUsername, (len + 1)*sizeof(WCHAR));
695 len = lstrlenW(params.pszPassword);
696 entry->pszPassword = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
697 memcpy(entry->pszPassword, params.pszPassword, (len + 1)*sizeof(WCHAR));
698 entry->generic = (dwFlags & CREDUI_FLAGS_GENERIC_CREDENTIALS) != 0;
700 LeaveCriticalSection(&csPendingCredentials);
702 else if (!(dwFlags & CREDUI_FLAGS_DO_NOT_PERSIST))
703 result = save_credentials(pszTargetName, pszUsername, pszPassword,
704 (dwFlags & CREDUI_FLAGS_GENERIC_CREDENTIALS) != 0);
707 return result;
710 /******************************************************************************
711 * CredUIConfirmCredentialsW [CREDUI.@]
713 DWORD WINAPI CredUIConfirmCredentialsW(PCWSTR pszTargetName, BOOL bConfirm)
715 struct pending_credentials *entry;
716 DWORD result = ERROR_NOT_FOUND;
718 TRACE("(%s, %s)\n", debugstr_w(pszTargetName), bConfirm ? "TRUE" : "FALSE");
720 if (!pszTargetName)
721 return ERROR_INVALID_PARAMETER;
723 EnterCriticalSection(&csPendingCredentials);
725 LIST_FOR_EACH_ENTRY(entry, &pending_credentials_list, struct pending_credentials, entry)
727 if (!lstrcmpW(pszTargetName, entry->pszTargetName))
729 if (bConfirm)
730 result = save_credentials(entry->pszTargetName, entry->pszUsername,
731 entry->pszPassword, entry->generic);
732 else
733 result = ERROR_SUCCESS;
735 list_remove(&entry->entry);
737 HeapFree(GetProcessHeap(), 0, entry->pszTargetName);
738 HeapFree(GetProcessHeap(), 0, entry->pszUsername);
739 SecureZeroMemory(entry->pszPassword, lstrlenW(entry->pszPassword) * sizeof(WCHAR));
740 HeapFree(GetProcessHeap(), 0, entry->pszPassword);
741 HeapFree(GetProcessHeap(), 0, entry);
743 break;
747 LeaveCriticalSection(&csPendingCredentials);
749 return result;
752 /******************************************************************************
753 * CredUIParseUserNameW [CREDUI.@]
755 DWORD WINAPI CredUIParseUserNameW(PCWSTR pszUserName, PWSTR pszUser,
756 ULONG ulMaxUserChars, PWSTR pszDomain,
757 ULONG ulMaxDomainChars)
759 PWSTR p;
761 TRACE("(%s, %p, %ld, %p, %ld)\n", debugstr_w(pszUserName), pszUser,
762 ulMaxUserChars, pszDomain, ulMaxDomainChars);
764 if (!pszUserName || !pszUser || !ulMaxUserChars || !pszDomain ||
765 !ulMaxDomainChars)
766 return ERROR_INVALID_PARAMETER;
768 /* FIXME: handle marshaled credentials */
770 p = wcschr(pszUserName, '\\');
771 if (p)
773 if (p - pszUserName > ulMaxDomainChars - 1)
774 return ERROR_INSUFFICIENT_BUFFER;
775 if (lstrlenW(p + 1) > ulMaxUserChars - 1)
776 return ERROR_INSUFFICIENT_BUFFER;
777 lstrcpyW(pszUser, p + 1);
778 memcpy(pszDomain, pszUserName, (p - pszUserName)*sizeof(WCHAR));
779 pszDomain[p - pszUserName] = '\0';
781 return ERROR_SUCCESS;
784 p = wcsrchr(pszUserName, '@');
785 if (p)
787 if (p + 1 - pszUserName > ulMaxUserChars - 1)
788 return ERROR_INSUFFICIENT_BUFFER;
789 if (lstrlenW(p + 1) > ulMaxDomainChars - 1)
790 return ERROR_INSUFFICIENT_BUFFER;
791 lstrcpyW(pszDomain, p + 1);
792 memcpy(pszUser, pszUserName, (p - pszUserName)*sizeof(WCHAR));
793 pszUser[p - pszUserName] = '\0';
795 return ERROR_SUCCESS;
798 if (lstrlenW(pszUserName) > ulMaxUserChars - 1)
799 return ERROR_INSUFFICIENT_BUFFER;
800 lstrcpyW(pszUser, pszUserName);
801 pszDomain[0] = '\0';
803 return ERROR_SUCCESS;
806 /******************************************************************************
807 * CredUIStoreSSOCredA [CREDUI.@]
809 DWORD WINAPI CredUIStoreSSOCredA(PCSTR pszRealm, PCSTR pszUsername,
810 PCSTR pszPassword, BOOL bPersist)
812 FIXME("(%s, %s, %p, %d)\n", debugstr_a(pszRealm), debugstr_a(pszUsername),
813 pszPassword, bPersist);
814 return ERROR_SUCCESS;
817 /******************************************************************************
818 * CredUIStoreSSOCredW [CREDUI.@]
820 DWORD WINAPI CredUIStoreSSOCredW(PCWSTR pszRealm, PCWSTR pszUsername,
821 PCWSTR pszPassword, BOOL bPersist)
823 FIXME("(%s, %s, %p, %d)\n", debugstr_w(pszRealm), debugstr_w(pszUsername),
824 pszPassword, bPersist);
825 return ERROR_SUCCESS;
828 /******************************************************************************
829 * CredUIReadSSOCredA [CREDUI.@]
831 DWORD WINAPI CredUIReadSSOCredA(PCSTR pszRealm, PSTR *ppszUsername)
833 FIXME("(%s, %p)\n", debugstr_a(pszRealm), ppszUsername);
834 if (ppszUsername)
835 *ppszUsername = NULL;
836 return ERROR_NOT_FOUND;
839 /******************************************************************************
840 * CredUIReadSSOCredW [CREDUI.@]
842 DWORD WINAPI CredUIReadSSOCredW(PCWSTR pszRealm, PWSTR *ppszUsername)
844 FIXME("(%s, %p)\n", debugstr_w(pszRealm), ppszUsername);
845 if (ppszUsername)
846 *ppszUsername = NULL;
847 return ERROR_NOT_FOUND;
850 /******************************************************************************
851 * CredUIInitControls [CREDUI.@]
853 BOOL WINAPI CredUIInitControls(void)
855 FIXME("() stub\n");
856 return TRUE;
859 /******************************************************************************
860 * SspiPromptForCredentialsW [CREDUI.@]
862 ULONG SEC_ENTRY SspiPromptForCredentialsW( PCWSTR target, void *info,
863 DWORD error, PCWSTR package,
864 PSEC_WINNT_AUTH_IDENTITY_OPAQUE input_id,
865 PSEC_WINNT_AUTH_IDENTITY_OPAQUE *output_id,
866 BOOL *save, DWORD sspi_flags )
868 WCHAR username[CREDUI_MAX_USERNAME_LENGTH + 1] = {0};
869 WCHAR password[CREDUI_MAX_PASSWORD_LENGTH + 1] = {0};
870 DWORD len_username = ARRAY_SIZE(username);
871 DWORD len_password = ARRAY_SIZE(password);
872 DWORD ret, flags;
873 CREDUI_INFOW *cred_info = info;
874 SEC_WINNT_AUTH_IDENTITY_W *id = input_id;
876 FIXME( "(%s, %p, %lu, %s, %p, %p, %p, %lx) stub\n", debugstr_w(target), info,
877 error, debugstr_w(package), input_id, output_id, save, sspi_flags );
879 if (!target) return ERROR_INVALID_PARAMETER;
880 if (!package || (wcsicmp( package, L"Basic" ) && wcsicmp( package, L"NTLM" ) &&
881 wcsicmp( package, L"Negotiate" )))
883 FIXME( "package %s not supported\n", debugstr_w(package) );
884 return ERROR_NO_SUCH_PACKAGE;
887 flags = CREDUI_FLAGS_ALWAYS_SHOW_UI | CREDUI_FLAGS_GENERIC_CREDENTIALS;
889 if (sspi_flags & SSPIPFC_CREDPROV_DO_NOT_SAVE)
890 flags |= CREDUI_FLAGS_DO_NOT_PERSIST;
892 if (!(sspi_flags & SSPIPFC_NO_CHECKBOX))
893 flags |= CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX;
895 if (!id) find_existing_credential( target, username, len_username, password, len_password );
896 else
898 if (id->User && id->UserLength > 0 && id->UserLength <= CREDUI_MAX_USERNAME_LENGTH)
900 memcpy( username, id->User, id->UserLength * sizeof(WCHAR) );
901 username[id->UserLength] = 0;
903 if (id->Password && id->PasswordLength > 0 && id->PasswordLength <= CREDUI_MAX_PASSWORD_LENGTH)
905 memcpy( password, id->Password, id->PasswordLength * sizeof(WCHAR) );
906 password[id->PasswordLength] = 0;
910 if (!(ret = CredUIPromptForCredentialsW( cred_info, target, NULL, error, username,
911 len_username, password, len_password, save, flags )))
913 DWORD size = sizeof(*id), len_domain = 0;
914 WCHAR *ptr, *user = username, *domain = NULL;
916 if ((ptr = wcschr( username, '\\' )))
918 user = ptr + 1;
919 len_username = lstrlenW( user );
920 if (!wcsicmp( package, L"NTLM" ) || !wcsicmp( package, L"Negotiate" ))
922 domain = username;
923 len_domain = ptr - username;
925 *ptr = 0;
927 else len_username = lstrlenW( username );
928 len_password = lstrlenW( password );
930 size += (len_username + 1) * sizeof(WCHAR);
931 size += (len_domain + 1) * sizeof(WCHAR);
932 size += (len_password + 1) * sizeof(WCHAR);
933 if (!(id = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
934 ptr = (WCHAR *)(id + 1);
936 memcpy( ptr, user, (len_username + 1) * sizeof(WCHAR) );
937 id->User = ptr;
938 id->UserLength = len_username;
939 ptr += len_username + 1;
940 if (len_domain)
942 memcpy( ptr, domain, (len_domain + 1) * sizeof(WCHAR) );
943 id->Domain = ptr;
944 id->DomainLength = len_domain;
945 ptr += len_domain + 1;
947 else
949 id->Domain = NULL;
950 id->DomainLength = 0;
952 memcpy( ptr, password, (len_password + 1) * sizeof(WCHAR) );
953 id->Password = ptr;
954 id->PasswordLength = len_password;
955 id->Flags = 0;
957 *output_id = id;
960 return ret;
963 /******************************************************************************
964 * CredUIPromptForWindowsCredentialsW [CREDUI.@]
966 DWORD WINAPI CredUIPromptForWindowsCredentialsW( CREDUI_INFOW *info, DWORD error, ULONG *package,
967 const void *in_buf, ULONG in_buf_size, void **out_buf,
968 ULONG *out_buf_size, BOOL *save, DWORD flags )
970 FIXME( "(%p, %lu, %p, %p, %lu, %p, %p, %p, %08lx) stub\n", info, error, package, in_buf, in_buf_size,
971 out_buf, out_buf_size, save, flags );
972 return ERROR_CALL_NOT_IMPLEMENTED;
975 /******************************************************************************
976 * CredPackAuthenticationBufferW [CREDUI.@]
978 BOOL WINAPI CredPackAuthenticationBufferW( DWORD flags, WCHAR *username, WCHAR *password, BYTE *buf,
979 DWORD *size )
981 FIXME( "(%08lx, %s, %p, %p, %p) stub\n", flags, debugstr_w(username), password, buf, size );
982 return ERROR_CALL_NOT_IMPLEMENTED;
985 /******************************************************************************
986 * CredUnPackAuthenticationBufferW [CREDUI.@]
988 BOOL WINAPI CredUnPackAuthenticationBufferW( DWORD flags, void *buf, DWORD size, WCHAR *username,
989 DWORD *len_username, WCHAR *domain, DWORD *len_domain,
990 WCHAR *password, DWORD *len_password )
992 FIXME( "(%08lx, %p, %lu, %p, %p, %p, %p, %p, %p) stub\n", flags, buf, size, username, len_username,
993 domain, len_domain, password, len_password );
994 return ERROR_CALL_NOT_IMPLEMENTED;