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
30 #include "credui_resources.h"
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
34 #include "wine/list.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(credui
);
38 struct pending_credentials
47 static HINSTANCE hinstCredUI
;
49 static struct list pending_credentials_list
= LIST_INIT(pending_credentials_list
);
51 static CRITICAL_SECTION csPendingCredentials
;
52 static CRITICAL_SECTION_DEBUG critsect_debug
=
54 0, 0, &csPendingCredentials
,
55 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
56 0, 0, { (DWORD_PTR
)(__FILE__
": csPendingCredentials") }
58 static CRITICAL_SECTION csPendingCredentials
= { &critsect_debug
, -1, 0, 0, 0, 0 };
61 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
63 TRACE("(0x%p, %d, %p)\n",hinstDLL
,fdwReason
,lpvReserved
);
65 if (fdwReason
== DLL_WINE_PREATTACH
) return FALSE
; /* prefer native version */
67 if (fdwReason
== DLL_PROCESS_ATTACH
)
69 DisableThreadLibraryCalls(hinstDLL
);
70 hinstCredUI
= hinstDLL
;
73 else if (fdwReason
== DLL_PROCESS_DETACH
)
75 struct pending_credentials
*entry
, *cursor2
;
76 LIST_FOR_EACH_ENTRY_SAFE(entry
, cursor2
, &pending_credentials_list
, struct pending_credentials
, entry
)
78 list_remove(&entry
->entry
);
80 HeapFree(GetProcessHeap(), 0, entry
->pszTargetName
);
81 HeapFree(GetProcessHeap(), 0, entry
->pszUsername
);
82 HeapFree(GetProcessHeap(), 0, entry
->pszPassword
);
83 HeapFree(GetProcessHeap(), 0, entry
);
90 static DWORD
save_credentials(PCWSTR pszTargetName
, PCWSTR pszUsername
,
91 PCWSTR pszPassword
, BOOL generic
)
95 TRACE("saving servername %s with username %s\n", debugstr_w(pszTargetName
), debugstr_w(pszUsername
));
98 cred
.Type
= generic
? CRED_TYPE_GENERIC
: CRED_TYPE_DOMAIN_PASSWORD
;
99 cred
.TargetName
= (LPWSTR
)pszTargetName
;
101 cred
.CredentialBlobSize
= strlenW(pszPassword
) * sizeof(WCHAR
);
102 cred
.CredentialBlob
= (LPBYTE
)pszPassword
;
103 cred
.Persist
= CRED_PERSIST_ENTERPRISE
;
104 cred
.AttributeCount
= 0;
105 cred
.Attributes
= NULL
;
106 cred
.TargetAlias
= NULL
;
107 cred
.UserName
= (LPWSTR
)pszUsername
;
109 if (CredWriteW(&cred
, 0))
110 return ERROR_SUCCESS
;
113 DWORD ret
= GetLastError();
114 ERR("CredWriteW failed with error %d\n", ret
);
119 struct cred_dialog_params
121 PCWSTR pszTargetName
;
122 PCWSTR pszMessageText
;
123 PCWSTR pszCaptionText
;
126 ULONG ulUsernameMaxChars
;
128 ULONG ulPasswordMaxChars
;
133 static void CredDialogFillUsernameCombo(HWND hwndUsername
, struct cred_dialog_params
*params
)
137 PCREDENTIALW
*credentials
;
139 if (!CredEnumerateW(NULL
, 0, &count
, &credentials
))
142 for (i
= 0; i
< count
; i
++)
144 COMBOBOXEXITEMW comboitem
;
146 if (params
->dwFlags
& CREDUI_FLAGS_GENERIC_CREDENTIALS
)
148 if ((credentials
[i
]->Type
!= CRED_TYPE_GENERIC
) || !credentials
[i
]->UserName
)
153 if (credentials
[i
]->Type
== CRED_TYPE_GENERIC
)
157 comboitem
.mask
= CBEIF_TEXT
;
158 comboitem
.iItem
= -1;
159 comboitem
.pszText
= credentials
[i
]->UserName
;
160 SendMessageW(hwndUsername
, CBEM_INSERTITEMW
, 0, (LPARAM
)&comboitem
);
163 CredFree(credentials
);
166 static BOOL
CredDialogInit(HWND hwndDlg
, struct cred_dialog_params
*params
)
168 HWND hwndUsername
= GetDlgItem(hwndDlg
, IDC_USERNAME
);
169 HWND hwndPassword
= GetDlgItem(hwndDlg
, IDC_PASSWORD
);
171 SetWindowLongPtrW(hwndDlg
, DWLP_USER
, (LONG_PTR
)params
);
172 if (params
->pszMessageText
)
173 SetDlgItemTextW(hwndDlg
, IDC_MESSAGE
, params
->pszMessageText
);
178 LoadStringW(hinstCredUI
, IDS_MESSAGEFORMAT
, format
, sizeof(format
)/sizeof(format
[0]));
179 snprintfW(message
, sizeof(message
)/sizeof(message
[0]), format
, params
->pszTargetName
);
180 SetDlgItemTextW(hwndDlg
, IDC_MESSAGE
, message
);
182 SetWindowTextW(hwndUsername
, params
->pszUsername
);
183 SetWindowTextW(hwndPassword
, params
->pszPassword
);
185 CredDialogFillUsernameCombo(hwndUsername
, params
);
187 if (params
->pszUsername
[0])
188 SetFocus(hwndPassword
);
190 SetFocus(hwndUsername
);
192 if (params
->pszCaptionText
)
193 SetWindowTextW(hwndDlg
, params
->pszCaptionText
);
198 LoadStringW(hinstCredUI
, IDS_TITLEFORMAT
, format
, sizeof(format
)/sizeof(format
[0]));
199 snprintfW(title
, sizeof(title
)/sizeof(title
[0]), format
, params
->pszTargetName
);
200 SetWindowTextW(hwndDlg
, title
);
203 if (params
->dwFlags
& (CREDUI_FLAGS_DO_NOT_PERSIST
|CREDUI_FLAGS_PERSIST
))
204 ShowWindow(GetDlgItem(hwndDlg
, IDC_SAVE
), SW_HIDE
);
205 else if (params
->fSave
)
206 CheckDlgButton(hwndDlg
, IDC_SAVE
, BST_CHECKED
);
211 static void CredDialogCommandOk(HWND hwndDlg
, struct cred_dialog_params
*params
)
213 HWND hwndUsername
= GetDlgItem(hwndDlg
, IDC_USERNAME
);
218 len
= GetWindowTextLengthW(hwndUsername
);
219 user
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
220 GetWindowTextW(hwndUsername
, user
, len
+ 1);
224 HeapFree(GetProcessHeap(), 0, user
);
228 if (!strchrW(user
, '\\') && !strchrW(user
, '@'))
230 INT len_target
= strlenW(params
->pszTargetName
);
231 memcpy(params
->pszUsername
, params
->pszTargetName
,
232 min(len_target
, params
->ulUsernameMaxChars
) * sizeof(WCHAR
));
233 if (len_target
+ 1 < params
->ulUsernameMaxChars
)
234 params
->pszUsername
[len_target
] = '\\';
235 if (len_target
+ 2 < params
->ulUsernameMaxChars
)
236 params
->pszUsername
[len_target
+ 1] = '\0';
238 else if (params
->ulUsernameMaxChars
> 0)
239 params
->pszUsername
[0] = '\0';
241 len2
= strlenW(params
->pszUsername
);
242 memcpy(params
->pszUsername
+ len2
, user
, min(len
, params
->ulUsernameMaxChars
- len2
) * sizeof(WCHAR
));
243 if (params
->ulUsernameMaxChars
)
244 params
->pszUsername
[len2
+ min(len
, params
->ulUsernameMaxChars
- len2
- 1)] = '\0';
246 HeapFree(GetProcessHeap(), 0, user
);
248 GetDlgItemTextW(hwndDlg
, IDC_PASSWORD
, params
->pszPassword
,
249 params
->ulPasswordMaxChars
);
251 EndDialog(hwndDlg
, IDOK
);
254 static INT_PTR CALLBACK
CredDialogProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
,
261 struct cred_dialog_params
*params
= (struct cred_dialog_params
*)lParam
;
263 return CredDialogInit(hwndDlg
, params
);
268 case MAKELONG(IDOK
, BN_CLICKED
):
270 struct cred_dialog_params
*params
=
271 (struct cred_dialog_params
*)GetWindowLongPtrW(hwndDlg
, DWLP_USER
);
272 CredDialogCommandOk(hwndDlg
, params
);
275 case MAKELONG(IDCANCEL
, BN_CLICKED
):
276 EndDialog(hwndDlg
, IDCANCEL
);
285 /******************************************************************************
286 * CredUIPromptForCredentialsW [CREDUI.@]
288 DWORD WINAPI
CredUIPromptForCredentialsW(PCREDUI_INFOW pUIInfo
,
289 PCWSTR pszTargetName
,
290 PCtxtHandle Reserved
,
293 ULONG ulUsernameMaxChars
,
295 ULONG ulPasswordMaxChars
, PBOOL pfSave
,
299 struct cred_dialog_params params
;
300 DWORD result
= ERROR_SUCCESS
;
302 TRACE("(%p, %s, %p, %d, %s, %d, %p, %d, %p, 0x%08x)\n", pUIInfo
,
303 debugstr_w(pszTargetName
), Reserved
, dwAuthError
, debugstr_w(pszUsername
),
304 ulUsernameMaxChars
, pszPassword
, ulPasswordMaxChars
, pfSave
, dwFlags
);
306 if ((dwFlags
& (CREDUI_FLAGS_ALWAYS_SHOW_UI
|CREDUI_FLAGS_GENERIC_CREDENTIALS
)) == CREDUI_FLAGS_ALWAYS_SHOW_UI
)
307 return ERROR_INVALID_FLAGS
;
310 return ERROR_INVALID_PARAMETER
;
312 if ((dwFlags
& CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX
) && !pfSave
)
313 return ERROR_INVALID_PARAMETER
;
315 params
.pszTargetName
= pszTargetName
;
318 params
.pszMessageText
= pUIInfo
->pszMessageText
;
319 params
.pszCaptionText
= pUIInfo
->pszCaptionText
;
320 params
.hbmBanner
= pUIInfo
->hbmBanner
;
324 params
.pszMessageText
= NULL
;
325 params
.pszCaptionText
= NULL
;
326 params
.hbmBanner
= NULL
;
328 params
.pszUsername
= pszUsername
;
329 params
.ulUsernameMaxChars
= ulUsernameMaxChars
;
330 params
.pszPassword
= pszPassword
;
331 params
.ulPasswordMaxChars
= ulPasswordMaxChars
;
332 params
.fSave
= pfSave
? *pfSave
: FALSE
;
333 params
.dwFlags
= dwFlags
;
335 ret
= DialogBoxParamW(hinstCredUI
, MAKEINTRESOURCEW(IDD_CREDDIALOG
),
336 pUIInfo
? pUIInfo
->hwndParent
: NULL
,
337 CredDialogProc
, (LPARAM
)¶ms
);
339 return GetLastError();
343 TRACE("dialog cancelled\n");
344 return ERROR_CANCELLED
;
348 *pfSave
= params
.fSave
;
352 if (dwFlags
& CREDUI_FLAGS_EXPECT_CONFIRMATION
)
355 struct pending_credentials
*entry
;
358 EnterCriticalSection(&csPendingCredentials
);
360 /* find existing pending credentials for the same target and overwrite */
361 /* FIXME: is this correct? */
362 LIST_FOR_EACH_ENTRY(entry
, &pending_credentials_list
, struct pending_credentials
, entry
)
363 if (!strcmpW(pszTargetName
, entry
->pszTargetName
))
366 HeapFree(GetProcessHeap(), 0, entry
->pszUsername
);
367 HeapFree(GetProcessHeap(), 0, entry
->pszPassword
);
372 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
373 list_init(&entry
->entry
);
374 len
= strlenW(pszTargetName
);
375 entry
->pszTargetName
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1)*sizeof(WCHAR
));
376 memcpy(entry
->pszTargetName
, pszTargetName
, (len
+ 1)*sizeof(WCHAR
));
377 list_add_tail(&entry
->entry
, &pending_credentials_list
);
380 len
= strlenW(params
.pszUsername
);
381 entry
->pszUsername
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1)*sizeof(WCHAR
));
382 memcpy(entry
->pszUsername
, params
.pszUsername
, (len
+ 1)*sizeof(WCHAR
));
383 len
= strlenW(params
.pszPassword
);
384 entry
->pszPassword
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1)*sizeof(WCHAR
));
385 memcpy(entry
->pszPassword
, params
.pszPassword
, (len
+ 1)*sizeof(WCHAR
));
386 entry
->generic
= dwFlags
& CREDUI_FLAGS_GENERIC_CREDENTIALS
? TRUE
: FALSE
;
388 LeaveCriticalSection(&csPendingCredentials
);
391 result
= save_credentials(pszTargetName
, pszUsername
, pszPassword
,
392 dwFlags
& CREDUI_FLAGS_GENERIC_CREDENTIALS
? TRUE
: FALSE
);
398 /******************************************************************************
399 * CredUIConfirmCredentialsW [CREDUI.@]
401 DWORD WINAPI
CredUIConfirmCredentialsW(PCWSTR pszTargetName
, BOOL bConfirm
)
403 struct pending_credentials
*entry
;
404 DWORD result
= ERROR_NOT_FOUND
;
406 TRACE("(%s, %s)\n", debugstr_w(pszTargetName
), bConfirm
? "TRUE" : "FALSE");
409 return ERROR_INVALID_PARAMETER
;
411 EnterCriticalSection(&csPendingCredentials
);
413 LIST_FOR_EACH_ENTRY(entry
, &pending_credentials_list
, struct pending_credentials
, entry
)
415 if (!strcmpW(pszTargetName
, entry
->pszTargetName
))
418 result
= save_credentials(entry
->pszTargetName
, entry
->pszUsername
,
419 entry
->pszPassword
, entry
->generic
);
421 result
= ERROR_SUCCESS
;
423 list_remove(&entry
->entry
);
425 HeapFree(GetProcessHeap(), 0, entry
->pszTargetName
);
426 HeapFree(GetProcessHeap(), 0, entry
->pszUsername
);
427 HeapFree(GetProcessHeap(), 0, entry
->pszPassword
);
428 HeapFree(GetProcessHeap(), 0, entry
);
434 LeaveCriticalSection(&csPendingCredentials
);
439 /******************************************************************************
440 * CredUIParseUserNameW [CREDUI.@]
442 DWORD WINAPI
CredUIParseUserNameW(PCWSTR pszUserName
, PWSTR pszUser
,
443 ULONG ulMaxUserChars
, PWSTR pszDomain
,
444 ULONG ulMaxDomainChars
)
448 TRACE("(%s, %p, %d, %p, %d)\n", debugstr_w(pszUserName
), pszUser
,
449 ulMaxUserChars
, pszDomain
, ulMaxDomainChars
);
451 if (!pszUserName
|| !pszUser
|| !ulMaxUserChars
|| !pszDomain
||
453 return ERROR_INVALID_PARAMETER
;
455 /* FIXME: handle marshaled credentials */
457 p
= strchrW(pszUserName
, '\\');
460 if (p
- pszUserName
> ulMaxDomainChars
- 1)
461 return ERROR_INSUFFICIENT_BUFFER
;
462 if (strlenW(p
+ 1) > ulMaxUserChars
- 1)
463 return ERROR_INSUFFICIENT_BUFFER
;
464 strcpyW(pszUser
, p
+ 1);
465 memcpy(pszDomain
, pszUserName
, (p
- pszUserName
)*sizeof(WCHAR
));
466 pszDomain
[p
- pszUserName
] = '\0';
468 return ERROR_SUCCESS
;
471 p
= strrchrW(pszUserName
, '@');
474 if (p
+ 1 - pszUserName
> ulMaxUserChars
- 1)
475 return ERROR_INSUFFICIENT_BUFFER
;
476 if (strlenW(p
+ 1) > ulMaxDomainChars
- 1)
477 return ERROR_INSUFFICIENT_BUFFER
;
478 strcpyW(pszDomain
, p
+ 1);
479 memcpy(pszUser
, pszUserName
, (p
- pszUserName
)*sizeof(WCHAR
));
480 pszUser
[p
- pszUserName
] = '\0';
482 return ERROR_SUCCESS
;
485 if (strlenW(pszUserName
) > ulMaxUserChars
- 1)
486 return ERROR_INSUFFICIENT_BUFFER
;
487 strcpyW(pszUser
, pszUserName
);
490 return ERROR_SUCCESS
;
493 /******************************************************************************
494 * CredUIStoreSSOCredA [CREDUI.@]
496 DWORD WINAPI
CredUIStoreSSOCredA(PCSTR pszRealm
, PCSTR pszUsername
,
497 PCSTR pszPassword
, BOOL bPersist
)
499 FIXME("(%s, %s, %p, %d)\n", debugstr_a(pszRealm
), debugstr_a(pszUsername
),
500 pszPassword
, bPersist
);
501 return ERROR_SUCCESS
;
504 /******************************************************************************
505 * CredUIStoreSSOCredW [CREDUI.@]
507 DWORD WINAPI
CredUIStoreSSOCredW(PCWSTR pszRealm
, PCWSTR pszUsername
,
508 PCWSTR pszPassword
, BOOL bPersist
)
510 FIXME("(%s, %s, %p, %d)\n", debugstr_w(pszRealm
), debugstr_w(pszUsername
),
511 pszPassword
, bPersist
);
512 return ERROR_SUCCESS
;
515 /******************************************************************************
516 * CredUIReadSSOCredA [CREDUI.@]
518 DWORD WINAPI
CredUIReadSSOCredA(PCSTR pszRealm
, PSTR
*ppszUsername
)
520 FIXME("(%s, %p)\n", debugstr_a(pszRealm
), ppszUsername
);
522 *ppszUsername
= NULL
;
523 return ERROR_NOT_FOUND
;
526 /******************************************************************************
527 * CredUIReadSSOCredW [CREDUI.@]
529 DWORD WINAPI
CredUIReadSSOCredW(PCWSTR pszRealm
, PWSTR
*ppszUsername
)
531 FIXME("(%s, %p)\n", debugstr_w(pszRealm
), ppszUsername
);
533 *ppszUsername
= NULL
;
534 return ERROR_NOT_FOUND
;