xref: /reactos/dll/cpl/sysdm/userprofile.c (revision a8e06d92)
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 #include <winnls.h>
14 
15 #include <debug.h>
16 
17 typedef struct _PROFILEDATA
18 {
19     DWORD dwRefCount;
20     DWORD dwState;
21     BOOL bUnknownProfile;
22     PWSTR pszFullName;
23     PWSTR pszProfilePath;
24 } PROFILEDATA, *PPROFILEDATA;
25 
26 
27 static
28 BOOL
OnProfileTypeInit(_In_ HWND hwndDlg,_In_ PPROFILEDATA pProfileData)29 OnProfileTypeInit(
30     _In_ HWND hwndDlg,
31     _In_ PPROFILEDATA pProfileData)
32 {
33     PWSTR pszRawBuffer = NULL, pszCookedBuffer = NULL;
34     INT nLength;
35 
36     nLength = LoadStringW(hApplet, IDS_USERPROFILE_TYPE_TEXT, (PWSTR)&pszRawBuffer, 0);
37     pszRawBuffer = NULL;
38     if (nLength == 0)
39         return FALSE;
40 
41     pszRawBuffer = HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(WCHAR));
42     if (pszRawBuffer == NULL)
43         return FALSE;
44 
45     LoadStringW(hApplet, IDS_USERPROFILE_TYPE_TEXT, pszRawBuffer, nLength + 1);
46 
47     pszCookedBuffer = HeapAlloc(GetProcessHeap(), 0, (nLength + wcslen(pProfileData->pszFullName) + 1) * sizeof(WCHAR));
48     if (pszCookedBuffer == NULL)
49         goto done;
50 
51     swprintf(pszCookedBuffer, pszRawBuffer, pProfileData->pszFullName);
52 
53     /* Set the full text */
54     SetDlgItemText(hwndDlg, IDC_USERPROFILE_TYPE_TEXT, pszCookedBuffer);
55 
56     /* FIXME: Right now, we support local user profiles only! */
57     EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_TYPE_ROAMING), FALSE);
58     Button_SetCheck(GetDlgItem(hwndDlg, IDC_USERPROFILE_TYPE_LOCAL), BST_CHECKED);
59     EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
60 
61 done:
62     if (pszCookedBuffer != NULL)
63         HeapFree(GetProcessHeap(), 0, pszCookedBuffer);
64 
65     if (pszRawBuffer != NULL)
66         HeapFree(GetProcessHeap(), 0, pszRawBuffer);
67 
68     return TRUE;
69 }
70 
71 
72 static
73 INT_PTR
74 CALLBACK
UserProfileTypeDlgProc(_In_ HWND hwndDlg,_In_ UINT uMsg,_In_ WPARAM wParam,_In_ LPARAM lParam)75 UserProfileTypeDlgProc(
76     _In_ HWND hwndDlg,
77     _In_ UINT uMsg,
78     _In_ WPARAM wParam,
79     _In_ LPARAM lParam)
80 {
81     switch (uMsg)
82     {
83         case WM_INITDIALOG:
84             OnProfileTypeInit(hwndDlg, (PPROFILEDATA)lParam);
85             return TRUE;
86 
87         case WM_DESTROY:
88             break;
89 
90         case WM_COMMAND:
91             switch (LOWORD(wParam))
92             {
93                 case IDOK:
94                 case IDCANCEL:
95                     EndDialog(hwndDlg,
96                               LOWORD(wParam));
97                     return TRUE;
98             }
99             break;
100     }
101 
102     return FALSE;
103 }
104 
105 
106 static
107 BOOL
ChangeUserProfileType(_In_ HWND hwndDlg)108 ChangeUserProfileType(
109     _In_ HWND hwndDlg)
110 {
111     HWND hwndListView;
112     LVITEM Item;
113     INT iSelected;
114 
115     DPRINT("ChangeUserProfileType(%p)\n", hwndDlg);
116 
117     hwndListView = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST);
118     if (hwndListView == NULL)
119         return FALSE;
120 
121     iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED);
122     if (iSelected == -1)
123         return FALSE;
124 
125     ZeroMemory(&Item, sizeof(LVITEM));
126     Item.mask = LVIF_PARAM;
127     Item.iItem = iSelected;
128     if (!ListView_GetItem(hwndListView, &Item))
129         return FALSE;
130 
131     if (Item.lParam == 0)
132         return FALSE;
133 
134     if (DialogBoxParam(hApplet,
135                        MAKEINTRESOURCE(IDD_USERPROFILE_TYPE),
136                        hwndDlg,
137                        UserProfileTypeDlgProc,
138                        (LPARAM)Item.lParam) == IDOK)
139     {
140         /* FIXME: Update the profile list view */
141         return TRUE;
142     }
143 
144     return FALSE;
145 }
146 
147 
148 static
149 BOOL
DeleteUserProfile(_In_ HWND hwndDlg)150 DeleteUserProfile(
151     _In_ HWND hwndDlg)
152 {
153     HWND hwndListView;
154     LVITEM Item;
155     INT iSelected;
156     PPROFILEDATA pProfileData;
157 
158     DPRINT("DeleteUserProfile()\n");
159 
160     hwndListView = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST);
161     if (hwndListView == NULL)
162         return FALSE;
163 
164     iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED);
165     if (iSelected == -1)
166         return FALSE;
167 
168     ZeroMemory(&Item, sizeof(LVITEM));
169     Item.mask = LVIF_PARAM;
170     Item.iItem = iSelected;
171     if (!ListView_GetItem(hwndListView, &Item))
172         return FALSE;
173 
174     if (Item.lParam == 0)
175         return FALSE;
176 
177     pProfileData = (PPROFILEDATA)Item.lParam;
178     if (pProfileData->dwRefCount != 0)
179         return FALSE;
180 
181     if (ResourceMessageBox(hApplet,
182                            hwndDlg,
183                            MB_ICONQUESTION | MB_YESNO,
184                            IDS_USERPROFILE_CONFIRM_DELETE_TITLE,
185                            IDS_USERPROFILE_CONFIRM_DELETE,
186                            pProfileData->pszFullName) == IDYES)
187     {
188         /* FIXME: Delete the profile here! */
189         return TRUE;
190     }
191 
192     return FALSE;
193 }
194 
195 
196 static
197 INT_PTR
198 CALLBACK
CopyUserProfileDlgProc(_In_ HWND hwndDlg,_In_ UINT uMsg,_In_ WPARAM wParam,_In_ LPARAM lParam)199 CopyUserProfileDlgProc(
200     _In_ HWND hwndDlg,
201     _In_ UINT uMsg,
202     _In_ WPARAM wParam,
203     _In_ LPARAM lParam)
204 {
205     switch (uMsg)
206     {
207         case WM_INITDIALOG:
208             return TRUE;
209 
210         case WM_DESTROY:
211             break;
212 
213         case WM_COMMAND:
214             switch (LOWORD(wParam))
215             {
216                 case IDOK:
217                 case IDCANCEL:
218                     EndDialog(hwndDlg,
219                               LOWORD(wParam));
220                     return TRUE;
221             }
222             break;
223     }
224 
225     return FALSE;
226 }
227 
228 
229 static
230 BOOL
CopyUserProfile(_In_ HWND hwndDlg)231 CopyUserProfile(
232     _In_ HWND hwndDlg)
233 {
234     HWND hwndListView;
235     LVITEM Item;
236     INT iSelected;
237 
238     DPRINT("CopyUserProfile()\n");
239 
240     hwndListView = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST);
241     if (hwndListView == NULL)
242         return FALSE;
243 
244     iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED);
245     if (iSelected == -1)
246         return FALSE;
247 
248     ZeroMemory(&Item, sizeof(LVITEM));
249     Item.mask = LVIF_PARAM;
250     Item.iItem = iSelected;
251     if (!ListView_GetItem(hwndListView, &Item))
252         return FALSE;
253 
254     if (Item.lParam == 0)
255         return FALSE;
256 
257     if (DialogBoxParam(hApplet,
258                        MAKEINTRESOURCE(IDD_USERPROFILE_COPY),
259                        hwndDlg,
260                        CopyUserProfileDlgProc,
261                        (LPARAM)Item.lParam) == IDOK)
262     {
263         /* FIXME: Update the profile list view */
264         return TRUE;
265     }
266 
267     return FALSE;
268 }
269 
270 
271 static VOID
SetListViewColumns(_In_ HWND hwndListView)272 SetListViewColumns(
273     _In_ HWND hwndListView)
274 {
275     LV_COLUMN column;
276     RECT rect;
277     TCHAR szStr[32];
278 
279     GetClientRect(hwndListView, &rect);
280 
281     SendMessage(hwndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
282 
283     memset(&column, 0x00, sizeof(column));
284     column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM | LVCF_TEXT;
285     column.fmt = LVCFMT_LEFT;
286     column.cx = (INT)((rect.right - rect.left) * 0.40);
287     column.iSubItem = 0;
288     LoadString(hApplet, IDS_USERPROFILE_NAME, szStr, ARRAYSIZE(szStr));
289     column.pszText = szStr;
290     (void)ListView_InsertColumn(hwndListView, 0, &column);
291 
292     column.fmt = LVCFMT_RIGHT;
293     column.cx = (INT)((rect.right - rect.left) * 0.15);
294     column.iSubItem = 1;
295     LoadString(hApplet, IDS_USERPROFILE_SIZE, szStr, ARRAYSIZE(szStr));
296     column.pszText = szStr;
297     (void)ListView_InsertColumn(hwndListView, 1, &column);
298 
299     column.fmt = LVCFMT_LEFT;
300     column.cx = (INT)((rect.right - rect.left) * 0.15);
301     column.iSubItem = 2;
302     LoadString(hApplet, IDS_USERPROFILE_TYPE, szStr, ARRAYSIZE(szStr));
303     column.pszText = szStr;
304     (void)ListView_InsertColumn(hwndListView, 2, &column);
305 
306     column.fmt = LVCFMT_LEFT;
307     column.cx = (INT)((rect.right - rect.left) * 0.15);
308     column.iSubItem = 3;
309     LoadString(hApplet, IDS_USERPROFILE_STATUS, szStr, ARRAYSIZE(szStr));
310     column.pszText = szStr;
311     (void)ListView_InsertColumn(hwndListView, 3, &column);
312 
313     column.fmt = LVCFMT_LEFT;
314     column.cx = (INT)((rect.right - rect.left) * 0.15) - GetSystemMetrics(SM_CYHSCROLL);
315     column.iSubItem = 4;
316     LoadString(hApplet, IDS_USERPROFILE_MODIFIED, szStr, ARRAYSIZE(szStr));
317     column.pszText = szStr;
318     (void)ListView_InsertColumn(hwndListView, 4, &column);
319 }
320 
321 
322 static
323 BOOL
GetProfileSize(_In_ PWSTR pszProfilePath,_Inout_ PULONGLONG pullProfileSize)324 GetProfileSize(
325     _In_ PWSTR pszProfilePath,
326     _Inout_ PULONGLONG pullProfileSize)
327 {
328     HANDLE hFile = INVALID_HANDLE_VALUE;
329     WIN32_FIND_DATA FindData;
330     DWORD dwProfilePathLength;
331     ULARGE_INTEGER Size;
332     BOOL bResult = TRUE;
333 
334     dwProfilePathLength = wcslen(pszProfilePath);
335 
336     wcscat(pszProfilePath, L"\\*.*");
337 
338     hFile = FindFirstFileW(pszProfilePath, &FindData);
339     if (hFile == INVALID_HANDLE_VALUE)
340     {
341         if ((GetLastError() != ERROR_FILE_NOT_FOUND) &&
342             (GetLastError() != ERROR_PATH_NOT_FOUND))
343             bResult = FALSE;
344 
345         goto done;
346     }
347 
348     do
349     {
350         if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
351         {
352             if ((_wcsicmp(FindData.cFileName, L".") == 0) ||
353                 (_wcsicmp(FindData.cFileName, L"..") == 0))
354                 continue;
355 
356             pszProfilePath[dwProfilePathLength + 1] = UNICODE_NULL;
357             wcscat(pszProfilePath, FindData.cFileName);
358 
359             if (!GetProfileSize(pszProfilePath, pullProfileSize))
360             {
361                 bResult = FALSE;
362                 goto done;
363             }
364         }
365         else
366         {
367             Size.u.LowPart = FindData.nFileSizeLow;
368             Size.u.HighPart = FindData.nFileSizeHigh;
369             *pullProfileSize += Size.QuadPart;
370         }
371     }
372     while (FindNextFile(hFile, &FindData));
373 
374 done:
375     pszProfilePath[dwProfilePathLength] = UNICODE_NULL;
376 
377     if (hFile != INVALID_HANDLE_VALUE)
378         FindClose(hFile);
379 
380     return bResult;
381 }
382 
383 
384 static
385 BOOL
GetProfileName(_In_ PSID pProfileSid,_In_ DWORD dwNameBufferSize,_Out_ PWSTR pszNameBuffer,_Out_ PBOOL pbUnknownProfile)386 GetProfileName(
387     _In_ PSID pProfileSid,
388     _In_ DWORD dwNameBufferSize,
389     _Out_ PWSTR pszNameBuffer,
390     _Out_ PBOOL pbUnknownProfile)
391 {
392     WCHAR szAccountName[128], szDomainName[128];
393     DWORD dwAccountNameSize, dwDomainNameSize;
394     SID_NAME_USE Use;
395 
396     dwAccountNameSize = ARRAYSIZE(szAccountName);
397     dwDomainNameSize = ARRAYSIZE(szDomainName);
398     if (!LookupAccountSidW(NULL,
399                            pProfileSid,
400                            szAccountName,
401                            &dwAccountNameSize,
402                            szDomainName,
403                            &dwDomainNameSize,
404                            &Use))
405     {
406         /* Unknown account */
407         LoadStringW(hApplet, IDS_USERPROFILE_ACCOUNT_UNKNOWN, pszNameBuffer, dwNameBufferSize);
408         *pbUnknownProfile = TRUE;
409     }
410     else
411     {
412         /* Show only the user accounts */
413         if (Use != SidTypeUser)
414             return FALSE;
415 
416         if (szAccountName[0] == UNICODE_NULL)
417         {
418             /* Deleted account */
419             LoadStringW(hApplet, IDS_USERPROFILE_ACCOUNT_DELETED, pszNameBuffer, dwNameBufferSize);
420         }
421         else
422         {
423             /* Normal account */
424             wsprintf(pszNameBuffer, L"%s\\%s", szDomainName, szAccountName);
425         }
426         *pbUnknownProfile = FALSE;
427     }
428 
429     return TRUE;
430 }
431 
432 
433 static VOID
AddUserProfile(_In_ HWND hwndListView,_In_ PSID pProfileSid,_In_ HKEY hProfileKey)434 AddUserProfile(
435     _In_ HWND hwndListView,
436     _In_ PSID pProfileSid,
437     _In_ HKEY hProfileKey)
438 {
439     WCHAR szTempProfilePath[MAX_PATH], szProfilePath[MAX_PATH];
440     WCHAR szNameBuffer[256];
441     PPROFILEDATA pProfileData = NULL;
442     DWORD dwProfileData, dwSize, dwType, dwState = 0, dwRefCount = 0;
443     DWORD dwProfilePathLength;
444     PWSTR ptr;
445     INT nId, iItem;
446     LV_ITEM lvi;
447     WIN32_FIND_DATA FindData;
448     HANDLE hFile;
449     SYSTEMTIME SystemTime;
450     ULONGLONG ullProfileSize;
451     BOOL bUnknownProfile;
452     DWORD dwError;
453 
454     /* Get the profile path */
455     dwSize = MAX_PATH * sizeof(WCHAR);
456     dwError = RegQueryValueExW(hProfileKey,
457                                L"ProfileImagePath",
458                                NULL,
459                                &dwType,
460                                (LPBYTE)szTempProfilePath,
461                                &dwSize);
462     if (dwError != ERROR_SUCCESS)
463         return;
464 
465     /* Expand it */
466     ExpandEnvironmentStringsW(szTempProfilePath,
467                               szProfilePath,
468                               MAX_PATH);
469 
470     /* Check if the profile path exists */
471     hFile = FindFirstFileW(szProfilePath, &FindData);
472     if (hFile == INVALID_HANDLE_VALUE)
473         return;
474 
475     FindClose(hFile);
476 
477     /* Get the length of the profile path */
478     dwProfilePathLength = wcslen(szProfilePath);
479 
480     /* Check for the ntuser.dat file */
481     wcscat(szProfilePath, L"\\ntuser.dat");
482     hFile = FindFirstFileW(szProfilePath, &FindData);
483     if (hFile == INVALID_HANDLE_VALUE)
484         return;
485 
486     FindClose(hFile);
487     szProfilePath[dwProfilePathLength] = UNICODE_NULL;
488 
489     /* Get the profile size */
490     ullProfileSize = 0ULL;
491     GetProfileSize(szProfilePath, &ullProfileSize);
492 
493     /* Get the profile name */
494     if (!GetProfileName(pProfileSid,
495                         ARRAYSIZE(szNameBuffer),
496                         szNameBuffer,
497                         &bUnknownProfile))
498         return;
499 
500     /* Get the profile state value */
501     dwSize = sizeof(dwState);
502     if (RegQueryValueExW(hProfileKey,
503                          L"State",
504                          NULL,
505                          &dwType,
506                          (LPBYTE)&dwState,
507                          &dwSize) != ERROR_SUCCESS)
508     {
509         dwState = 0;
510     }
511 
512     /* Get the profile reference counter */
513     dwSize = sizeof(dwRefCount);
514     if (RegQueryValueExW(hProfileKey,
515                          L"RefCount",
516                          NULL,
517                          &dwType,
518                          (LPBYTE)&dwRefCount,
519                          &dwSize) != ERROR_SUCCESS)
520     {
521         dwRefCount = 0;
522     }
523 
524     /* Create and fill the profile data entry */
525     dwProfileData = sizeof(PROFILEDATA) +
526                     ((wcslen(szNameBuffer) + 1) * sizeof(WCHAR)) +
527                     ((wcslen(szProfilePath) + 1) * sizeof(WCHAR));
528     pProfileData = HeapAlloc(GetProcessHeap(),
529                              HEAP_ZERO_MEMORY,
530                              dwProfileData);
531     if (pProfileData == NULL)
532         return;
533 
534     pProfileData->dwRefCount = dwRefCount;
535     pProfileData->dwState = dwState;
536     pProfileData->bUnknownProfile = bUnknownProfile;
537 
538     ptr = (PWSTR)((ULONG_PTR)pProfileData + sizeof(PROFILEDATA));
539     pProfileData->pszFullName = ptr;
540 
541     wcscpy(pProfileData->pszFullName, szNameBuffer);
542 
543     ptr = (PWSTR)((ULONG_PTR)ptr + ((wcslen(pProfileData->pszFullName) + 1) * sizeof(WCHAR)));
544     pProfileData->pszProfilePath = ptr;
545     wcscpy(pProfileData->pszProfilePath, szProfilePath);
546 
547     /* Add the profile and set its name */
548     memset(&lvi, 0x00, sizeof(lvi));
549     lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
550     lvi.pszText = pProfileData->pszFullName;
551     lvi.state = 0;
552     lvi.lParam = (LPARAM)pProfileData;
553     iItem = ListView_InsertItem(hwndListView, &lvi);
554 
555     /* Set the profile size */
556     StrFormatByteSizeW(ullProfileSize, szNameBuffer, ARRAYSIZE(szNameBuffer) - 1);
557     ListView_SetItemText(hwndListView, iItem, 1, szNameBuffer);
558 
559     /* Set the profile type */
560     if (dwState & 0x0010) // PROFILE_UPDATE_CENTRAL
561         nId = IDS_USERPROFILE_ROAMING;
562     else
563         nId = IDS_USERPROFILE_LOCAL;
564 
565     LoadStringW(hApplet, nId, szNameBuffer, ARRAYSIZE(szNameBuffer));
566 
567     ListView_SetItemText(hwndListView, iItem, 2, szNameBuffer);
568 
569     /* FIXME: Set the profile status */
570     if (dwState & 0x0001) // PROFILE_MANDATORY
571         nId = IDS_USERPROFILE_MANDATORY;
572     else if (dwState & 0x0010) // PROFILE_UPDATE_CENTRAL
573         nId = IDS_USERPROFILE_ROAMING;
574     else
575         nId = IDS_USERPROFILE_LOCAL;
576 
577     LoadStringW(hApplet, nId, szNameBuffer, ARRAYSIZE(szNameBuffer));
578 
579     ListView_SetItemText(hwndListView, iItem, 3, szNameBuffer);
580 
581     /* Set the profile modified time */
582     FileTimeToSystemTime(&FindData.ftLastWriteTime,
583                          &SystemTime);
584 
585     GetDateFormatW(LOCALE_USER_DEFAULT,
586                    DATE_SHORTDATE,
587                    &SystemTime,
588                    NULL,
589                    szNameBuffer,
590                    ARRAYSIZE(szNameBuffer));
591 
592     ListView_SetItemText(hwndListView, iItem, 4, szNameBuffer);
593 }
594 
595 
596 static VOID
UpdateButtonState(_In_ HWND hwndDlg,_In_ HWND hwndListView)597 UpdateButtonState(
598     _In_ HWND hwndDlg,
599     _In_ HWND hwndListView)
600 {
601     LVITEM Item;
602     INT iSelected;
603     BOOL bChange = FALSE;
604     BOOL bCopy = FALSE;
605     BOOL bDelete = FALSE;
606     PPROFILEDATA pProfileData;
607 
608     if (ListView_GetSelectedCount(hwndListView) != 0)
609     {
610         iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED);
611         if (iSelected != -1)
612         {
613             ZeroMemory(&Item, sizeof(LVITEM));
614             Item.mask = LVIF_PARAM;
615             Item.iItem = iSelected;
616             if (ListView_GetItem(hwndListView, &Item))
617             {
618                 if (Item.lParam != 0)
619                 {
620                     pProfileData = (PPROFILEDATA)Item.lParam;
621 
622                     if (pProfileData->bUnknownProfile)
623                     {
624                         bDelete = TRUE;
625                         bCopy = FALSE;
626                     }
627                     else
628                     {
629                         bDelete = (pProfileData->dwRefCount == 0);
630                         bCopy = (pProfileData->dwRefCount == 0);
631                     }
632                 }
633             }
634 
635             bChange = TRUE;
636         }
637     }
638 
639     EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_CHANGE), bChange);
640     EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_DELETE), bDelete);
641     EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_COPY), bCopy);
642 }
643 
644 
645 static VOID
AddUserProfiles(_In_ HWND hwndDlg,_In_ HWND hwndListView,_In_ BOOL bAdmin)646 AddUserProfiles(
647     _In_ HWND hwndDlg,
648     _In_ HWND hwndListView,
649     _In_ BOOL bAdmin)
650 {
651     HKEY hKeyUserProfiles = INVALID_HANDLE_VALUE;
652     HKEY hProfileKey;
653     DWORD dwIndex;
654     WCHAR szProfileSid[64];
655     DWORD dwSidLength;
656     FILETIME ftLastWrite;
657     DWORD dwSize;
658     HANDLE hToken = NULL;
659     PTOKEN_USER pTokenUser = NULL;
660     PSID pProfileSid;
661     PWSTR pszProfileSid;
662 
663     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
664         return;
665 
666     if (GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize) ||
667         GetLastError() != ERROR_INSUFFICIENT_BUFFER)
668     {
669         goto done;
670     }
671 
672     pTokenUser = HeapAlloc(GetProcessHeap(), 0, dwSize);
673     if (pTokenUser == NULL)
674         goto done;
675 
676     if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize))
677         goto done;
678 
679     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
680                       L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
681                       0,
682                       KEY_READ,
683                       &hKeyUserProfiles))
684         goto done;
685 
686     if (bAdmin)
687     {
688         for (dwIndex = 0; ; dwIndex++)
689         {
690             dwSidLength = ARRAYSIZE(szProfileSid);
691             if (RegEnumKeyExW(hKeyUserProfiles,
692                               dwIndex,
693                               szProfileSid,
694                               &dwSidLength,
695                               NULL,
696                               NULL,
697                               NULL,
698                               &ftLastWrite))
699                 break;
700 
701             if (RegOpenKeyExW(hKeyUserProfiles,
702                               szProfileSid,
703                               0,
704                               KEY_READ,
705                               &hProfileKey) == ERROR_SUCCESS)
706             {
707                 if (ConvertStringSidToSid(szProfileSid, &pProfileSid))
708                 {
709                     AddUserProfile(hwndListView,
710                                    pProfileSid,
711                                    hProfileKey);
712                     LocalFree(pProfileSid);
713                 }
714 
715                 RegCloseKey(hProfileKey);
716             }
717         }
718     }
719     else
720     {
721         if (ConvertSidToStringSidW(pTokenUser->User.Sid, &pszProfileSid))
722         {
723             if (RegOpenKeyExW(hKeyUserProfiles,
724                               pszProfileSid,
725                               0,
726                               KEY_READ,
727                               &hProfileKey) == ERROR_SUCCESS)
728             {
729                 AddUserProfile(hwndListView,
730                                pTokenUser->User.Sid,
731                                hProfileKey);
732                 RegCloseKey(hProfileKey);
733             }
734 
735             LocalFree(pszProfileSid);
736         }
737     }
738 
739     if (ListView_GetItemCount(hwndListView) != 0)
740         ListView_SetItemState(hwndListView, 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
741 
742     UpdateButtonState(hwndDlg, hwndListView);
743 
744 done:
745     if (hKeyUserProfiles != INVALID_HANDLE_VALUE)
746         RegCloseKey(hKeyUserProfiles);
747 
748     if (pTokenUser != NULL)
749         HeapFree(GetProcessHeap(), 0, pTokenUser);
750 
751     if (hToken != NULL)
752         CloseHandle(hToken);
753 }
754 
755 
756 static VOID
OnInitUserProfileDialog(HWND hwndDlg)757 OnInitUserProfileDialog(HWND hwndDlg)
758 {
759     BOOL bAdmin;
760 
761     bAdmin = IsUserAdmin();
762 
763     /* Initialize the list view control */
764     SetListViewColumns(GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST));
765 
766     /* Hide the delete and copy buttons for non-admins */
767     ShowWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_DELETE), bAdmin ? SW_SHOW : SW_HIDE);
768     ShowWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_COPY), bAdmin ? SW_SHOW : SW_HIDE);
769 
770     /* Add the profiles to the list view */
771     AddUserProfiles(hwndDlg, GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST), bAdmin);
772 }
773 
774 static
775 VOID
OnNotify(_In_ HWND hwndDlg,_In_ NMHDR * nmhdr)776 OnNotify(
777     _In_ HWND hwndDlg,
778     _In_ NMHDR *nmhdr)
779 {
780     LPNMLISTVIEW pNMLV;
781 
782     if (nmhdr->idFrom == IDC_USERACCOUNT_LINK && nmhdr->code == NM_CLICK)
783     {
784         ShellExecuteW(hwndDlg, NULL, L"usrmgr.cpl", NULL, NULL, 0);
785     }
786     else if (nmhdr->idFrom == IDC_USERPROFILE_LIST)
787     {
788         switch(nmhdr->code)
789         {
790             case LVN_ITEMCHANGED:
791                 UpdateButtonState(hwndDlg, nmhdr->hwndFrom);
792                 break;
793 
794             case NM_DBLCLK:
795                 ChangeUserProfileType(hwndDlg);
796                 break;
797 
798             case LVN_DELETEITEM:
799                 pNMLV = (LPNMLISTVIEW)nmhdr;
800                 if (pNMLV->lParam != 0)
801                     HeapFree(GetProcessHeap(), 0, (LPVOID)pNMLV->lParam);
802                 break;
803         }
804     }
805 }
806 
807 
808 /* Property page dialog callback */
809 INT_PTR CALLBACK
UserProfileDlgProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)810 UserProfileDlgProc(HWND hwndDlg,
811                    UINT uMsg,
812                    WPARAM wParam,
813                    LPARAM lParam)
814 {
815     switch (uMsg)
816     {
817         case WM_INITDIALOG:
818             OnInitUserProfileDialog(hwndDlg);
819             return TRUE;
820 
821         case WM_COMMAND:
822             switch (LOWORD(wParam))
823             {
824                 case IDOK:
825                 case IDCANCEL:
826                     EndDialog(hwndDlg,
827                               LOWORD(wParam));
828                     return TRUE;
829 
830                 case IDC_USERPROFILE_CHANGE:
831                     ChangeUserProfileType(hwndDlg);
832                     break;
833 
834                 case IDC_USERPROFILE_DELETE:
835                     DeleteUserProfile(hwndDlg);
836                     break;
837 
838                 case IDC_USERPROFILE_COPY:
839                     CopyUserProfile(hwndDlg);
840                     break;
841             }
842             break;
843 
844         case WM_NOTIFY:
845             OnNotify(hwndDlg, (NMHDR *)lParam);
846             break;
847     }
848 
849     return FALSE;
850 }
851