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