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