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