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
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
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
);
74 case DLL_PROCESS_ATTACH
:
75 DisableThreadLibraryCalls(hinstDLL
);
76 hinstCredUI
= hinstDLL
;
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
);
99 static DWORD
save_credentials(PCWSTR pszTargetName
, PCWSTR pszUsername
,
100 PCWSTR pszPassword
, BOOL generic
)
104 TRACE("saving servername %s with username %s\n", debugstr_w(pszTargetName
), debugstr_w(pszUsername
));
107 cred
.Type
= generic
? CRED_TYPE_GENERIC
: CRED_TYPE_DOMAIN_PASSWORD
;
108 cred
.TargetName
= (LPWSTR
)pszTargetName
;
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
;
122 DWORD ret
= GetLastError();
123 ERR("CredWriteW failed with error %d\n", ret
);
128 struct cred_dialog_params
130 PCWSTR pszTargetName
;
131 PCWSTR pszMessageText
;
132 PCWSTR pszCaptionText
;
135 ULONG ulUsernameMaxChars
;
137 ULONG ulPasswordMaxChars
;
141 BOOL fBalloonTipActive
;
144 static void CredDialogFillUsernameCombo(HWND hwndUsername
, const struct cred_dialog_params
*params
)
148 PCREDENTIALW
*credentials
;
150 if (!CredEnumerateW(NULL
, 0, &count
, &credentials
))
153 for (i
= 0; i
< count
; i
++)
155 COMBOBOXEXITEMW comboitem
;
157 BOOL duplicate
= FALSE
;
159 if (!credentials
[i
]->UserName
)
162 if (params
->dwFlags
& CREDUI_FLAGS_GENERIC_CREDENTIALS
)
164 if (credentials
[i
]->Type
!= CRED_TYPE_GENERIC
)
166 credentials
[i
]->UserName
= NULL
;
170 else if (credentials
[i
]->Type
== CRED_TYPE_GENERIC
)
172 credentials
[i
]->UserName
= NULL
;
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
))
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
;
202 if (params
->hwndBalloonTip
)
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
,
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");
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
;
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");
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
;
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
250 if (!params
->pszUsername
[0])
253 /* don't show two balloon tips at once */
254 if (params
->fBalloonTipActive
)
257 if (!LoadStringW(hinstCredUI
, IDS_INCORRECTPASSWORDTITLE
, wszTitle
, ARRAY_SIZE(wszTitle
)))
259 ERR("failed to load IDS_INCORRECTPASSWORDTITLE\n");
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
;
291 /* don't show two balloon tips at once */
292 if (params
->fBalloonTipActive
)
295 if (!LoadStringW(hinstCredUI
, IDS_CAPSLOCKONTITLE
, wszTitle
, ARRAY_SIZE(wszTitle
)))
297 ERR("failed to load IDS_IDSCAPSLOCKONTITLE\n");
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),
322 params
->fBalloonTipActive
= TRUE
;
325 static void CredDialogHideBalloonTip(HWND hwndDlg
, struct cred_dialog_params
*params
)
327 TTTOOLINFOW toolinfo
;
329 if (!params
->hwndBalloonTip
)
332 memset(&toolinfo
, 0, sizeof(toolinfo
));
334 toolinfo
.cbSize
= sizeof(toolinfo
);
335 toolinfo
.hwnd
= hwndDlg
;
337 SendMessageW(params
->hwndBalloonTip
, TTM_TRACKACTIVATE
, FALSE
, (LPARAM
)&toolinfo
);
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
;
356 if (wParam
== VK_CAPITAL
)
358 HWND hwndDlg
= GetParent(hwnd
);
359 if (CredDialogCapsLockOn())
360 CredDialogShowCapsLockBalloon(hwndDlg
, params
);
362 CredDialogHideBalloonTip(hwndDlg
, params
);
366 RemoveWindowSubclass(hwnd
, CredDialogPasswordSubclassProc
, uIdSubclass
);
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
);
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
;
406 SetFocus(hwndUsername
);
408 if (params
->pszCaptionText
)
409 SetWindowTextW(hwndDlg
, params
->pszCaptionText
);
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
);
437 static void CredDialogCommandOk(HWND hwndDlg
, struct cred_dialog_params
*params
)
439 HWND hwndUsername
= GetDlgItem(hwndDlg
, IDC_USERNAME
);
444 len
= GetWindowTextLengthW(hwndUsername
);
445 user
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
446 GetWindowTextW(hwndUsername
, user
, len
+ 1);
450 HeapFree(GetProcessHeap(), 0, user
);
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
,
489 struct cred_dialog_params
*params
= (struct cred_dialog_params
*)lParam
;
491 return CredDialogInit(hwndDlg
, params
);
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
);
503 case MAKELONG(IDCANCEL
, BN_CLICKED
):
504 EndDialog(hwndDlg
, IDCANCEL
);
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
);
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
);
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
);
537 if (wParam
== ID_CAPSLOCKPOP
)
539 struct cred_dialog_params
*params
=
540 (struct cred_dialog_params
*)GetWindowLongPtrW(hwndDlg
, DWLP_USER
);
541 CredDialogHideBalloonTip(hwndDlg
, params
);
547 struct cred_dialog_params
*params
=
548 (struct cred_dialog_params
*)GetWindowLongPtrW(hwndDlg
, DWLP_USER
);
549 if (params
->hwndBalloonTip
) DestroyWindow(params
->hwndBalloonTip
);
557 static BOOL
find_existing_credential(const WCHAR
*target
, WCHAR
*username
, ULONG len_username
,
558 WCHAR
*password
, ULONG len_password
)
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 %u credentials\n", credentials
[i
]->Type
);
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
);
586 CredFree(credentials
);
590 /******************************************************************************
591 * CredUIPromptForCredentialsW [CREDUI.@]
593 DWORD WINAPI
CredUIPromptForCredentialsW(PCREDUI_INFOW pUIInfo
,
594 PCWSTR pszTargetName
,
595 PCtxtHandle Reserved
,
598 ULONG ulUsernameMaxChars
,
600 ULONG ulPasswordMaxChars
, PBOOL pfSave
,
604 struct cred_dialog_params params
;
605 DWORD result
= ERROR_SUCCESS
;
607 TRACE("(%p, %s, %p, %d, %s, %d, %p, %d, %p, 0x%08x)\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
;
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
;
628 params
.pszMessageText
= pUIInfo
->pszMessageText
;
629 params
.pszCaptionText
= pUIInfo
->pszCaptionText
;
630 params
.hbmBanner
= pUIInfo
->hbmBanner
;
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
)¶ms
);
651 return GetLastError();
655 TRACE("dialog cancelled\n");
656 return ERROR_CANCELLED
;
660 *pfSave
= params
.fSave
;
664 if (dwFlags
& CREDUI_FLAGS_EXPECT_CONFIRMATION
)
667 struct pending_credentials
*entry
;
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
))
678 HeapFree(GetProcessHeap(), 0, entry
->pszUsername
);
679 SecureZeroMemory(entry
->pszPassword
, lstrlenW(entry
->pszPassword
) * sizeof(WCHAR
));
680 HeapFree(GetProcessHeap(), 0, entry
->pszPassword
);
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);
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");
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
))
730 result
= save_credentials(entry
->pszTargetName
, entry
->pszUsername
,
731 entry
->pszPassword
, entry
->generic
);
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
);
747 LeaveCriticalSection(&csPendingCredentials
);
752 /******************************************************************************
753 * CredUIParseUserNameW [CREDUI.@]
755 DWORD WINAPI
CredUIParseUserNameW(PCWSTR pszUserName
, PWSTR pszUser
,
756 ULONG ulMaxUserChars
, PWSTR pszDomain
,
757 ULONG ulMaxDomainChars
)
761 TRACE("(%s, %p, %d, %p, %d)\n", debugstr_w(pszUserName
), pszUser
,
762 ulMaxUserChars
, pszDomain
, ulMaxDomainChars
);
764 if (!pszUserName
|| !pszUser
|| !ulMaxUserChars
|| !pszDomain
||
766 return ERROR_INVALID_PARAMETER
;
768 /* FIXME: handle marshaled credentials */
770 p
= wcschr(pszUserName
, '\\');
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
, '@');
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
);
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
);
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
);
846 *ppszUsername
= NULL
;
847 return ERROR_NOT_FOUND
;
850 /******************************************************************************
851 * CredUIInitControls [CREDUI.@]
853 BOOL WINAPI
CredUIInitControls(void)
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
);
873 CREDUI_INFOW
*cred_info
= info
;
874 SEC_WINNT_AUTH_IDENTITY_W
*id
= input_id
;
876 FIXME( "(%s, %p, %u, %s, %p, %p, %p, %x) 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
);
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
, '\\' )))
919 len_username
= lstrlenW( user
);
920 if (!wcsicmp( package
, L
"NTLM" ) || !wcsicmp( package
, L
"Negotiate" ))
923 len_domain
= ptr
- username
;
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
) );
938 id
->UserLength
= len_username
;
939 ptr
+= len_username
+ 1;
942 memcpy( ptr
, domain
, (len_domain
+ 1) * sizeof(WCHAR
) );
944 id
->DomainLength
= len_domain
;
945 ptr
+= len_domain
+ 1;
950 id
->DomainLength
= 0;
952 memcpy( ptr
, password
, (len_password
+ 1) * sizeof(WCHAR
) );
954 id
->PasswordLength
= len_password
;
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, %u, %p, %p, %u, %p, %p, %p, %08x) 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
,
981 FIXME( "(%08x, %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( "(%08x, %p, %u, %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
;