shell32: Some undocumented defines and functions are now in the PSDK.
[wine] / dlls / credui / credui_main.c
1 /*
2  * Credentials User Interface
3  *
4  * Copyright 2006 Robert Shearman (for CodeWeavers)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winnt.h"
26 #include "winuser.h"
27 #include "wincred.h"
28 #include "commctrl.h"
29
30 #include "credui_resources.h"
31
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
34 #include "wine/list.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(credui);
37
38 struct pending_credentials
39 {
40     struct list entry;
41     PWSTR pszTargetName;
42     PWSTR pszUsername;
43     PWSTR pszPassword;
44 };
45
46 static HINSTANCE hinstCredUI;
47
48 static struct list pending_credentials_list = LIST_INIT(pending_credentials_list);
49
50 static CRITICAL_SECTION csPendingCredentials;
51 static CRITICAL_SECTION_DEBUG critsect_debug =
52 {
53     0, 0, &csPendingCredentials,
54     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
55     0, 0, { (DWORD_PTR)(__FILE__ ": csPendingCredentials") }
56 };
57 static CRITICAL_SECTION csPendingCredentials = { &critsect_debug, -1, 0, 0, 0, 0 };
58
59
60 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
61 {
62     TRACE("(0x%p, %d, %p)\n",hinstDLL,fdwReason,lpvReserved);
63
64     if (fdwReason == DLL_WINE_PREATTACH) return FALSE;  /* prefer native version */
65
66     if (fdwReason == DLL_PROCESS_ATTACH)
67     {
68         DisableThreadLibraryCalls(hinstDLL);
69         hinstCredUI = hinstDLL;
70         InitCommonControls();
71     }
72     else if (fdwReason == DLL_PROCESS_DETACH)
73     {
74         struct pending_credentials *entry, *cursor2;
75         LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &pending_credentials_list, struct pending_credentials, entry)
76         {
77             list_remove(&entry->entry);
78
79             HeapFree(GetProcessHeap(), 0, entry->pszTargetName);
80             HeapFree(GetProcessHeap(), 0, entry->pszUsername);
81             HeapFree(GetProcessHeap(), 0, entry->pszPassword);
82             HeapFree(GetProcessHeap(), 0, entry);
83         }
84     }
85
86     return TRUE;
87 }
88
89 static DWORD save_credentials(PCWSTR pszTargetName, PCWSTR pszUsername,
90                               PCWSTR pszPassword)
91 {
92     FIXME("save servername %s with username %s\n", debugstr_w(pszTargetName), debugstr_w(pszUsername));
93     return ERROR_SUCCESS;
94 }
95
96 struct cred_dialog_params
97 {
98     PCWSTR pszTargetName;
99     PCWSTR pszMessageText;
100     PCWSTR pszCaptionText;
101     HBITMAP hbmBanner;
102     PWSTR pszUsername;
103     ULONG ulUsernameMaxChars;
104     PWSTR pszPassword;
105     ULONG ulPasswordMaxChars;
106     BOOL fSave;
107     DWORD dwFlags;
108 };
109
110 static INT_PTR CALLBACK CredDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
111                                        LPARAM lParam)
112 {
113     switch (uMsg)
114     {
115         case WM_INITDIALOG:
116         {
117             struct cred_dialog_params *params = (struct cred_dialog_params *)lParam;
118
119             SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)params);
120             if (params->pszMessageText)
121                 SetDlgItemTextW(hwndDlg, IDC_MESSAGE, params->pszMessageText);
122             else
123             {
124                 WCHAR format[256];
125                 WCHAR message[256];
126                 LoadStringW(hinstCredUI, IDS_MESSAGEFORMAT, format, sizeof(format)/sizeof(format[0]));
127                 snprintfW(message, sizeof(message)/sizeof(message[0]), format, params->pszTargetName);
128                 SetDlgItemTextW(hwndDlg, IDC_MESSAGE, message);
129             }
130             SetDlgItemTextW(hwndDlg, IDC_USERNAME, params->pszUsername);
131             SetDlgItemTextW(hwndDlg, IDC_PASSWORD, params->pszPassword);
132
133             if (params->pszUsername[0])
134                 SetFocus(GetDlgItem(hwndDlg, IDC_PASSWORD));
135             else
136                 SetFocus(GetDlgItem(hwndDlg, IDC_USERNAME));
137
138             if (params->pszCaptionText)
139                 SetWindowTextW(hwndDlg, params->pszCaptionText);
140             else
141             {
142                 WCHAR format[256];
143                 WCHAR title[256];
144                 LoadStringW(hinstCredUI, IDS_TITLEFORMAT, format, sizeof(format)/sizeof(format[0]));
145                 snprintfW(title, sizeof(title)/sizeof(title[0]), format, params->pszTargetName);
146                 SetWindowTextW(hwndDlg, title);
147             }
148
149             if (params->dwFlags & (CREDUI_FLAGS_DO_NOT_PERSIST|CREDUI_FLAGS_PERSIST))
150                 ShowWindow(GetDlgItem(hwndDlg, IDC_SAVE), SW_HIDE);
151             else if (params->fSave)
152                 CheckDlgButton(hwndDlg, IDC_SAVE, BST_CHECKED);
153
154             return FALSE;
155         }
156         case WM_COMMAND:
157             switch (wParam)
158             {
159                 case MAKELONG(IDOK, BN_CLICKED):
160                 {
161                     struct cred_dialog_params *params =
162                         (struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
163                     HWND hwndUsername = GetDlgItem(hwndDlg, IDC_USERNAME);
164                     LPWSTR user;
165                     INT len;
166                     INT len2;
167
168                     len = GetWindowTextLengthW(hwndUsername);
169                     user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
170                     GetWindowTextW(hwndUsername, user, len + 1);
171
172                     if (!user[0])
173                     {
174                         HeapFree(GetProcessHeap(), 0, user);
175                         return TRUE;
176                     }
177
178                     if (!strchrW(user, '\\') && !strchrW(user, '@'))
179                     {
180                         INT len_target = strlenW(params->pszTargetName);
181                         memcpy(params->pszUsername, params->pszTargetName,
182                                min(len_target, params->ulUsernameMaxChars) * sizeof(WCHAR));
183                         if (len_target + 1 < params->ulUsernameMaxChars)
184                             params->pszUsername[len_target] = '\\';
185                         if (len_target + 2 < params->ulUsernameMaxChars)
186                             params->pszUsername[len_target + 1] = '\0';
187                     }
188                     else if (params->ulUsernameMaxChars > 0)
189                         params->pszUsername[0] = '\0';
190
191                     len2 = strlenW(params->pszUsername);
192                     memcpy(params->pszUsername + len2, user, min(len, params->ulUsernameMaxChars - len2) * sizeof(WCHAR));
193                     if (params->ulUsernameMaxChars)
194                         params->pszUsername[len2 + min(len, params->ulUsernameMaxChars - len2 - 1)] = '\0';
195
196                     HeapFree(GetProcessHeap(), 0, user);
197
198                     GetDlgItemTextW(hwndDlg, IDC_PASSWORD, params->pszPassword,
199                                     params->ulPasswordMaxChars);
200
201                     EndDialog(hwndDlg, IDOK);
202                     return TRUE;
203                 }
204                 case MAKELONG(IDCANCEL, BN_CLICKED):
205                     EndDialog(hwndDlg, IDCANCEL);
206                     return TRUE;
207             }
208             /* fall through */
209         default:
210             return FALSE;
211     }
212 }
213
214 /******************************************************************************
215  *           CredUIPromptForCredentialsW [CREDUI.@]
216  */
217 DWORD WINAPI CredUIPromptForCredentialsW(PCREDUI_INFOW pUIInfo,
218                                          PCWSTR pszTargetName,
219                                          PCtxtHandle Reserved,
220                                          DWORD dwAuthError,
221                                          PWSTR pszUsername,
222                                          ULONG ulUsernameMaxChars,
223                                          PWSTR pszPassword,
224                                          ULONG ulPasswordMaxChars, PBOOL pfSave,
225                                          DWORD dwFlags)
226 {
227     INT_PTR ret;
228     struct cred_dialog_params params;
229     DWORD result = ERROR_SUCCESS;
230
231     TRACE("(%p, %s, %p, %d, %s, %d, %p, %d, %p, 0x%08x)\n", pUIInfo,
232           debugstr_w(pszTargetName), Reserved, dwAuthError, debugstr_w(pszUsername),
233           ulUsernameMaxChars, pszPassword, ulPasswordMaxChars, pfSave, dwFlags);
234
235     if ((dwFlags & (CREDUI_FLAGS_ALWAYS_SHOW_UI|CREDUI_FLAGS_GENERIC_CREDENTIALS)) == CREDUI_FLAGS_ALWAYS_SHOW_UI)
236         return ERROR_INVALID_FLAGS;
237
238     if (!pszTargetName)
239         return ERROR_INVALID_PARAMETER;
240
241     if ((dwFlags & CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX) && !pfSave)
242         return ERROR_INVALID_PARAMETER;
243
244     params.pszTargetName = pszTargetName;
245     if (pUIInfo)
246     {
247         params.pszMessageText = pUIInfo->pszMessageText;
248         params.pszCaptionText = pUIInfo->pszCaptionText;
249         params.hbmBanner  = pUIInfo->hbmBanner;
250     }
251     else
252     {
253         params.pszMessageText = NULL;
254         params.pszCaptionText = NULL;
255         params.hbmBanner = NULL;
256     }
257     params.pszUsername = pszUsername;
258     params.ulUsernameMaxChars = ulUsernameMaxChars;
259     params.pszPassword = pszPassword;
260     params.ulPasswordMaxChars = ulPasswordMaxChars;
261     params.fSave = pfSave ? *pfSave : FALSE;
262     params.dwFlags = dwFlags;
263
264     ret = DialogBoxParamW(hinstCredUI, MAKEINTRESOURCEW(IDD_CREDDIALOG),
265                           pUIInfo ? pUIInfo->hwndParent : NULL,
266                           CredDialogProc, (LPARAM)&params);
267     if (ret <= 0)
268         return GetLastError();
269
270     if (ret == IDCANCEL)
271     {
272         TRACE("dialog cancelled\n");
273         return ERROR_CANCELLED;
274     }
275
276     if (pfSave)
277         *pfSave = params.fSave;
278
279     if (params.fSave)
280     {
281         if (dwFlags & CREDUI_FLAGS_EXPECT_CONFIRMATION)
282         {
283             BOOL found = FALSE;
284             struct pending_credentials *entry;
285             int len;
286
287             EnterCriticalSection(&csPendingCredentials);
288
289             /* find existing pending credentials for the same target and overwrite */
290             /* FIXME: is this correct? */
291             LIST_FOR_EACH_ENTRY(entry, &pending_credentials_list, struct pending_credentials, entry)
292                 if (!strcmpW(pszTargetName, entry->pszTargetName))
293                 {
294                     found = TRUE;
295                     HeapFree(GetProcessHeap(), 0, entry->pszUsername);
296                     HeapFree(GetProcessHeap(), 0, entry->pszPassword);
297                 }
298
299             if (!found)
300             {
301                 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
302                 list_init(&entry->entry);
303                 len = strlenW(pszTargetName);
304                 entry->pszTargetName = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
305                 memcpy(entry->pszTargetName, pszTargetName, (len + 1)*sizeof(WCHAR));
306                 list_add_tail(&entry->entry, &pending_credentials_list);
307             }
308
309             len = strlenW(params.pszUsername);
310             entry->pszUsername = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
311             memcpy(entry->pszUsername, params.pszUsername, (len + 1)*sizeof(WCHAR));
312             len = strlenW(params.pszPassword);
313             entry->pszPassword = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
314             memcpy(entry->pszPassword, params.pszPassword, (len + 1)*sizeof(WCHAR));
315
316             LeaveCriticalSection(&csPendingCredentials);
317         }
318         else
319             result = save_credentials(pszTargetName, pszUsername, pszPassword);
320     }
321
322     return result;
323 }
324
325 /******************************************************************************
326  *           CredUIConfirmCredentialsW [CREDUI.@]
327  */
328 DWORD WINAPI CredUIConfirmCredentialsW(PCWSTR pszTargetName, BOOL bConfirm)
329 {
330     struct pending_credentials *entry;
331     DWORD result = ERROR_NOT_FOUND;
332
333     TRACE("(%s, %s)\n", debugstr_w(pszTargetName), bConfirm ? "TRUE" : "FALSE");
334
335     if (!pszTargetName)
336         return ERROR_INVALID_PARAMETER;
337
338     EnterCriticalSection(&csPendingCredentials);
339
340     LIST_FOR_EACH_ENTRY(entry, &pending_credentials_list, struct pending_credentials, entry)
341     {
342         if (!strcmpW(pszTargetName, entry->pszTargetName))
343         {
344             if (bConfirm)
345                 result = save_credentials(entry->pszTargetName, entry->pszUsername, entry->pszPassword);
346             else
347                 result = ERROR_SUCCESS;
348
349             list_remove(&entry->entry);
350
351             HeapFree(GetProcessHeap(), 0, entry->pszTargetName);
352             HeapFree(GetProcessHeap(), 0, entry->pszUsername);
353             HeapFree(GetProcessHeap(), 0, entry->pszPassword);
354             HeapFree(GetProcessHeap(), 0, entry);
355
356             break;
357         }
358     }
359
360     LeaveCriticalSection(&csPendingCredentials);
361
362     return result;
363 }
364
365 /******************************************************************************
366  *           CredUIParseUserNameW [CREDUI.@]
367  */
368 DWORD WINAPI CredUIParseUserNameW(PCWSTR pszUserName, PWSTR pszUser,
369                                   ULONG ulMaxUserChars, PWSTR pszDomain,
370                                   ULONG ulMaxDomainChars)
371 {
372     PWSTR p;
373
374     TRACE("(%s, %p, %d, %p, %d)\n", debugstr_w(pszUserName), pszUser,
375           ulMaxUserChars, pszDomain, ulMaxDomainChars);
376
377     if (!pszUserName || !pszUser || !ulMaxUserChars || !pszDomain ||
378         !ulMaxDomainChars)
379         return ERROR_INVALID_PARAMETER;
380
381     /* FIXME: handle marshaled credentials */
382
383     p = strchrW(pszUserName, '\\');
384     if (p)
385     {
386         if (p - pszUserName > ulMaxDomainChars - 1)
387             return ERROR_INSUFFICIENT_BUFFER;
388         if (strlenW(p + 1) > ulMaxUserChars - 1)
389             return ERROR_INSUFFICIENT_BUFFER;
390         strcpyW(pszUser, p + 1);
391         memcpy(pszDomain, pszUserName, (p - pszUserName)*sizeof(WCHAR));
392         pszDomain[p - pszUserName] = '\0';
393
394         return ERROR_SUCCESS;
395     }
396
397     p = strrchrW(pszUserName, '@');
398     if (p)
399     {
400         if (p + 1 - pszUserName > ulMaxUserChars - 1)
401             return ERROR_INSUFFICIENT_BUFFER;
402         if (strlenW(p + 1) > ulMaxDomainChars - 1)
403             return ERROR_INSUFFICIENT_BUFFER;
404         strcpyW(pszDomain, p + 1);
405         memcpy(pszUser, pszUserName, (p - pszUserName)*sizeof(WCHAR));
406         pszUser[p - pszUserName] = '\0';
407
408         return ERROR_SUCCESS;
409     }
410
411     if (strlenW(pszUserName) > ulMaxUserChars - 1)
412         return ERROR_INSUFFICIENT_BUFFER;
413     strcpyW(pszUser, pszUserName);
414     pszDomain[0] = '\0';
415
416     return ERROR_SUCCESS;
417 }
418
419 /******************************************************************************
420  *           CredUIStoreSSOCredA [CREDUI.@]
421  */
422 DWORD WINAPI CredUIStoreSSOCredA(PCSTR pszRealm, PCSTR pszUsername,
423                                  PCSTR pszPassword, BOOL bPersist)
424 {
425     FIXME("(%s, %s, %p, %d)\n", debugstr_a(pszRealm), debugstr_a(pszUsername),
426           pszPassword, bPersist);
427     return ERROR_SUCCESS;
428 }
429
430 /******************************************************************************
431  *           CredUIStoreSSOCredW [CREDUI.@]
432  */
433 DWORD WINAPI CredUIStoreSSOCredW(PCWSTR pszRealm, PCWSTR pszUsername,
434                                  PCWSTR pszPassword, BOOL bPersist)
435 {
436     FIXME("(%s, %s, %p, %d)\n", debugstr_w(pszRealm), debugstr_w(pszUsername),
437           pszPassword, bPersist);
438     return ERROR_SUCCESS;
439 }
440
441 /******************************************************************************
442  *           CredUIReadSSOCredA [CREDUI.@]
443  */
444 DWORD WINAPI CredUIReadSSOCredA(PCSTR pszRealm, PSTR *ppszUsername)
445 {
446     FIXME("(%s, %p)\n", debugstr_a(pszRealm), ppszUsername);
447     if (ppszUsername)
448         *ppszUsername = NULL;
449     return ERROR_NOT_FOUND;
450 }
451
452 /******************************************************************************
453  *           CredUIReadSSOCredW [CREDUI.@]
454  */
455 DWORD WINAPI CredUIReadSSOCredW(PCWSTR pszRealm, PWSTR *ppszUsername)
456 {
457     FIXME("(%s, %p)\n", debugstr_w(pszRealm), ppszUsername);
458     if (ppszUsername)
459         *ppszUsername = NULL;
460     return ERROR_NOT_FOUND;
461 }