1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS User Manager Control Panel 4 * FILE: dll/cpl/usrmgr/groupprops.c 5 * PURPOSE: Group property sheet 6 * 7 * PROGRAMMERS: Eric Kohl 8 */ 9 10 #include "usrmgr.h" 11 12 typedef struct _GENERAL_GROUP_DATA 13 { 14 TCHAR szGroupName[1]; 15 } GENERAL_GROUP_DATA, *PGENERAL_GROUP_DATA; 16 17 18 static VOID 19 GetTextSid(PSID pSid, 20 LPTSTR pTextSid) 21 { 22 PSID_IDENTIFIER_AUTHORITY psia; 23 DWORD dwSubAuthorities; 24 DWORD dwSidRev = SID_REVISION; 25 DWORD dwCounter; 26 DWORD dwSidSize; 27 28 psia = GetSidIdentifierAuthority(pSid); 29 30 dwSubAuthorities = *GetSidSubAuthorityCount(pSid); 31 32 dwSidSize = wsprintf(pTextSid, TEXT("S-%lu-"), dwSidRev); 33 34 if ((psia->Value[0] != 0) || (psia->Value[1] != 0)) 35 { 36 dwSidSize += wsprintf(pTextSid + lstrlen(pTextSid), 37 TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"), 38 (USHORT)psia->Value[0], 39 (USHORT)psia->Value[1], 40 (USHORT)psia->Value[2], 41 (USHORT)psia->Value[3], 42 (USHORT)psia->Value[4], 43 (USHORT)psia->Value[5]); 44 } 45 else 46 { 47 dwSidSize += wsprintf(pTextSid + lstrlen(pTextSid), 48 TEXT("%lu"), 49 (ULONG)(psia->Value[5]) + 50 (ULONG)(psia->Value[4] << 8) + 51 (ULONG)(psia->Value[3] << 16) + 52 (ULONG)(psia->Value[2] << 24)); 53 } 54 55 for (dwCounter = 0 ; dwCounter < dwSubAuthorities ; dwCounter++) 56 { 57 dwSidSize += wsprintf(pTextSid + dwSidSize, TEXT("-%lu"), 58 *GetSidSubAuthority(pSid, dwCounter)); 59 } 60 } 61 62 63 static VOID 64 InitGroupMembersList(HWND hwndDlg, 65 PGENERAL_GROUP_DATA pGroupData) 66 { 67 HWND hwndLV; 68 LV_COLUMN column; 69 RECT rect; 70 TCHAR szStr[32]; 71 HIMAGELIST hImgList; 72 HICON hIcon; 73 74 NET_API_STATUS netStatus; 75 PUSER_INFO_20 pUserBuffer; 76 DWORD entriesread; 77 DWORD totalentries; 78 DWORD resume_handle = 0; 79 DWORD i; 80 LV_ITEM lvi; 81 INT iItem; 82 83 hwndLV = GetDlgItem(hwndDlg, IDC_USER_ADD_MEMBERSHIP_LIST); 84 GetClientRect(hwndLV, &rect); 85 86 hImgList = ImageList_Create(16,16,ILC_COLOR32 | ILC_MASK,5,5); 87 hIcon = LoadImage(hApplet,MAKEINTRESOURCE(IDI_GROUP),IMAGE_ICON,16,16,LR_DEFAULTCOLOR); 88 ImageList_AddIcon(hImgList,hIcon); 89 DestroyIcon(hIcon); 90 hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_USER), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); 91 ImageList_AddIcon(hImgList, hIcon); 92 DestroyIcon(hIcon); 93 hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_LOCKED_USER), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); 94 ImageList_AddIcon(hImgList, hIcon); 95 DestroyIcon(hIcon); 96 97 (void)ListView_SetImageList(hwndLV, hImgList, LVSIL_SMALL); 98 (void)ListView_SetExtendedListViewStyle(hwndLV, LVS_EX_FULLROWSELECT); 99 100 memset(&column, 0x00, sizeof(column)); 101 column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM | LVCF_TEXT; 102 column.fmt = LVCFMT_LEFT; 103 column.cx = (INT)((rect.right - rect.left) * 0.40); 104 column.iSubItem = 0; 105 LoadString(hApplet, IDS_NAME, szStr, sizeof(szStr) / sizeof(szStr[0])); 106 column.pszText = szStr; 107 (void)ListView_InsertColumn(hwndLV, 0, &column); 108 109 column.cx = (INT)((rect.right - rect.left) * 0.60); 110 column.iSubItem = 1; 111 LoadString(hApplet, IDS_DESCRIPTION, szStr, sizeof(szStr) / sizeof(szStr[0])); 112 column.pszText = szStr; 113 (void)ListView_InsertColumn(hwndLV, 1, &column); 114 115 /* TODO: Enumerate global groups and add them to the list! */ 116 117 for (;;) 118 { 119 netStatus = NetUserEnum(NULL, 20, FILTER_NORMAL_ACCOUNT, 120 (LPBYTE*)&pUserBuffer, 121 1024, &entriesread, 122 &totalentries, &resume_handle); 123 if (netStatus != NERR_Success && netStatus != ERROR_MORE_DATA) 124 break; 125 126 for (i = 0; i < entriesread; i++) 127 { 128 memset(&lvi, 0x00, sizeof(lvi)); 129 lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE; 130 lvi.pszText = pUserBuffer[i].usri20_name; 131 lvi.state = 0; 132 lvi.iImage = (pUserBuffer[i].usri20_flags & UF_ACCOUNTDISABLE) ? 2 : 1; 133 iItem = ListView_InsertItem(hwndLV, &lvi); 134 135 ListView_SetItemText(hwndLV, iItem, 1, 136 pUserBuffer[i].usri20_full_name); 137 138 ListView_SetItemText(hwndLV, iItem, 2, 139 pUserBuffer[i].usri20_comment); 140 } 141 142 NetApiBufferFree(pUserBuffer); 143 144 /* No more data left */ 145 if (netStatus != ERROR_MORE_DATA) 146 break; 147 } 148 } 149 150 151 static BOOL 152 AddSelectedUsersToGroup(HWND hwndDlg, 153 PGENERAL_GROUP_DATA pGroupData) 154 { 155 HWND hwndLV; 156 INT nSelectedItems; 157 INT nItem; 158 TCHAR szUserName[UNLEN + 1]; 159 BOOL bResult = FALSE; 160 LOCALGROUP_MEMBERS_INFO_3 memberInfo; 161 NET_API_STATUS status; 162 163 hwndLV = GetDlgItem(hwndDlg, IDC_USER_ADD_MEMBERSHIP_LIST); 164 165 nSelectedItems = ListView_GetSelectedCount(hwndLV); 166 if (nSelectedItems > 0) 167 { 168 nItem = ListView_GetNextItem(hwndLV, -1, LVNI_SELECTED); 169 while (nItem != -1) 170 { 171 /* Get the new user name */ 172 ListView_GetItemText(hwndLV, 173 nItem, 0, 174 szUserName, 175 UNLEN + 1); 176 TRACE("Selected user: %s", dbgstrx(szUserName)); 177 178 memberInfo.lgrmi3_domainandname = szUserName; 179 180 status = NetLocalGroupAddMembers(NULL, pGroupData->szGroupName, 3, 181 (LPBYTE)&memberInfo, 1); 182 if (status != NERR_Success && status != ERROR_MEMBER_IN_ALIAS) 183 { 184 TCHAR szText[256]; 185 wsprintf(szText, TEXT("Error: %u"), status); 186 MessageBox(NULL, szText, TEXT("NetLocalGroupAddMembers"), MB_ICONERROR | MB_OK); 187 } 188 else 189 { 190 bResult = TRUE; 191 } 192 193 nItem = ListView_GetNextItem(hwndLV, nItem, LVNI_SELECTED); 194 } 195 } 196 197 return bResult; 198 } 199 200 201 INT_PTR CALLBACK 202 AddUsersToGroupDlgProc(HWND hwndDlg, 203 UINT uMsg, 204 WPARAM wParam, 205 LPARAM lParam) 206 { 207 PGENERAL_GROUP_DATA pGroupData; 208 209 UNREFERENCED_PARAMETER(wParam); 210 211 pGroupData = (PGENERAL_GROUP_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER); 212 213 switch (uMsg) 214 { 215 case WM_INITDIALOG: 216 pGroupData = (PGENERAL_GROUP_DATA)lParam; 217 SetWindowLongPtr(hwndDlg, DWLP_USER, (INT_PTR)pGroupData); 218 InitGroupMembersList(hwndDlg, pGroupData); 219 break; 220 221 case WM_COMMAND: 222 switch (LOWORD(wParam)) 223 { 224 case IDOK: 225 if (AddSelectedUsersToGroup(hwndDlg, pGroupData)) 226 EndDialog(hwndDlg, IDOK); 227 else 228 EndDialog(hwndDlg, IDCANCEL); 229 break; 230 231 case IDCANCEL: 232 EndDialog(hwndDlg, IDCANCEL); 233 break; 234 } 235 break; 236 237 default: 238 return FALSE; 239 } 240 241 return TRUE; 242 } 243 244 245 static VOID 246 AddUsersToGroup(HWND hwndDlg, 247 PGENERAL_GROUP_DATA pGroupData) 248 { 249 HWND hwndLV; 250 // NET_API_STATUS status; 251 PLOCALGROUP_MEMBERS_INFO_1 membersInfo = NULL; 252 DWORD dwRead; 253 DWORD dwTotal; 254 DWORD_PTR resumeHandle = 0; 255 DWORD i; 256 LV_ITEM lvi; 257 TCHAR szGroupName[256]; 258 259 if (DialogBoxParam(hApplet, 260 MAKEINTRESOURCE(IDD_USER_ADD_MEMBERSHIP), 261 hwndDlg, 262 AddUsersToGroupDlgProc, 263 (LPARAM)pGroupData) == IDOK) 264 { 265 hwndLV = GetDlgItem(hwndDlg, IDC_GROUP_GENERAL_MEMBERS); 266 267 (void)ListView_DeleteAllItems(hwndLV); 268 269 // DebugPrintf(_T("Removed all users from the list!")); 270 271 /* Set group members */ 272 NetLocalGroupGetMembers(NULL, pGroupData->szGroupName, 1, (LPBYTE*)&membersInfo, 273 MAX_PREFERRED_LENGTH, &dwRead, &dwTotal, 274 &resumeHandle); 275 276 for (i = 0; i < dwRead; i++) 277 { 278 ZeroMemory(&lvi, sizeof(lvi)); 279 lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE; 280 lvi.pszText = membersInfo[i].lgrmi1_name; 281 lvi.state = 0; 282 lvi.iImage = (membersInfo[i].lgrmi1_sidusage == SidTypeGroup || 283 membersInfo[i].lgrmi1_sidusage == SidTypeWellKnownGroup) ? 1 : 0; 284 285 if (membersInfo[i].lgrmi1_sidusage == SidTypeWellKnownGroup) 286 { 287 TCHAR szSid[256]; 288 289 GetTextSid(membersInfo[i].lgrmi1_sid, szSid); 290 291 wsprintf(szGroupName, 292 TEXT("%s (%s)"), 293 membersInfo[i].lgrmi1_name, 294 szSid); 295 296 lvi.pszText = szGroupName; 297 } 298 299 300 (void)ListView_InsertItem(hwndLV, &lvi); 301 } 302 303 NetApiBufferFree(membersInfo); 304 } 305 } 306 307 308 static VOID 309 RemoveUserFromGroup(HWND hwndDlg, 310 PGENERAL_GROUP_DATA pGroupData) 311 { 312 TCHAR szUserName[UNLEN + 1]; 313 TCHAR szText[256]; 314 LOCALGROUP_MEMBERS_INFO_3 memberInfo; 315 HWND hwndLV; 316 INT nItem; 317 NET_API_STATUS status; 318 319 hwndLV = GetDlgItem(hwndDlg, IDC_GROUP_GENERAL_MEMBERS); 320 nItem = ListView_GetNextItem(hwndLV, -1, LVNI_SELECTED); 321 if (nItem == -1) 322 return; 323 324 /* Get the new user name */ 325 ListView_GetItemText(hwndLV, 326 nItem, 0, 327 szUserName, 328 UNLEN + 1); 329 330 /* Display a warning message because the remove operation cannot be reverted */ 331 wsprintf(szText, TEXT("Do you really want to remove the user \"%s\" from the group \"%s\"?"), 332 szUserName, pGroupData->szGroupName); 333 if (MessageBox(NULL, szText, TEXT("User Accounts"), MB_ICONWARNING | MB_YESNO) == IDNO) 334 return; 335 336 memberInfo.lgrmi3_domainandname = szUserName; 337 338 status = NetLocalGroupDelMembers(NULL, pGroupData->szGroupName, 339 3, (LPBYTE)&memberInfo, 1); 340 if (status != NERR_Success) 341 { 342 TCHAR szText[256]; 343 wsprintf(szText, TEXT("Error: %u"), status); 344 MessageBox(NULL, szText, TEXT("NetLocalGroupDelMembers"), MB_ICONERROR | MB_OK); 345 return; 346 } 347 348 (void)ListView_DeleteItem(hwndLV, nItem); 349 350 if (ListView_GetItemCount(hwndLV) == 0) 351 EnableWindow(GetDlgItem(hwndDlg, IDC_GROUP_GENERAL_REMOVE), FALSE); 352 } 353 354 355 static BOOL 356 OnGroupPropSheetNotify(HWND hwndDlg, 357 PGENERAL_GROUP_DATA pGroupData, 358 LPARAM lParam) 359 { 360 LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lParam; 361 362 switch (((LPNMHDR)lParam)->idFrom) 363 { 364 case IDC_GROUP_GENERAL_MEMBERS: 365 switch (((LPNMHDR)lParam)->code) 366 { 367 case NM_CLICK: 368 EnableWindow(GetDlgItem(hwndDlg, IDC_GROUP_GENERAL_REMOVE), (lpnmlv->iItem != -1)); 369 break; 370 371 case LVN_KEYDOWN: 372 if (((LPNMLVKEYDOWN)lParam)->wVKey == VK_DELETE) 373 { 374 RemoveUserFromGroup(hwndDlg, pGroupData); 375 } 376 break; 377 378 } 379 break; 380 } 381 382 return FALSE; 383 } 384 385 386 static VOID 387 GetGeneralGroupData(HWND hwndDlg, 388 PGENERAL_GROUP_DATA pGroupData) 389 { 390 PLOCALGROUP_INFO_1 groupInfo = NULL; 391 PLOCALGROUP_MEMBERS_INFO_2 membersInfo = NULL; 392 DWORD dwRead; 393 DWORD dwTotal; 394 DWORD_PTR resumeHandle = 0; 395 DWORD i; 396 LV_ITEM lvi; 397 HWND hwndLV; 398 LV_COLUMN column; 399 RECT rect; 400 HIMAGELIST hImgList; 401 HICON hIcon; 402 TCHAR szGroupName[256]; 403 404 405 hwndLV = GetDlgItem(hwndDlg, IDC_GROUP_GENERAL_MEMBERS); 406 407 /* Create the image list */ 408 hImgList = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 5, 5); 409 hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_GROUP), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); 410 ImageList_AddIcon(hImgList, hIcon); 411 DestroyIcon(hIcon); 412 hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_USER), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); 413 ImageList_AddIcon(hImgList, hIcon); 414 DestroyIcon(hIcon); 415 416 (void)ListView_SetImageList(hwndLV, hImgList, LVSIL_SMALL); 417 418 /* Set the list column */ 419 GetClientRect(hwndLV, &rect); 420 421 memset(&column, 0x00, sizeof(column)); 422 column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM; 423 column.fmt = LVCFMT_LEFT; 424 column.cx = (INT)(rect.right - rect.left); 425 column.iSubItem = 0; 426 (void)ListView_InsertColumn(hwndLV, 0, &column); 427 428 /* Set group name */ 429 SetDlgItemText(hwndDlg, IDC_GROUP_GENERAL_NAME, pGroupData->szGroupName); 430 431 /* Set group description */ 432 NetLocalGroupGetInfo(NULL, pGroupData->szGroupName, 1, (LPBYTE*)&groupInfo); 433 SetDlgItemText(hwndDlg, IDC_GROUP_GENERAL_DESCRIPTION, groupInfo->lgrpi1_comment); 434 NetApiBufferFree(groupInfo); 435 436 /* Set group members */ 437 NetLocalGroupGetMembers(NULL, pGroupData->szGroupName, 2, (LPBYTE*)&membersInfo, 438 MAX_PREFERRED_LENGTH, &dwRead, &dwTotal, 439 &resumeHandle); 440 441 for (i = 0; i < dwRead; i++) 442 { 443 ZeroMemory(&lvi, sizeof(lvi)); 444 lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE; 445 lvi.state = 0; 446 if (membersInfo[i].lgrmi2_sidusage == SidTypeGroup || 447 membersInfo[i].lgrmi2_sidusage == SidTypeWellKnownGroup) 448 { 449 lvi.iImage = 0; 450 } 451 else if (membersInfo[i].lgrmi2_sidusage == SidTypeUser) 452 { 453 /* FIXME: handle locked user properly! */ 454 lvi.iImage = 1; 455 } 456 457 if (membersInfo[i].lgrmi2_sidusage == SidTypeWellKnownGroup) 458 { 459 TCHAR szSid[256]; 460 461 GetTextSid(membersInfo[i].lgrmi2_sid, szSid); 462 463 wsprintf(szGroupName, 464 TEXT("%s (%s)"), 465 membersInfo[i].lgrmi2_domainandname, 466 szSid); 467 468 lvi.pszText = szGroupName; 469 } 470 else 471 { 472 LPWSTR ptr; 473 474 ptr = wcschr(membersInfo[i].lgrmi2_domainandname, L'\\'); 475 if (ptr != NULL) 476 { 477 lvi.pszText = ++ptr; 478 } 479 else 480 { 481 lvi.pszText = membersInfo[i].lgrmi2_domainandname; 482 } 483 } 484 485 (void)ListView_InsertItem(hwndLV, &lvi); 486 } 487 488 NetApiBufferFree(membersInfo); 489 } 490 491 492 static BOOL 493 SetGeneralGroupData(HWND hwndDlg, 494 PGENERAL_GROUP_DATA pGroupData) 495 { 496 LOCALGROUP_INFO_1 groupInfo; 497 NET_API_STATUS status; 498 DWORD dwIndex; 499 500 /* Get the group description */ 501 groupInfo.lgrpi1_comment = GetDlgItemTextAlloc(hwndDlg, IDC_GROUP_GENERAL_DESCRIPTION); 502 503 status = NetLocalGroupSetInfo(NULL, pGroupData->szGroupName, 1, (LPBYTE)&groupInfo, &dwIndex); 504 if (status != NERR_Success) 505 { 506 ERR("NetLocalGroupSetInfo failed. Status: %lu Index: %lu", status, dwIndex); 507 } 508 509 HeapFree(GetProcessHeap(), 0, groupInfo.lgrpi1_comment); 510 511 return TRUE; 512 } 513 514 515 INT_PTR CALLBACK 516 GroupGeneralPageProc(HWND hwndDlg, 517 UINT uMsg, 518 WPARAM wParam, 519 LPARAM lParam) 520 { 521 PGENERAL_GROUP_DATA pGroupData; 522 523 UNREFERENCED_PARAMETER(lParam); 524 UNREFERENCED_PARAMETER(wParam); 525 UNREFERENCED_PARAMETER(hwndDlg); 526 527 pGroupData= (PGENERAL_GROUP_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER); 528 529 switch (uMsg) 530 { 531 case WM_INITDIALOG: 532 pGroupData = (PGENERAL_GROUP_DATA)HeapAlloc(GetProcessHeap(), 533 HEAP_ZERO_MEMORY, 534 sizeof(GENERAL_GROUP_DATA) + 535 lstrlen((LPTSTR)((PROPSHEETPAGE *)lParam)->lParam) * sizeof(TCHAR)); 536 lstrcpy(pGroupData->szGroupName, (LPTSTR)((PROPSHEETPAGE *)lParam)->lParam); 537 538 SetWindowLongPtr(hwndDlg, DWLP_USER, (INT_PTR)pGroupData); 539 540 GetGeneralGroupData(hwndDlg, 541 pGroupData); 542 break; 543 544 case WM_COMMAND: 545 switch (LOWORD(wParam)) 546 { 547 case IDC_GROUP_GENERAL_DESCRIPTION: 548 if (HIWORD(wParam) == EN_CHANGE) 549 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 550 break; 551 552 case IDC_GROUP_GENERAL_ADD: 553 AddUsersToGroup(hwndDlg, pGroupData); 554 break; 555 556 case IDC_GROUP_GENERAL_REMOVE: 557 RemoveUserFromGroup(hwndDlg, pGroupData); 558 break; 559 } 560 break; 561 562 case WM_NOTIFY: 563 if (((LPPSHNOTIFY)lParam)->hdr.code == PSN_APPLY) 564 { 565 SetGeneralGroupData(hwndDlg, pGroupData); 566 return TRUE; 567 } 568 else 569 { 570 return OnGroupPropSheetNotify(hwndDlg, pGroupData, lParam); 571 } 572 break; 573 574 case WM_DESTROY: 575 HeapFree(GetProcessHeap(), 0, pGroupData); 576 break; 577 } 578 579 return FALSE; 580 } 581 582 583 static VOID 584 InitGroupPropSheetPage(PROPSHEETPAGE *psp, WORD idDlg, DLGPROC DlgProc, LPTSTR pszGroup) 585 { 586 ZeroMemory(psp, sizeof(PROPSHEETPAGE)); 587 psp->dwSize = sizeof(PROPSHEETPAGE); 588 psp->dwFlags = PSP_DEFAULT; 589 psp->hInstance = hApplet; 590 psp->pszTemplate = MAKEINTRESOURCE(idDlg); 591 psp->pfnDlgProc = DlgProc; 592 psp->lParam = (LPARAM)pszGroup; 593 } 594 595 596 BOOL 597 GroupProperties(HWND hwndDlg) 598 { 599 PROPSHEETPAGE psp[1]; 600 PROPSHEETHEADER psh; 601 TCHAR szGroupName[UNLEN + 1]; 602 INT nItem; 603 HWND hwndLV; 604 605 hwndLV = GetDlgItem(hwndDlg, IDC_GROUPS_LIST); 606 nItem = ListView_GetNextItem(hwndLV, -1, LVNI_SELECTED); 607 if (nItem == -1) 608 return FALSE; 609 610 /* Get the new user name */ 611 ListView_GetItemText(hwndLV, 612 nItem, 0, 613 szGroupName, 614 UNLEN + 1); 615 616 ZeroMemory(&psh, sizeof(PROPSHEETHEADER)); 617 psh.dwSize = sizeof(PROPSHEETHEADER); 618 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_PROPTITLE; 619 psh.hwndParent = hwndDlg; 620 psh.hInstance = hApplet; 621 psh.hIcon = NULL; 622 psh.pszCaption = szGroupName; 623 psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE); 624 psh.nStartPage = 0; 625 psh.ppsp = psp; 626 627 InitGroupPropSheetPage(&psp[0], IDD_GROUP_GENERAL, GroupGeneralPageProc, szGroupName); 628 629 return (PropertySheet(&psh) == IDOK); 630 } 631