[SYSDM] Simplify AddUserProfile() by using fixed size buffers for account and domain...
[reactos.git] / dll / cpl / sysdm / userprofile.c
1 /*
2 * PROJECT: ReactOS System Control Panel Applet
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/cpl/sysdm/userprofile.c
5 * PURPOSE: Computer settings for networking
6 * COPYRIGHT: Copyright Thomas Weidenmueller <w3seek@reactos.org>
7 * Copyright 2006 Ged Murphy <gedmurphy@gmail.com>
8 *
9 */
10
11 #include "precomp.h"
12 #include <sddl.h>
13
14 #include <debug.h>
15
16 typedef struct _PROFILEDATA
17 {
18 BOOL bMyProfile;
19 PWSTR pszFullName;
20 } PROFILEDATA, *PPROFILEDATA;
21
22
23 static
24 BOOL
25 OnProfileTypeInit(
26 HWND hwndDlg,
27 PPROFILEDATA pProfileData)
28 {
29 PWSTR pszRawBuffer = NULL, pszCookedBuffer = NULL;
30 INT nLength;
31
32 nLength = LoadStringW(hApplet, IDS_USERPROFILE_TYPE_TEXT, (PWSTR)&pszRawBuffer, 0);
33 pszRawBuffer = NULL;
34 if (nLength == 0)
35 return FALSE;
36
37 pszRawBuffer = HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(WCHAR));
38 if (pszRawBuffer == NULL)
39 return FALSE;
40
41 LoadStringW(hApplet, IDS_USERPROFILE_TYPE_TEXT, pszRawBuffer, nLength + 1);
42
43 pszCookedBuffer = HeapAlloc(GetProcessHeap(), 0, (nLength + wcslen(pProfileData->pszFullName) + 1) * sizeof(WCHAR));
44 if (pszCookedBuffer == NULL)
45 goto done;
46
47 swprintf(pszCookedBuffer, pszRawBuffer, pProfileData->pszFullName);
48
49 /* Set the full text */
50 SetDlgItemText(hwndDlg, IDC_USERPROFILE_TYPE_TEXT, pszCookedBuffer);
51
52 /* FIXME: Right now, we support local user profiles only! */
53 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_TYPE_ROAMING), FALSE);
54 Button_SetCheck(GetDlgItem(hwndDlg, IDC_USERPROFILE_TYPE_LOCAL), BST_CHECKED);
55 EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
56
57 done:
58 if (pszCookedBuffer != NULL)
59 HeapFree(GetProcessHeap(), 0, pszCookedBuffer);
60
61 if (pszRawBuffer != NULL)
62 HeapFree(GetProcessHeap(), 0, pszRawBuffer);
63
64 return TRUE;
65 }
66
67
68 static
69 INT_PTR
70 CALLBACK
71 UserProfileTypeDlgProc(HWND hwndDlg,
72 UINT uMsg,
73 WPARAM wParam,
74 LPARAM lParam)
75 {
76 switch (uMsg)
77 {
78 case WM_INITDIALOG:
79 OnProfileTypeInit(hwndDlg, (PPROFILEDATA)lParam);
80 return TRUE;
81
82 case WM_DESTROY:
83 break;
84
85 case WM_COMMAND:
86 switch (LOWORD(wParam))
87 {
88 case IDOK:
89 case IDCANCEL:
90 EndDialog(hwndDlg,
91 LOWORD(wParam));
92 return TRUE;
93 }
94 break;
95 }
96
97 return FALSE;
98 }
99
100
101 static
102 BOOL
103 ChangeUserProfileType(
104 _In_ HWND hwndDlg)
105 {
106 HWND hwndListView;
107 LVITEM Item;
108 INT iSelected;
109
110 DPRINT("ChangeUserProfileType(%p)\n", hwndDlg);
111
112 hwndListView = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST);
113 if (hwndListView == NULL)
114 return FALSE;
115
116 iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED);
117 if (iSelected == -1)
118 return FALSE;
119
120 ZeroMemory(&Item, sizeof(LVITEM));
121 Item.mask = LVIF_PARAM;
122 Item.iItem = iSelected;
123 Item.iSubItem = 0;
124 if (!ListView_GetItem(hwndListView, &Item))
125 return FALSE;
126
127 if (Item.lParam == 0)
128 return FALSE;
129
130 if (DialogBoxParam(hApplet,
131 MAKEINTRESOURCE(IDD_USERPROFILE_TYPE),
132 hwndDlg,
133 UserProfileTypeDlgProc,
134 (LPARAM)Item.lParam) == IDOK)
135 {
136 /* FIXME: Update the profile list view */
137 return TRUE;
138 }
139
140 return FALSE;
141 }
142
143
144 static VOID
145 SetListViewColumns(
146 _In_ HWND hwndListView)
147 {
148 LV_COLUMN column;
149 RECT rect;
150 TCHAR szStr[32];
151
152 GetClientRect(hwndListView, &rect);
153
154 SendMessage(hwndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
155
156 memset(&column, 0x00, sizeof(column));
157 column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM | LVCF_TEXT;
158 column.fmt = LVCFMT_LEFT;
159 column.cx = (INT)((rect.right - rect.left) * 0.40);
160 column.iSubItem = 0;
161 LoadString(hApplet, IDS_USERPROFILE_NAME, szStr, ARRAYSIZE(szStr));
162 column.pszText = szStr;
163 (void)ListView_InsertColumn(hwndListView, 0, &column);
164
165 column.fmt = LVCFMT_RIGHT;
166 column.cx = (INT)((rect.right - rect.left) * 0.15);
167 column.iSubItem = 1;
168 LoadString(hApplet, IDS_USERPROFILE_SIZE, szStr, ARRAYSIZE(szStr));
169 column.pszText = szStr;
170 (void)ListView_InsertColumn(hwndListView, 1, &column);
171
172 column.fmt = LVCFMT_LEFT;
173 column.cx = (INT)((rect.right - rect.left) * 0.15);
174 column.iSubItem = 2;
175 LoadString(hApplet, IDS_USERPROFILE_TYPE, szStr, ARRAYSIZE(szStr));
176 column.pszText = szStr;
177 (void)ListView_InsertColumn(hwndListView, 2, &column);
178
179 column.fmt = LVCFMT_LEFT;
180 column.cx = (INT)((rect.right - rect.left) * 0.15);
181 column.iSubItem = 3;
182 LoadString(hApplet, IDS_USERPROFILE_STATUS, szStr, ARRAYSIZE(szStr));
183 column.pszText = szStr;
184 (void)ListView_InsertColumn(hwndListView, 3, &column);
185
186 column.fmt = LVCFMT_LEFT;
187 column.cx = (INT)((rect.right - rect.left) * 0.15) - GetSystemMetrics(SM_CYHSCROLL);
188 column.iSubItem = 4;
189 LoadString(hApplet, IDS_USERPROFILE_MODIFIED, szStr, ARRAYSIZE(szStr));
190 column.pszText = szStr;
191 (void)ListView_InsertColumn(hwndListView, 4, &column);
192 }
193
194
195 static VOID
196 AddUserProfile(
197 _In_ HWND hwndListView,
198 _In_ LPTSTR lpProfileSid,
199 _In_ PSID pMySid,
200 _In_ HKEY hProfileKey)
201 {
202 PPROFILEDATA pProfileData = NULL;
203 WCHAR szAccountName[128], szDomainName[128];
204 WCHAR szNameBuffer[256];
205 SID_NAME_USE Use;
206 DWORD dwAccountNameSize, dwDomainNameSize;
207 DWORD dwProfileData;
208 PWSTR ptr;
209 PSID pSid = NULL;
210 LV_ITEM lvi;
211
212 if (!ConvertStringSidToSid(lpProfileSid,
213 &pSid))
214 return;
215
216 dwAccountNameSize = ARRAYSIZE(szAccountName);
217 dwDomainNameSize = ARRAYSIZE(szDomainName);
218 if (!LookupAccountSidW(NULL,
219 pSid,
220 szAccountName,
221 &dwAccountNameSize,
222 szDomainName,
223 &dwDomainNameSize,
224 &Use))
225 {
226 /* Unknown account */
227 LoadStringW(hApplet, IDS_USERPROFILE_ACCOUNT_UNKNOWN, szNameBuffer, ARRAYSIZE(szNameBuffer));
228 }
229 else
230 {
231 /* Show only the user accounts */
232 if (Use != SidTypeUser)
233 goto done;
234
235 if (szAccountName[0] == UNICODE_NULL)
236 {
237 /* Deleted account */
238 LoadStringW(hApplet, IDS_USERPROFILE_ACCOUNT_DELETED, szNameBuffer, ARRAYSIZE(szNameBuffer));
239 }
240 else
241 {
242 /* Normal account */
243 wsprintf(szNameBuffer, L"%s\\%s", szDomainName, szAccountName);
244 }
245 }
246
247 dwProfileData = sizeof(PROFILEDATA) +
248 ((wcslen(szNameBuffer) + 1) * sizeof(WCHAR));
249 pProfileData = HeapAlloc(GetProcessHeap(),
250 0,
251 dwProfileData);
252 if (pProfileData == NULL)
253 goto done;
254
255 pProfileData->bMyProfile = EqualSid(pMySid, pSid);
256
257 ptr = (PWSTR)((ULONG_PTR)pProfileData + sizeof(PROFILEDATA));
258 pProfileData->pszFullName = ptr;
259
260 wcscpy(pProfileData->pszFullName, szNameBuffer);
261
262 memset(&lvi, 0x00, sizeof(lvi));
263 lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
264 lvi.pszText = pProfileData->pszFullName;
265 lvi.state = 0;
266 lvi.lParam = (LPARAM)pProfileData;
267 ListView_InsertItem(hwndListView, &lvi);
268
269 done:
270 if (pSid != NULL)
271 LocalFree(pSid);
272 }
273
274
275 static VOID
276 UpdateButtonState(
277 _In_ HWND hwndDlg,
278 _In_ HWND hwndListView)
279 {
280 LVITEM Item;
281 INT iSelected;
282 BOOL bMyProfile;
283
284 iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED);
285 if (iSelected != -1)
286 {
287 Item.mask = LVIF_PARAM;
288 Item.iItem = iSelected;
289 Item.iSubItem = 0;
290 if (ListView_GetItem(hwndListView, &Item))
291 {
292 if (Item.lParam != 0)
293 {
294 bMyProfile = ((PPROFILEDATA)Item.lParam)->bMyProfile;
295 if (/*IsUserAnAdmin() &&*/ !bMyProfile)
296 {
297 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_DELETE), TRUE);
298 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_COPY), TRUE);
299 }
300 }
301 }
302 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_CHANGE), TRUE);
303 }
304 else
305 {
306 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_CHANGE), FALSE);
307 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_DELETE), FALSE);
308 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_COPY), FALSE);
309 }
310 }
311
312
313 static VOID
314 AddUserProfiles(
315 _In_ HWND hwndDlg,
316 _In_ HWND hwndListView)
317 {
318 HKEY hKeyUserProfiles = INVALID_HANDLE_VALUE;
319 HKEY hProfileKey;
320 DWORD dwIndex;
321 WCHAR szProfileSid[64];
322 DWORD dwSidLength;
323 FILETIME ftLastWrite;
324 DWORD dwSize;
325 HANDLE hToken = NULL;
326 PTOKEN_USER pTokenUser = NULL;
327
328 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
329 return;
330
331 GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize);
332 if (dwSize == 0)
333 goto done;
334
335 pTokenUser = HeapAlloc(GetProcessHeap(), 0, dwSize);
336 if (pTokenUser == NULL)
337 goto done;
338
339 if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize))
340 goto done;
341
342 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
343 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
344 0,
345 KEY_READ,
346 &hKeyUserProfiles))
347 goto done;
348
349 for (dwIndex = 0; ; dwIndex++)
350 {
351 dwSidLength = ARRAYSIZE(szProfileSid);
352 if (RegEnumKeyExW(hKeyUserProfiles,
353 dwIndex,
354 szProfileSid,
355 &dwSidLength,
356 NULL,
357 NULL,
358 NULL,
359 &ftLastWrite))
360 break;
361
362 if (RegOpenKeyExW(hKeyUserProfiles,
363 szProfileSid,
364 0,
365 KEY_READ,
366 &hProfileKey) == ERROR_SUCCESS)
367 {
368 AddUserProfile(hwndListView, szProfileSid, pTokenUser->User.Sid, hProfileKey);
369 RegCloseKey(hProfileKey);
370 }
371 }
372
373 if (ListView_GetItemCount(hwndListView) != 0)
374 ListView_SetItemState(hwndListView, 0, LVIS_SELECTED, LVIS_SELECTED);
375
376 UpdateButtonState(hwndDlg, hwndListView);
377
378 done:
379 if (hKeyUserProfiles != INVALID_HANDLE_VALUE)
380 RegCloseKey(hKeyUserProfiles);
381
382 if (pTokenUser != NULL)
383 HeapFree(GetProcessHeap(), 0, pTokenUser);
384
385 if (hToken != NULL)
386 CloseHandle(hToken);
387 }
388
389
390 static VOID
391 OnInitUserProfileDialog(HWND hwndDlg)
392 {
393 /* Initialize the list view control */
394 SetListViewColumns(GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST));
395
396 AddUserProfiles(hwndDlg, GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST));
397 }
398
399
400 static
401 VOID
402 OnDestroy(
403 _In_ HWND hwndDlg)
404 {
405 HWND hwndList;
406 INT nItems, i;
407 LVITEM Item;
408
409 hwndList = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST);
410
411 nItems = ListView_GetItemCount(hwndList);
412 for (i = 0; i < nItems; i++)
413 {
414 Item.iItem = i;
415 Item.iSubItem = 0;
416 if (ListView_GetItem(hwndList, &Item))
417 {
418 if (Item.lParam != 0)
419 HeapFree(GetProcessHeap(), 0, (PVOID)Item.lParam);
420 }
421 }
422 }
423
424
425 static
426 VOID
427 OnNotify(
428 _In_ HWND hwndDlg,
429 _In_ NMHDR *nmhdr)
430 {
431 if (nmhdr->idFrom == IDC_USERACCOUNT_LINK && nmhdr->code == NM_CLICK)
432 {
433 ShellExecuteW(hwndDlg, NULL, L"usrmgr.cpl", NULL, NULL, 0);
434 }
435 else if (nmhdr->idFrom == IDC_USERPROFILE_LIST && nmhdr->code == LVN_ITEMCHANGED)
436 {
437 UpdateButtonState(hwndDlg, nmhdr->hwndFrom);
438 }
439 }
440
441
442 static
443 BOOL
444 DeleteUserProfile(
445 HWND hwndDlg)
446 {
447 WCHAR szTitle[64], szRawText[128], szCookedText[256];
448 HWND hwndListView;
449 LVITEM Item;
450 INT iSelected;
451 PPROFILEDATA pProfileData;
452
453 DPRINT("DeleteUserProfile()\n");
454
455 hwndListView = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST);
456 if (hwndListView == NULL)
457 return FALSE;
458
459 iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED);
460 if (iSelected == -1)
461 return FALSE;
462
463 ZeroMemory(&Item, sizeof(LVITEM));
464 Item.mask = LVIF_PARAM;
465 Item.iItem = iSelected;
466 Item.iSubItem = 0;
467 if (!ListView_GetItem(hwndListView, &Item))
468 return FALSE;
469
470 if (Item.lParam == 0)
471 return FALSE;
472
473 pProfileData = (PPROFILEDATA)Item.lParam;
474 if (pProfileData->bMyProfile)
475 return FALSE;
476
477 LoadStringW(hApplet, IDS_USERPROFILE_CONFIRM_DELETE_TITLE, szTitle, ARRAYSIZE(szTitle));
478 LoadStringW(hApplet, IDS_USERPROFILE_CONFIRM_DELETE, szRawText, ARRAYSIZE(szRawText));
479 swprintf(szCookedText, szRawText, pProfileData->pszFullName);
480
481 if (MessageBoxW(hwndDlg,
482 szCookedText,
483 szTitle,
484 MB_ICONQUESTION | MB_YESNO) == IDNO)
485 return FALSE;
486
487 /* FIXME: Delete the profile here! */
488
489 return TRUE;
490 }
491
492
493 /* Property page dialog callback */
494 INT_PTR CALLBACK
495 UserProfileDlgProc(HWND hwndDlg,
496 UINT uMsg,
497 WPARAM wParam,
498 LPARAM lParam)
499 {
500 switch (uMsg)
501 {
502 case WM_INITDIALOG:
503 OnInitUserProfileDialog(hwndDlg);
504 return TRUE;
505
506 case WM_DESTROY:
507 OnDestroy(hwndDlg);
508 break;
509
510 case WM_COMMAND:
511 switch (LOWORD(wParam))
512 {
513 case IDOK:
514 case IDCANCEL:
515 EndDialog(hwndDlg,
516 LOWORD(wParam));
517 return TRUE;
518
519 case IDC_USERPROFILE_CHANGE:
520 ChangeUserProfileType(hwndDlg);
521 break;
522
523 case IDC_USERPROFILE_DELETE:
524 DeleteUserProfile(hwndDlg);
525 break;
526
527 case IDC_USERPROFILE_COPY:
528 break;
529 }
530 break;
531
532 case WM_NOTIFY:
533 OnNotify(hwndDlg, (NMHDR *)lParam);
534 break;
535 }
536
537 return FALSE;
538 }