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 DWORD dwState; 20 PWSTR pszFullName; 21 } PROFILEDATA, *PPROFILEDATA; 22 23 24 static 25 BOOL 26 OnProfileTypeInit( 27 HWND hwndDlg, 28 PPROFILEDATA pProfileData) 29 { 30 PWSTR pszRawBuffer = NULL, pszCookedBuffer = NULL; 31 INT nLength; 32 33 nLength = LoadStringW(hApplet, IDS_USERPROFILE_TYPE_TEXT, (PWSTR)&pszRawBuffer, 0); 34 pszRawBuffer = NULL; 35 if (nLength == 0) 36 return FALSE; 37 38 pszRawBuffer = HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(WCHAR)); 39 if (pszRawBuffer == NULL) 40 return FALSE; 41 42 LoadStringW(hApplet, IDS_USERPROFILE_TYPE_TEXT, pszRawBuffer, nLength + 1); 43 44 pszCookedBuffer = HeapAlloc(GetProcessHeap(), 0, (nLength + wcslen(pProfileData->pszFullName) + 1) * sizeof(WCHAR)); 45 if (pszCookedBuffer == NULL) 46 goto done; 47 48 swprintf(pszCookedBuffer, pszRawBuffer, pProfileData->pszFullName); 49 50 /* Set the full text */ 51 SetDlgItemText(hwndDlg, IDC_USERPROFILE_TYPE_TEXT, pszCookedBuffer); 52 53 /* FIXME: Right now, we support local user profiles only! */ 54 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_TYPE_ROAMING), FALSE); 55 Button_SetCheck(GetDlgItem(hwndDlg, IDC_USERPROFILE_TYPE_LOCAL), BST_CHECKED); 56 EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); 57 58 done: 59 if (pszCookedBuffer != NULL) 60 HeapFree(GetProcessHeap(), 0, pszCookedBuffer); 61 62 if (pszRawBuffer != NULL) 63 HeapFree(GetProcessHeap(), 0, pszRawBuffer); 64 65 return TRUE; 66 } 67 68 69 static 70 INT_PTR 71 CALLBACK 72 UserProfileTypeDlgProc( 73 _In_ HWND hwndDlg, 74 _In_ UINT uMsg, 75 _In_ WPARAM wParam, 76 _In_ LPARAM lParam) 77 { 78 switch (uMsg) 79 { 80 case WM_INITDIALOG: 81 OnProfileTypeInit(hwndDlg, (PPROFILEDATA)lParam); 82 return TRUE; 83 84 case WM_DESTROY: 85 break; 86 87 case WM_COMMAND: 88 switch (LOWORD(wParam)) 89 { 90 case IDOK: 91 case IDCANCEL: 92 EndDialog(hwndDlg, 93 LOWORD(wParam)); 94 return TRUE; 95 } 96 break; 97 } 98 99 return FALSE; 100 } 101 102 103 static 104 BOOL 105 ChangeUserProfileType( 106 _In_ HWND hwndDlg) 107 { 108 HWND hwndListView; 109 LVITEM Item; 110 INT iSelected; 111 112 DPRINT("ChangeUserProfileType(%p)\n", hwndDlg); 113 114 hwndListView = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST); 115 if (hwndListView == NULL) 116 return FALSE; 117 118 iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED); 119 if (iSelected == -1) 120 return FALSE; 121 122 ZeroMemory(&Item, sizeof(LVITEM)); 123 Item.mask = LVIF_PARAM; 124 Item.iItem = iSelected; 125 Item.iSubItem = 0; 126 if (!ListView_GetItem(hwndListView, &Item)) 127 return FALSE; 128 129 if (Item.lParam == 0) 130 return FALSE; 131 132 if (DialogBoxParam(hApplet, 133 MAKEINTRESOURCE(IDD_USERPROFILE_TYPE), 134 hwndDlg, 135 UserProfileTypeDlgProc, 136 (LPARAM)Item.lParam) == IDOK) 137 { 138 /* FIXME: Update the profile list view */ 139 return TRUE; 140 } 141 142 return FALSE; 143 } 144 145 146 static 147 BOOL 148 DeleteUserProfile( 149 _In_ HWND hwndDlg) 150 { 151 WCHAR szTitle[64], szRawText[128], szCookedText[256]; 152 HWND hwndListView; 153 LVITEM Item; 154 INT iSelected; 155 PPROFILEDATA pProfileData; 156 157 DPRINT("DeleteUserProfile()\n"); 158 159 hwndListView = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST); 160 if (hwndListView == NULL) 161 return FALSE; 162 163 iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED); 164 if (iSelected == -1) 165 return FALSE; 166 167 ZeroMemory(&Item, sizeof(LVITEM)); 168 Item.mask = LVIF_PARAM; 169 Item.iItem = iSelected; 170 Item.iSubItem = 0; 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->bMyProfile) 179 return FALSE; 180 181 LoadStringW(hApplet, IDS_USERPROFILE_CONFIRM_DELETE_TITLE, szTitle, ARRAYSIZE(szTitle)); 182 LoadStringW(hApplet, IDS_USERPROFILE_CONFIRM_DELETE, szRawText, ARRAYSIZE(szRawText)); 183 swprintf(szCookedText, szRawText, pProfileData->pszFullName); 184 185 if (MessageBoxW(hwndDlg, 186 szCookedText, 187 szTitle, 188 MB_ICONQUESTION | MB_YESNO) == IDYES) 189 { 190 /* FIXME: Delete the profile here! */ 191 return TRUE; 192 } 193 194 return FALSE; 195 } 196 197 198 static 199 INT_PTR 200 CALLBACK 201 CopyUserProfileDlgProc( 202 _In_ HWND hwndDlg, 203 _In_ UINT uMsg, 204 _In_ WPARAM wParam, 205 _In_ LPARAM lParam) 206 { 207 switch (uMsg) 208 { 209 case WM_INITDIALOG: 210 return TRUE; 211 212 case WM_DESTROY: 213 break; 214 215 case WM_COMMAND: 216 switch (LOWORD(wParam)) 217 { 218 case IDOK: 219 case IDCANCEL: 220 EndDialog(hwndDlg, 221 LOWORD(wParam)); 222 return TRUE; 223 } 224 break; 225 } 226 227 return FALSE; 228 } 229 230 231 static 232 BOOL 233 CopyUserProfile( 234 _In_ HWND hwndDlg) 235 { 236 HWND hwndListView; 237 LVITEM Item; 238 INT iSelected; 239 240 DPRINT("CopyUserProfile()\n"); 241 242 hwndListView = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST); 243 if (hwndListView == NULL) 244 return FALSE; 245 246 iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED); 247 if (iSelected == -1) 248 return FALSE; 249 250 ZeroMemory(&Item, sizeof(LVITEM)); 251 Item.mask = LVIF_PARAM; 252 Item.iItem = iSelected; 253 Item.iSubItem = 0; 254 if (!ListView_GetItem(hwndListView, &Item)) 255 return FALSE; 256 257 if (Item.lParam == 0) 258 return FALSE; 259 260 if (DialogBoxParam(hApplet, 261 MAKEINTRESOURCE(IDD_USERPROFILE_COPY), 262 hwndDlg, 263 CopyUserProfileDlgProc, 264 (LPARAM)Item.lParam) == IDOK) 265 { 266 /* FIXME: Update the profile list view */ 267 return TRUE; 268 } 269 270 return FALSE; 271 } 272 273 274 static VOID 275 SetListViewColumns( 276 _In_ HWND hwndListView) 277 { 278 LV_COLUMN column; 279 RECT rect; 280 TCHAR szStr[32]; 281 282 GetClientRect(hwndListView, &rect); 283 284 SendMessage(hwndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT); 285 286 memset(&column, 0x00, sizeof(column)); 287 column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM | LVCF_TEXT; 288 column.fmt = LVCFMT_LEFT; 289 column.cx = (INT)((rect.right - rect.left) * 0.40); 290 column.iSubItem = 0; 291 LoadString(hApplet, IDS_USERPROFILE_NAME, szStr, ARRAYSIZE(szStr)); 292 column.pszText = szStr; 293 (void)ListView_InsertColumn(hwndListView, 0, &column); 294 295 column.fmt = LVCFMT_RIGHT; 296 column.cx = (INT)((rect.right - rect.left) * 0.15); 297 column.iSubItem = 1; 298 LoadString(hApplet, IDS_USERPROFILE_SIZE, szStr, ARRAYSIZE(szStr)); 299 column.pszText = szStr; 300 (void)ListView_InsertColumn(hwndListView, 1, &column); 301 302 column.fmt = LVCFMT_LEFT; 303 column.cx = (INT)((rect.right - rect.left) * 0.15); 304 column.iSubItem = 2; 305 LoadString(hApplet, IDS_USERPROFILE_TYPE, szStr, ARRAYSIZE(szStr)); 306 column.pszText = szStr; 307 (void)ListView_InsertColumn(hwndListView, 2, &column); 308 309 column.fmt = LVCFMT_LEFT; 310 column.cx = (INT)((rect.right - rect.left) * 0.15); 311 column.iSubItem = 3; 312 LoadString(hApplet, IDS_USERPROFILE_STATUS, szStr, ARRAYSIZE(szStr)); 313 column.pszText = szStr; 314 (void)ListView_InsertColumn(hwndListView, 3, &column); 315 316 column.fmt = LVCFMT_LEFT; 317 column.cx = (INT)((rect.right - rect.left) * 0.15) - GetSystemMetrics(SM_CYHSCROLL); 318 column.iSubItem = 4; 319 LoadString(hApplet, IDS_USERPROFILE_MODIFIED, szStr, ARRAYSIZE(szStr)); 320 column.pszText = szStr; 321 (void)ListView_InsertColumn(hwndListView, 4, &column); 322 } 323 324 325 static VOID 326 AddUserProfile( 327 _In_ HWND hwndListView, 328 _In_ LPTSTR lpProfileSid, 329 _In_ PSID pMySid, 330 _In_ HKEY hProfileKey) 331 { 332 PPROFILEDATA pProfileData = NULL; 333 WCHAR szAccountName[128], szDomainName[128]; 334 WCHAR szNameBuffer[256]; 335 SID_NAME_USE Use; 336 DWORD dwAccountNameSize, dwDomainNameSize; 337 DWORD dwProfileData, dwSize, dwType, dwState = 0; 338 PWSTR ptr; 339 PSID pSid = NULL; 340 INT nId, iItem; 341 LV_ITEM lvi; 342 343 if (!ConvertStringSidToSid(lpProfileSid, 344 &pSid)) 345 return; 346 347 dwAccountNameSize = ARRAYSIZE(szAccountName); 348 dwDomainNameSize = ARRAYSIZE(szDomainName); 349 if (!LookupAccountSidW(NULL, 350 pSid, 351 szAccountName, 352 &dwAccountNameSize, 353 szDomainName, 354 &dwDomainNameSize, 355 &Use)) 356 { 357 /* Unknown account */ 358 LoadStringW(hApplet, IDS_USERPROFILE_ACCOUNT_UNKNOWN, szNameBuffer, ARRAYSIZE(szNameBuffer)); 359 } 360 else 361 { 362 /* Show only the user accounts */ 363 if (Use != SidTypeUser) 364 goto done; 365 366 if (szAccountName[0] == UNICODE_NULL) 367 { 368 /* Deleted account */ 369 LoadStringW(hApplet, IDS_USERPROFILE_ACCOUNT_DELETED, szNameBuffer, ARRAYSIZE(szNameBuffer)); 370 } 371 else 372 { 373 /* Normal account */ 374 wsprintf(szNameBuffer, L"%s\\%s", szDomainName, szAccountName); 375 } 376 } 377 378 /* Get the profile state value */ 379 dwSize = sizeof(dwState); 380 if (RegQueryValueExW(hProfileKey, 381 L"State", 382 NULL, 383 &dwType, 384 (LPBYTE)&dwState, 385 &dwSize) != ERROR_SUCCESS) 386 { 387 dwState = 0; 388 } 389 390 /* Create and fill the profile data entry */ 391 dwProfileData = sizeof(PROFILEDATA) + 392 ((wcslen(szNameBuffer) + 1) * sizeof(WCHAR)); 393 pProfileData = HeapAlloc(GetProcessHeap(), 394 0, 395 dwProfileData); 396 if (pProfileData == NULL) 397 goto done; 398 399 pProfileData->bMyProfile = EqualSid(pMySid, pSid); 400 pProfileData->dwState = dwState; 401 402 ptr = (PWSTR)((ULONG_PTR)pProfileData + sizeof(PROFILEDATA)); 403 pProfileData->pszFullName = ptr; 404 405 wcscpy(pProfileData->pszFullName, szNameBuffer); 406 407 /* Add the profile and set its name */ 408 memset(&lvi, 0x00, sizeof(lvi)); 409 lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM; 410 lvi.pszText = pProfileData->pszFullName; 411 lvi.state = 0; 412 lvi.lParam = (LPARAM)pProfileData; 413 iItem = ListView_InsertItem(hwndListView, &lvi); 414 415 /* Set the profile type */ 416 if (dwState & 0x0001) // PROFILE_MANDATORY 417 nId = IDS_USERPROFILE_MANDATORY; 418 else if (dwState & 0x0010) // PROFILE_UPDATE_CENTRAL 419 nId = IDS_USERPROFILE_ROAMING; 420 else 421 nId = IDS_USERPROFILE_LOCAL; 422 423 LoadStringW(hApplet, nId, szAccountName, ARRAYSIZE(szAccountName)); 424 425 ListView_SetItemText(hwndListView, iItem, 2, szAccountName); 426 427 done: 428 if (pSid != NULL) 429 LocalFree(pSid); 430 } 431 432 433 static VOID 434 UpdateButtonState( 435 _In_ HWND hwndDlg, 436 _In_ HWND hwndListView) 437 { 438 LVITEM Item; 439 INT iSelected; 440 BOOL bMyProfile; 441 442 iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED); 443 if (iSelected != -1) 444 { 445 Item.mask = LVIF_PARAM; 446 Item.iItem = iSelected; 447 Item.iSubItem = 0; 448 if (ListView_GetItem(hwndListView, &Item)) 449 { 450 if (Item.lParam != 0) 451 { 452 bMyProfile = ((PPROFILEDATA)Item.lParam)->bMyProfile; 453 if (/*IsUserAnAdmin() &&*/ !bMyProfile) 454 { 455 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_DELETE), TRUE); 456 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_COPY), TRUE); 457 } 458 } 459 } 460 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_CHANGE), TRUE); 461 } 462 else 463 { 464 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_CHANGE), FALSE); 465 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_DELETE), FALSE); 466 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_COPY), FALSE); 467 } 468 } 469 470 471 static VOID 472 AddUserProfiles( 473 _In_ HWND hwndDlg, 474 _In_ HWND hwndListView) 475 { 476 HKEY hKeyUserProfiles = INVALID_HANDLE_VALUE; 477 HKEY hProfileKey; 478 DWORD dwIndex; 479 WCHAR szProfileSid[64]; 480 DWORD dwSidLength; 481 FILETIME ftLastWrite; 482 DWORD dwSize; 483 HANDLE hToken = NULL; 484 PTOKEN_USER pTokenUser = NULL; 485 486 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) 487 return; 488 489 GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize); 490 if (dwSize == 0) 491 goto done; 492 493 pTokenUser = HeapAlloc(GetProcessHeap(), 0, dwSize); 494 if (pTokenUser == NULL) 495 goto done; 496 497 if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize)) 498 goto done; 499 500 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, 501 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList", 502 0, 503 KEY_READ, 504 &hKeyUserProfiles)) 505 goto done; 506 507 for (dwIndex = 0; ; dwIndex++) 508 { 509 dwSidLength = ARRAYSIZE(szProfileSid); 510 if (RegEnumKeyExW(hKeyUserProfiles, 511 dwIndex, 512 szProfileSid, 513 &dwSidLength, 514 NULL, 515 NULL, 516 NULL, 517 &ftLastWrite)) 518 break; 519 520 if (RegOpenKeyExW(hKeyUserProfiles, 521 szProfileSid, 522 0, 523 KEY_READ, 524 &hProfileKey) == ERROR_SUCCESS) 525 { 526 AddUserProfile(hwndListView, szProfileSid, pTokenUser->User.Sid, hProfileKey); 527 RegCloseKey(hProfileKey); 528 } 529 } 530 531 if (ListView_GetItemCount(hwndListView) != 0) 532 ListView_SetItemState(hwndListView, 0, LVIS_SELECTED, LVIS_SELECTED); 533 534 UpdateButtonState(hwndDlg, hwndListView); 535 536 done: 537 if (hKeyUserProfiles != INVALID_HANDLE_VALUE) 538 RegCloseKey(hKeyUserProfiles); 539 540 if (pTokenUser != NULL) 541 HeapFree(GetProcessHeap(), 0, pTokenUser); 542 543 if (hToken != NULL) 544 CloseHandle(hToken); 545 } 546 547 548 static VOID 549 OnInitUserProfileDialog(HWND hwndDlg) 550 { 551 /* Initialize the list view control */ 552 SetListViewColumns(GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST)); 553 554 AddUserProfiles(hwndDlg, GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST)); 555 } 556 557 558 static 559 VOID 560 OnDestroy( 561 _In_ HWND hwndDlg) 562 { 563 HWND hwndList; 564 INT nItems, i; 565 LVITEM Item; 566 567 hwndList = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST); 568 569 nItems = ListView_GetItemCount(hwndList); 570 for (i = 0; i < nItems; i++) 571 { 572 Item.iItem = i; 573 Item.iSubItem = 0; 574 if (ListView_GetItem(hwndList, &Item)) 575 { 576 if (Item.lParam != 0) 577 HeapFree(GetProcessHeap(), 0, (PVOID)Item.lParam); 578 } 579 } 580 } 581 582 583 static 584 VOID 585 OnNotify( 586 _In_ HWND hwndDlg, 587 _In_ NMHDR *nmhdr) 588 { 589 if (nmhdr->idFrom == IDC_USERACCOUNT_LINK && nmhdr->code == NM_CLICK) 590 { 591 ShellExecuteW(hwndDlg, NULL, L"usrmgr.cpl", NULL, NULL, 0); 592 } 593 else if (nmhdr->idFrom == IDC_USERPROFILE_LIST && nmhdr->code == LVN_ITEMCHANGED) 594 { 595 UpdateButtonState(hwndDlg, nmhdr->hwndFrom); 596 } 597 } 598 599 600 /* Property page dialog callback */ 601 INT_PTR CALLBACK 602 UserProfileDlgProc(HWND hwndDlg, 603 UINT uMsg, 604 WPARAM wParam, 605 LPARAM lParam) 606 { 607 switch (uMsg) 608 { 609 case WM_INITDIALOG: 610 OnInitUserProfileDialog(hwndDlg); 611 return TRUE; 612 613 case WM_DESTROY: 614 OnDestroy(hwndDlg); 615 break; 616 617 case WM_COMMAND: 618 switch (LOWORD(wParam)) 619 { 620 case IDOK: 621 case IDCANCEL: 622 EndDialog(hwndDlg, 623 LOWORD(wParam)); 624 return TRUE; 625 626 case IDC_USERPROFILE_CHANGE: 627 ChangeUserProfileType(hwndDlg); 628 break; 629 630 case IDC_USERPROFILE_DELETE: 631 DeleteUserProfile(hwndDlg); 632 break; 633 634 case IDC_USERPROFILE_COPY: 635 CopyUserProfile(hwndDlg); 636 break; 637 } 638 break; 639 640 case WM_NOTIFY: 641 OnNotify(hwndDlg, (NMHDR *)lParam); 642 break; 643 } 644 645 return FALSE; 646 } 647