d3dx9: Correctly handle sprites array reallocation.
[wine.git] / dlls / credui / credui_main.c
blobf08d1406f900bfea4c9ca7cbabf3d12e12e79ed6
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, %d, %p)\n",hinstDLL,fdwReason,lpvReserved);
72 switch (fdwReason)
74 case DLL_WINE_PREATTACH:
75 return FALSE; /* prefer native version */
77 case DLL_PROCESS_ATTACH:
78 DisableThreadLibraryCalls(hinstDLL);
79 hinstCredUI = hinstDLL;
80 InitCommonControls();
81 break;
83 case DLL_PROCESS_DETACH:
84 if (lpvReserved) break;
85 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &pending_credentials_list, struct pending_credentials, entry)
87 list_remove(&entry->entry);
89 HeapFree(GetProcessHeap(), 0, entry->pszTargetName);
90 HeapFree(GetProcessHeap(), 0, entry->pszUsername);
91 SecureZeroMemory(entry->pszPassword, lstrlenW(entry->pszPassword) * sizeof(WCHAR));
92 HeapFree(GetProcessHeap(), 0, entry->pszPassword);
93 HeapFree(GetProcessHeap(), 0, entry);
95 DeleteCriticalSection(&csPendingCredentials);
96 break;
99 return TRUE;
102 static DWORD save_credentials(PCWSTR pszTargetName, PCWSTR pszUsername,
103 PCWSTR pszPassword, BOOL generic)
105 CREDENTIALW cred;
107 TRACE("saving servername %s with username %s\n", debugstr_w(pszTargetName), debugstr_w(pszUsername));
109 cred.Flags = 0;
110 cred.Type = generic ? CRED_TYPE_GENERIC : CRED_TYPE_DOMAIN_PASSWORD;
111 cred.TargetName = (LPWSTR)pszTargetName;
112 cred.Comment = NULL;
113 cred.CredentialBlobSize = lstrlenW(pszPassword) * sizeof(WCHAR);
114 cred.CredentialBlob = (LPBYTE)pszPassword;
115 cred.Persist = CRED_PERSIST_ENTERPRISE;
116 cred.AttributeCount = 0;
117 cred.Attributes = NULL;
118 cred.TargetAlias = NULL;
119 cred.UserName = (LPWSTR)pszUsername;
121 if (CredWriteW(&cred, 0))
122 return ERROR_SUCCESS;
123 else
125 DWORD ret = GetLastError();
126 ERR("CredWriteW failed with error %d\n", ret);
127 return ret;
131 struct cred_dialog_params
133 PCWSTR pszTargetName;
134 PCWSTR pszMessageText;
135 PCWSTR pszCaptionText;
136 HBITMAP hbmBanner;
137 PWSTR pszUsername;
138 ULONG ulUsernameMaxChars;
139 PWSTR pszPassword;
140 ULONG ulPasswordMaxChars;
141 BOOL fSave;
142 DWORD dwFlags;
143 HWND hwndBalloonTip;
144 BOOL fBalloonTipActive;
147 static void CredDialogFillUsernameCombo(HWND hwndUsername, const struct cred_dialog_params *params)
149 DWORD count;
150 DWORD i;
151 PCREDENTIALW *credentials;
153 if (!CredEnumerateW(NULL, 0, &count, &credentials))
154 return;
156 for (i = 0; i < count; i++)
158 COMBOBOXEXITEMW comboitem;
159 DWORD j;
160 BOOL duplicate = FALSE;
162 if (!credentials[i]->UserName)
163 continue;
165 if (params->dwFlags & CREDUI_FLAGS_GENERIC_CREDENTIALS)
167 if (credentials[i]->Type != CRED_TYPE_GENERIC)
169 credentials[i]->UserName = NULL;
170 continue;
173 else if (credentials[i]->Type == CRED_TYPE_GENERIC)
175 credentials[i]->UserName = NULL;
176 continue;
179 /* don't add another item with the same name if we've already added it */
180 for (j = 0; j < i; j++)
181 if (credentials[j]->UserName
182 && !lstrcmpW(credentials[i]->UserName, credentials[j]->UserName))
184 duplicate = TRUE;
185 break;
188 if (duplicate)
189 continue;
191 comboitem.mask = CBEIF_TEXT;
192 comboitem.iItem = -1;
193 comboitem.pszText = credentials[i]->UserName;
194 SendMessageW(hwndUsername, CBEM_INSERTITEMW, 0, (LPARAM)&comboitem);
197 CredFree(credentials);
200 static void CredDialogCreateBalloonTip(HWND hwndDlg, struct cred_dialog_params *params)
202 TTTOOLINFOW toolinfo;
203 WCHAR wszText[256];
205 if (params->hwndBalloonTip)
206 return;
208 params->hwndBalloonTip = CreateWindowExW(WS_EX_TOOLWINDOW, TOOLTIPS_CLASSW,
209 NULL, WS_POPUP | TTS_NOPREFIX | TTS_BALLOON, CW_USEDEFAULT,
210 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hwndDlg, NULL,
211 hinstCredUI, NULL);
212 SetWindowPos(params->hwndBalloonTip, HWND_TOPMOST, 0, 0, 0, 0,
213 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
215 if (!LoadStringW(hinstCredUI, IDS_INCORRECTPASSWORD, wszText, ARRAY_SIZE(wszText)))
217 ERR("failed to load IDS_INCORRECTPASSWORD\n");
218 return;
221 toolinfo.cbSize = sizeof(toolinfo);
222 toolinfo.uFlags = TTF_TRACK;
223 toolinfo.hwnd = hwndDlg;
224 toolinfo.uId = TOOLID_INCORRECTPASSWORD;
225 SetRectEmpty(&toolinfo.rect);
226 toolinfo.hinst = NULL;
227 toolinfo.lpszText = wszText;
228 toolinfo.lParam = 0;
229 toolinfo.lpReserved = NULL;
230 SendMessageW(params->hwndBalloonTip, TTM_ADDTOOLW, 0, (LPARAM)&toolinfo);
232 if (!LoadStringW(hinstCredUI, IDS_CAPSLOCKON, wszText, ARRAY_SIZE(wszText)))
234 ERR("failed to load IDS_CAPSLOCKON\n");
235 return;
238 toolinfo.uId = TOOLID_CAPSLOCKON;
239 SendMessageW(params->hwndBalloonTip, TTM_ADDTOOLW, 0, (LPARAM)&toolinfo);
242 static void CredDialogShowIncorrectPasswordBalloon(HWND hwndDlg, struct cred_dialog_params *params)
244 TTTOOLINFOW toolinfo;
245 RECT rcPassword;
246 INT x;
247 INT y;
248 WCHAR wszTitle[256];
250 /* user name likely wrong so balloon would be confusing. focus is also
251 * not set to the password edit box, so more notification would need to be
252 * handled */
253 if (!params->pszUsername[0])
254 return;
256 /* don't show two balloon tips at once */
257 if (params->fBalloonTipActive)
258 return;
260 if (!LoadStringW(hinstCredUI, IDS_INCORRECTPASSWORDTITLE, wszTitle, ARRAY_SIZE(wszTitle)))
262 ERR("failed to load IDS_INCORRECTPASSWORDTITLE\n");
263 return;
266 CredDialogCreateBalloonTip(hwndDlg, params);
268 memset(&toolinfo, 0, sizeof(toolinfo));
269 toolinfo.cbSize = sizeof(toolinfo);
270 toolinfo.hwnd = hwndDlg;
271 toolinfo.uId = TOOLID_INCORRECTPASSWORD;
273 SendMessageW(params->hwndBalloonTip, TTM_SETTITLEW, TTI_ERROR, (LPARAM)wszTitle);
275 GetWindowRect(GetDlgItem(hwndDlg, IDC_PASSWORD), &rcPassword);
276 /* centered vertically and in the right side of the password edit control */
277 x = rcPassword.right - 12;
278 y = (rcPassword.top + rcPassword.bottom) / 2;
279 SendMessageW(params->hwndBalloonTip, TTM_TRACKPOSITION, 0, MAKELONG(x, y));
281 SendMessageW(params->hwndBalloonTip, TTM_TRACKACTIVATE, TRUE, (LPARAM)&toolinfo);
283 params->fBalloonTipActive = TRUE;
286 static void CredDialogShowCapsLockBalloon(HWND hwndDlg, struct cred_dialog_params *params)
288 TTTOOLINFOW toolinfo;
289 RECT rcPassword;
290 INT x;
291 INT y;
292 WCHAR wszTitle[256];
294 /* don't show two balloon tips at once */
295 if (params->fBalloonTipActive)
296 return;
298 if (!LoadStringW(hinstCredUI, IDS_CAPSLOCKONTITLE, wszTitle, ARRAY_SIZE(wszTitle)))
300 ERR("failed to load IDS_IDSCAPSLOCKONTITLE\n");
301 return;
304 CredDialogCreateBalloonTip(hwndDlg, params);
306 memset(&toolinfo, 0, sizeof(toolinfo));
307 toolinfo.cbSize = sizeof(toolinfo);
308 toolinfo.hwnd = hwndDlg;
309 toolinfo.uId = TOOLID_CAPSLOCKON;
311 SendMessageW(params->hwndBalloonTip, TTM_SETTITLEW, TTI_WARNING, (LPARAM)wszTitle);
313 GetWindowRect(GetDlgItem(hwndDlg, IDC_PASSWORD), &rcPassword);
314 /* just inside the left side of the password edit control */
315 x = rcPassword.left + 12;
316 y = rcPassword.bottom - 3;
317 SendMessageW(params->hwndBalloonTip, TTM_TRACKPOSITION, 0, MAKELONG(x, y));
319 SendMessageW(params->hwndBalloonTip, TTM_TRACKACTIVATE, TRUE, (LPARAM)&toolinfo);
321 SetTimer(hwndDlg, ID_CAPSLOCKPOP,
322 SendMessageW(params->hwndBalloonTip, TTM_GETDELAYTIME, TTDT_AUTOPOP, 0),
323 NULL);
325 params->fBalloonTipActive = TRUE;
328 static void CredDialogHideBalloonTip(HWND hwndDlg, struct cred_dialog_params *params)
330 TTTOOLINFOW toolinfo;
332 if (!params->hwndBalloonTip)
333 return;
335 memset(&toolinfo, 0, sizeof(toolinfo));
337 toolinfo.cbSize = sizeof(toolinfo);
338 toolinfo.hwnd = hwndDlg;
339 toolinfo.uId = 0;
340 SendMessageW(params->hwndBalloonTip, TTM_TRACKACTIVATE, FALSE, (LPARAM)&toolinfo);
341 toolinfo.uId = 1;
342 SendMessageW(params->hwndBalloonTip, TTM_TRACKACTIVATE, FALSE, (LPARAM)&toolinfo);
344 params->fBalloonTipActive = FALSE;
347 static inline BOOL CredDialogCapsLockOn(void)
349 return (GetKeyState(VK_CAPITAL) & 0x1) != 0;
352 static LRESULT CALLBACK CredDialogPasswordSubclassProc(HWND hwnd, UINT uMsg,
353 WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
355 struct cred_dialog_params *params = (struct cred_dialog_params *)dwRefData;
356 switch (uMsg)
358 case WM_KEYDOWN:
359 if (wParam == VK_CAPITAL)
361 HWND hwndDlg = GetParent(hwnd);
362 if (CredDialogCapsLockOn())
363 CredDialogShowCapsLockBalloon(hwndDlg, params);
364 else
365 CredDialogHideBalloonTip(hwndDlg, params);
367 break;
368 case WM_DESTROY:
369 RemoveWindowSubclass(hwnd, CredDialogPasswordSubclassProc, uIdSubclass);
370 break;
372 return DefSubclassProc(hwnd, uMsg, wParam, lParam);
375 static BOOL CredDialogInit(HWND hwndDlg, struct cred_dialog_params *params)
377 HWND hwndUsername = GetDlgItem(hwndDlg, IDC_USERNAME);
378 HWND hwndPassword = GetDlgItem(hwndDlg, IDC_PASSWORD);
380 SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)params);
382 if (params->hbmBanner)
383 SendMessageW(GetDlgItem(hwndDlg, IDB_BANNER), STM_SETIMAGE,
384 IMAGE_BITMAP, (LPARAM)params->hbmBanner);
386 if (params->pszMessageText)
387 SetDlgItemTextW(hwndDlg, IDC_MESSAGE, params->pszMessageText);
388 else
390 WCHAR format[256];
391 WCHAR message[256];
392 LoadStringW(hinstCredUI, IDS_MESSAGEFORMAT, format, ARRAY_SIZE(format));
393 swprintf(message, ARRAY_SIZE(message), format, params->pszTargetName);
394 SetDlgItemTextW(hwndDlg, IDC_MESSAGE, message);
396 SetWindowTextW(hwndUsername, params->pszUsername);
397 SetWindowTextW(hwndPassword, params->pszPassword);
399 CredDialogFillUsernameCombo(hwndUsername, params);
401 if (params->pszUsername[0])
403 /* prevent showing a balloon tip here */
404 params->fBalloonTipActive = TRUE;
405 SetFocus(hwndPassword);
406 params->fBalloonTipActive = FALSE;
408 else
409 SetFocus(hwndUsername);
411 if (params->pszCaptionText)
412 SetWindowTextW(hwndDlg, params->pszCaptionText);
413 else
415 WCHAR format[256];
416 WCHAR title[256];
417 LoadStringW(hinstCredUI, IDS_TITLEFORMAT, format, ARRAY_SIZE(format));
418 swprintf(title, ARRAY_SIZE(title), format, params->pszTargetName);
419 SetWindowTextW(hwndDlg, title);
422 if (params->dwFlags & CREDUI_FLAGS_PERSIST ||
423 (params->dwFlags & CREDUI_FLAGS_DO_NOT_PERSIST &&
424 !(params->dwFlags & CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX)))
425 ShowWindow(GetDlgItem(hwndDlg, IDC_SAVE), SW_HIDE);
426 else if (params->fSave)
427 CheckDlgButton(hwndDlg, IDC_SAVE, BST_CHECKED);
429 /* setup subclassing for Caps Lock detection */
430 SetWindowSubclass(hwndPassword, CredDialogPasswordSubclassProc, 1, (DWORD_PTR)params);
432 if (params->dwFlags & CREDUI_FLAGS_INCORRECT_PASSWORD)
433 CredDialogShowIncorrectPasswordBalloon(hwndDlg, params);
434 else if ((GetFocus() == hwndPassword) && CredDialogCapsLockOn())
435 CredDialogShowCapsLockBalloon(hwndDlg, params);
437 return FALSE;
440 static void CredDialogCommandOk(HWND hwndDlg, struct cred_dialog_params *params)
442 HWND hwndUsername = GetDlgItem(hwndDlg, IDC_USERNAME);
443 LPWSTR user;
444 INT len;
445 INT len2;
447 len = GetWindowTextLengthW(hwndUsername);
448 user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
449 GetWindowTextW(hwndUsername, user, len + 1);
451 if (!user[0])
453 HeapFree(GetProcessHeap(), 0, user);
454 return;
457 if (!wcschr(user, '\\') && !wcschr(user, '@'))
459 ULONG len_target = lstrlenW(params->pszTargetName);
460 memcpy(params->pszUsername, params->pszTargetName,
461 min(len_target, params->ulUsernameMaxChars) * sizeof(WCHAR));
462 if (len_target + 1 < params->ulUsernameMaxChars)
463 params->pszUsername[len_target] = '\\';
464 if (len_target + 2 < params->ulUsernameMaxChars)
465 params->pszUsername[len_target + 1] = '\0';
467 else if (params->ulUsernameMaxChars > 0)
468 params->pszUsername[0] = '\0';
470 len2 = lstrlenW(params->pszUsername);
471 memcpy(params->pszUsername + len2, user, min(len, params->ulUsernameMaxChars - len2) * sizeof(WCHAR));
472 if (params->ulUsernameMaxChars)
473 params->pszUsername[len2 + min(len, params->ulUsernameMaxChars - len2 - 1)] = '\0';
475 HeapFree(GetProcessHeap(), 0, user);
477 GetDlgItemTextW(hwndDlg, IDC_PASSWORD, params->pszPassword,
478 params->ulPasswordMaxChars);
480 params->fSave = IsDlgButtonChecked(hwndDlg, IDC_SAVE) == BST_CHECKED;
482 EndDialog(hwndDlg, IDOK);
485 static INT_PTR CALLBACK CredDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
486 LPARAM lParam)
488 switch (uMsg)
490 case WM_INITDIALOG:
492 struct cred_dialog_params *params = (struct cred_dialog_params *)lParam;
494 return CredDialogInit(hwndDlg, params);
496 case WM_COMMAND:
497 switch (wParam)
499 case MAKELONG(IDOK, BN_CLICKED):
501 struct cred_dialog_params *params =
502 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
503 CredDialogCommandOk(hwndDlg, params);
504 return TRUE;
506 case MAKELONG(IDCANCEL, BN_CLICKED):
507 EndDialog(hwndDlg, IDCANCEL);
508 return TRUE;
509 case MAKELONG(IDC_PASSWORD, EN_SETFOCUS):
510 if (CredDialogCapsLockOn())
512 struct cred_dialog_params *params =
513 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
514 CredDialogShowCapsLockBalloon(hwndDlg, params);
516 /* don't allow another window to steal focus while the
517 * user is typing their password */
518 LockSetForegroundWindow(LSFW_LOCK);
519 return TRUE;
520 case MAKELONG(IDC_PASSWORD, EN_KILLFOCUS):
522 struct cred_dialog_params *params =
523 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
524 /* the user is no longer typing their password, so allow
525 * other windows to become foreground ones */
526 LockSetForegroundWindow(LSFW_UNLOCK);
527 CredDialogHideBalloonTip(hwndDlg, params);
528 return TRUE;
530 case MAKELONG(IDC_PASSWORD, EN_CHANGE):
532 struct cred_dialog_params *params =
533 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
534 CredDialogHideBalloonTip(hwndDlg, params);
535 return TRUE;
538 return FALSE;
539 case WM_TIMER:
540 if (wParam == ID_CAPSLOCKPOP)
542 struct cred_dialog_params *params =
543 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
544 CredDialogHideBalloonTip(hwndDlg, params);
545 return TRUE;
547 return FALSE;
548 case WM_DESTROY:
550 struct cred_dialog_params *params =
551 (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
552 if (params->hwndBalloonTip) DestroyWindow(params->hwndBalloonTip);
553 return TRUE;
555 default:
556 return FALSE;
560 static BOOL find_existing_credential(const WCHAR *target, WCHAR *username, ULONG len_username,
561 WCHAR *password, ULONG len_password)
563 DWORD count, i;
564 CREDENTIALW **credentials;
566 if (!CredEnumerateW(target, 0, &count, &credentials)) return FALSE;
567 for (i = 0; i < count; i++)
569 if (credentials[i]->Type != CRED_TYPE_DOMAIN_PASSWORD &&
570 credentials[i]->Type != CRED_TYPE_GENERIC)
572 FIXME("no support for type %u credentials\n", credentials[i]->Type);
573 continue;
575 if ((!*username || !lstrcmpW(username, credentials[i]->UserName)) &&
576 lstrlenW(credentials[i]->UserName) < len_username &&
577 credentials[i]->CredentialBlobSize / sizeof(WCHAR) < len_password)
579 TRACE("found existing credential for %s\n", debugstr_w(credentials[i]->UserName));
581 lstrcpyW(username, credentials[i]->UserName);
582 memcpy(password, credentials[i]->CredentialBlob, credentials[i]->CredentialBlobSize);
583 password[credentials[i]->CredentialBlobSize / sizeof(WCHAR)] = 0;
585 CredFree(credentials);
586 return TRUE;
589 CredFree(credentials);
590 return FALSE;
593 /******************************************************************************
594 * CredUIPromptForCredentialsW [CREDUI.@]
596 DWORD WINAPI CredUIPromptForCredentialsW(PCREDUI_INFOW pUIInfo,
597 PCWSTR pszTargetName,
598 PCtxtHandle Reserved,
599 DWORD dwAuthError,
600 PWSTR pszUsername,
601 ULONG ulUsernameMaxChars,
602 PWSTR pszPassword,
603 ULONG ulPasswordMaxChars, PBOOL pfSave,
604 DWORD dwFlags)
606 INT_PTR ret;
607 struct cred_dialog_params params;
608 DWORD result = ERROR_SUCCESS;
610 TRACE("(%p, %s, %p, %d, %s, %d, %p, %d, %p, 0x%08x)\n", pUIInfo,
611 debugstr_w(pszTargetName), Reserved, dwAuthError, debugstr_w(pszUsername),
612 ulUsernameMaxChars, pszPassword, ulPasswordMaxChars, pfSave, dwFlags);
614 if ((dwFlags & (CREDUI_FLAGS_ALWAYS_SHOW_UI|CREDUI_FLAGS_GENERIC_CREDENTIALS)) == CREDUI_FLAGS_ALWAYS_SHOW_UI)
615 return ERROR_INVALID_FLAGS;
617 if (!pszTargetName)
618 return ERROR_INVALID_PARAMETER;
620 if ((dwFlags & CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX) && !pfSave)
621 return ERROR_INVALID_PARAMETER;
623 if (!(dwFlags & CREDUI_FLAGS_ALWAYS_SHOW_UI) &&
624 !(dwFlags & CREDUI_FLAGS_INCORRECT_PASSWORD) &&
625 find_existing_credential(pszTargetName, pszUsername, ulUsernameMaxChars, pszPassword, ulPasswordMaxChars))
626 return ERROR_SUCCESS;
628 params.pszTargetName = pszTargetName;
629 if (pUIInfo)
631 params.pszMessageText = pUIInfo->pszMessageText;
632 params.pszCaptionText = pUIInfo->pszCaptionText;
633 params.hbmBanner = pUIInfo->hbmBanner;
635 else
637 params.pszMessageText = NULL;
638 params.pszCaptionText = NULL;
639 params.hbmBanner = NULL;
641 params.pszUsername = pszUsername;
642 params.ulUsernameMaxChars = ulUsernameMaxChars;
643 params.pszPassword = pszPassword;
644 params.ulPasswordMaxChars = ulPasswordMaxChars;
645 params.fSave = pfSave ? *pfSave : FALSE;
646 params.dwFlags = dwFlags;
647 params.hwndBalloonTip = NULL;
648 params.fBalloonTipActive = FALSE;
650 ret = DialogBoxParamW(hinstCredUI, MAKEINTRESOURCEW(IDD_CREDDIALOG),
651 pUIInfo ? pUIInfo->hwndParent : NULL,
652 CredDialogProc, (LPARAM)&params);
653 if (ret <= 0)
654 return GetLastError();
656 if (ret == IDCANCEL)
658 TRACE("dialog cancelled\n");
659 return ERROR_CANCELLED;
662 if (pfSave)
663 *pfSave = params.fSave;
665 if (params.fSave)
667 if (dwFlags & CREDUI_FLAGS_EXPECT_CONFIRMATION)
669 BOOL found = FALSE;
670 struct pending_credentials *entry;
671 int len;
673 EnterCriticalSection(&csPendingCredentials);
675 /* find existing pending credentials for the same target and overwrite */
676 /* FIXME: is this correct? */
677 LIST_FOR_EACH_ENTRY(entry, &pending_credentials_list, struct pending_credentials, entry)
678 if (!lstrcmpW(pszTargetName, entry->pszTargetName))
680 found = TRUE;
681 HeapFree(GetProcessHeap(), 0, entry->pszUsername);
682 SecureZeroMemory(entry->pszPassword, lstrlenW(entry->pszPassword) * sizeof(WCHAR));
683 HeapFree(GetProcessHeap(), 0, entry->pszPassword);
686 if (!found)
688 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
689 len = lstrlenW(pszTargetName);
690 entry->pszTargetName = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
691 memcpy(entry->pszTargetName, pszTargetName, (len + 1)*sizeof(WCHAR));
692 list_add_tail(&pending_credentials_list, &entry->entry);
695 len = lstrlenW(params.pszUsername);
696 entry->pszUsername = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
697 memcpy(entry->pszUsername, params.pszUsername, (len + 1)*sizeof(WCHAR));
698 len = lstrlenW(params.pszPassword);
699 entry->pszPassword = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
700 memcpy(entry->pszPassword, params.pszPassword, (len + 1)*sizeof(WCHAR));
701 entry->generic = (dwFlags & CREDUI_FLAGS_GENERIC_CREDENTIALS) != 0;
703 LeaveCriticalSection(&csPendingCredentials);
705 else if (!(dwFlags & CREDUI_FLAGS_DO_NOT_PERSIST))
706 result = save_credentials(pszTargetName, pszUsername, pszPassword,
707 (dwFlags & CREDUI_FLAGS_GENERIC_CREDENTIALS) != 0);
710 return result;
713 /******************************************************************************
714 * CredUIConfirmCredentialsW [CREDUI.@]
716 DWORD WINAPI CredUIConfirmCredentialsW(PCWSTR pszTargetName, BOOL bConfirm)
718 struct pending_credentials *entry;
719 DWORD result = ERROR_NOT_FOUND;
721 TRACE("(%s, %s)\n", debugstr_w(pszTargetName), bConfirm ? "TRUE" : "FALSE");
723 if (!pszTargetName)
724 return ERROR_INVALID_PARAMETER;
726 EnterCriticalSection(&csPendingCredentials);
728 LIST_FOR_EACH_ENTRY(entry, &pending_credentials_list, struct pending_credentials, entry)
730 if (!lstrcmpW(pszTargetName, entry->pszTargetName))
732 if (bConfirm)
733 result = save_credentials(entry->pszTargetName, entry->pszUsername,
734 entry->pszPassword, entry->generic);
735 else
736 result = ERROR_SUCCESS;
738 list_remove(&entry->entry);
740 HeapFree(GetProcessHeap(), 0, entry->pszTargetName);
741 HeapFree(GetProcessHeap(), 0, entry->pszUsername);
742 SecureZeroMemory(entry->pszPassword, lstrlenW(entry->pszPassword) * sizeof(WCHAR));
743 HeapFree(GetProcessHeap(), 0, entry->pszPassword);
744 HeapFree(GetProcessHeap(), 0, entry);
746 break;
750 LeaveCriticalSection(&csPendingCredentials);
752 return result;
755 /******************************************************************************
756 * CredUIParseUserNameW [CREDUI.@]
758 DWORD WINAPI CredUIParseUserNameW(PCWSTR pszUserName, PWSTR pszUser,
759 ULONG ulMaxUserChars, PWSTR pszDomain,
760 ULONG ulMaxDomainChars)
762 PWSTR p;
764 TRACE("(%s, %p, %d, %p, %d)\n", debugstr_w(pszUserName), pszUser,
765 ulMaxUserChars, pszDomain, ulMaxDomainChars);
767 if (!pszUserName || !pszUser || !ulMaxUserChars || !pszDomain ||
768 !ulMaxDomainChars)
769 return ERROR_INVALID_PARAMETER;
771 /* FIXME: handle marshaled credentials */
773 p = wcschr(pszUserName, '\\');
774 if (p)
776 if (p - pszUserName > ulMaxDomainChars - 1)
777 return ERROR_INSUFFICIENT_BUFFER;
778 if (lstrlenW(p + 1) > ulMaxUserChars - 1)
779 return ERROR_INSUFFICIENT_BUFFER;
780 lstrcpyW(pszUser, p + 1);
781 memcpy(pszDomain, pszUserName, (p - pszUserName)*sizeof(WCHAR));
782 pszDomain[p - pszUserName] = '\0';
784 return ERROR_SUCCESS;
787 p = wcsrchr(pszUserName, '@');
788 if (p)
790 if (p + 1 - pszUserName > ulMaxUserChars - 1)
791 return ERROR_INSUFFICIENT_BUFFER;
792 if (lstrlenW(p + 1) > ulMaxDomainChars - 1)
793 return ERROR_INSUFFICIENT_BUFFER;
794 lstrcpyW(pszDomain, p + 1);
795 memcpy(pszUser, pszUserName, (p - pszUserName)*sizeof(WCHAR));
796 pszUser[p - pszUserName] = '\0';
798 return ERROR_SUCCESS;
801 if (lstrlenW(pszUserName) > ulMaxUserChars - 1)
802 return ERROR_INSUFFICIENT_BUFFER;
803 lstrcpyW(pszUser, pszUserName);
804 pszDomain[0] = '\0';
806 return ERROR_SUCCESS;
809 /******************************************************************************
810 * CredUIStoreSSOCredA [CREDUI.@]
812 DWORD WINAPI CredUIStoreSSOCredA(PCSTR pszRealm, PCSTR pszUsername,
813 PCSTR pszPassword, BOOL bPersist)
815 FIXME("(%s, %s, %p, %d)\n", debugstr_a(pszRealm), debugstr_a(pszUsername),
816 pszPassword, bPersist);
817 return ERROR_SUCCESS;
820 /******************************************************************************
821 * CredUIStoreSSOCredW [CREDUI.@]
823 DWORD WINAPI CredUIStoreSSOCredW(PCWSTR pszRealm, PCWSTR pszUsername,
824 PCWSTR pszPassword, BOOL bPersist)
826 FIXME("(%s, %s, %p, %d)\n", debugstr_w(pszRealm), debugstr_w(pszUsername),
827 pszPassword, bPersist);
828 return ERROR_SUCCESS;
831 /******************************************************************************
832 * CredUIReadSSOCredA [CREDUI.@]
834 DWORD WINAPI CredUIReadSSOCredA(PCSTR pszRealm, PSTR *ppszUsername)
836 FIXME("(%s, %p)\n", debugstr_a(pszRealm), ppszUsername);
837 if (ppszUsername)
838 *ppszUsername = NULL;
839 return ERROR_NOT_FOUND;
842 /******************************************************************************
843 * CredUIReadSSOCredW [CREDUI.@]
845 DWORD WINAPI CredUIReadSSOCredW(PCWSTR pszRealm, PWSTR *ppszUsername)
847 FIXME("(%s, %p)\n", debugstr_w(pszRealm), ppszUsername);
848 if (ppszUsername)
849 *ppszUsername = NULL;
850 return ERROR_NOT_FOUND;
853 /******************************************************************************
854 * CredUIInitControls [CREDUI.@]
856 BOOL WINAPI CredUIInitControls(void)
858 FIXME("() stub\n");
859 return TRUE;
862 /******************************************************************************
863 * SspiPromptForCredentialsW [CREDUI.@]
865 ULONG SEC_ENTRY SspiPromptForCredentialsW( PCWSTR target, void *info,
866 DWORD error, PCWSTR package,
867 PSEC_WINNT_AUTH_IDENTITY_OPAQUE input_id,
868 PSEC_WINNT_AUTH_IDENTITY_OPAQUE *output_id,
869 BOOL *save, DWORD sspi_flags )
871 WCHAR username[CREDUI_MAX_USERNAME_LENGTH + 1] = {0};
872 WCHAR password[CREDUI_MAX_PASSWORD_LENGTH + 1] = {0};
873 DWORD len_username = ARRAY_SIZE(username);
874 DWORD len_password = ARRAY_SIZE(password);
875 DWORD ret, flags;
876 CREDUI_INFOW *cred_info = info;
877 SEC_WINNT_AUTH_IDENTITY_W *id = input_id;
879 FIXME( "(%s, %p, %u, %s, %p, %p, %p, %x) stub\n", debugstr_w(target), info,
880 error, debugstr_w(package), input_id, output_id, save, sspi_flags );
882 if (!target) return ERROR_INVALID_PARAMETER;
883 if (!package || (wcsicmp( package, L"Basic" ) && wcsicmp( package, L"NTLM" ) &&
884 wcsicmp( package, L"Negotiate" )))
886 FIXME( "package %s not supported\n", debugstr_w(package) );
887 return ERROR_NO_SUCH_PACKAGE;
890 flags = CREDUI_FLAGS_ALWAYS_SHOW_UI | CREDUI_FLAGS_GENERIC_CREDENTIALS;
892 if (sspi_flags & SSPIPFC_CREDPROV_DO_NOT_SAVE)
893 flags |= CREDUI_FLAGS_DO_NOT_PERSIST;
895 if (!(sspi_flags & SSPIPFC_NO_CHECKBOX))
896 flags |= CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX;
898 if (!id) find_existing_credential( target, username, len_username, password, len_password );
899 else
901 if (id->User && id->UserLength > 0 && id->UserLength <= CREDUI_MAX_USERNAME_LENGTH)
903 memcpy( username, id->User, id->UserLength * sizeof(WCHAR) );
904 username[id->UserLength] = 0;
906 if (id->Password && id->PasswordLength > 0 && id->PasswordLength <= CREDUI_MAX_PASSWORD_LENGTH)
908 memcpy( password, id->Password, id->PasswordLength * sizeof(WCHAR) );
909 password[id->PasswordLength] = 0;
913 if (!(ret = CredUIPromptForCredentialsW( cred_info, target, NULL, error, username,
914 len_username, password, len_password, save, flags )))
916 DWORD size = sizeof(*id), len_domain = 0;
917 WCHAR *ptr, *user = username, *domain = NULL;
919 if ((ptr = wcschr( username, '\\' )))
921 user = ptr + 1;
922 len_username = lstrlenW( user );
923 if (!wcsicmp( package, L"NTLM" ) || !wcsicmp( package, L"Negotiate" ))
925 domain = username;
926 len_domain = ptr - username;
928 *ptr = 0;
930 else len_username = lstrlenW( username );
931 len_password = lstrlenW( password );
933 size += (len_username + 1) * sizeof(WCHAR);
934 size += (len_domain + 1) * sizeof(WCHAR);
935 size += (len_password + 1) * sizeof(WCHAR);
936 if (!(id = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY;
937 ptr = (WCHAR *)(id + 1);
939 memcpy( ptr, user, (len_username + 1) * sizeof(WCHAR) );
940 id->User = ptr;
941 id->UserLength = len_username;
942 ptr += len_username + 1;
943 if (len_domain)
945 memcpy( ptr, domain, (len_domain + 1) * sizeof(WCHAR) );
946 id->Domain = ptr;
947 id->DomainLength = len_domain;
948 ptr += len_domain + 1;
950 else
952 id->Domain = NULL;
953 id->DomainLength = 0;
955 memcpy( ptr, password, (len_password + 1) * sizeof(WCHAR) );
956 id->Password = ptr;
957 id->PasswordLength = len_password;
958 id->Flags = 0;
960 *output_id = id;
963 return ret;
966 /******************************************************************************
967 * CredUIPromptForWindowsCredentialsW [CREDUI.@]
969 DWORD WINAPI CredUIPromptForWindowsCredentialsW( CREDUI_INFOW *info, DWORD error, ULONG *package,
970 const void *in_buf, ULONG in_buf_size, void **out_buf,
971 ULONG *out_buf_size, BOOL *save, DWORD flags )
973 FIXME( "(%p, %u, %p, %p, %u, %p, %p, %p, %08x) stub\n", info, error, package, in_buf, in_buf_size,
974 out_buf, out_buf_size, save, flags );
975 return ERROR_CALL_NOT_IMPLEMENTED;
978 /******************************************************************************
979 * CredPackAuthenticationBufferW [CREDUI.@]
981 BOOL WINAPI CredPackAuthenticationBufferW( DWORD flags, WCHAR *username, WCHAR *password, BYTE *buf,
982 DWORD *size )
984 FIXME( "(%08x, %s, %p, %p, %p) stub\n", flags, debugstr_w(username), password, buf, size );
985 return ERROR_CALL_NOT_IMPLEMENTED;
988 /******************************************************************************
989 * CredUnPackAuthenticationBufferW [CREDUI.@]
991 BOOL WINAPI CredUnPackAuthenticationBufferW( DWORD flags, void *buf, DWORD size, WCHAR *username,
992 DWORD *len_username, WCHAR *domain, DWORD *len_domain,
993 WCHAR *password, DWORD *len_password )
995 FIXME( "(%08x, %p, %u, %p, %p, %p, %p, %p, %p) stub\n", flags, buf, size, username, len_username,
996 domain, len_domain, password, len_password );
997 return ERROR_CALL_NOT_IMPLEMENTED;