Implement removal of a user from a user group.
[reactos.git] / reactos / dll / cpl / usrmgr / groupprops.c
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 RemoveUserFromGroup(HWND hwndDlg,
65 PGENERAL_GROUP_DATA pGroupData)
66 {
67 TCHAR szUserName[UNLEN];
68 TCHAR szText[256];
69 LOCALGROUP_MEMBERS_INFO_3 memberInfo;
70 HWND hwndLV;
71 INT nItem;
72 NET_API_STATUS status;
73
74 hwndLV = GetDlgItem(hwndDlg, IDC_GROUP_GENERAL_MEMBERS);
75 nItem = ListView_GetNextItem(hwndLV, -1, LVNI_SELECTED);
76 if (nItem == -1)
77 return;
78
79 /* Get the new user name */
80 ListView_GetItemText(hwndLV,
81 nItem, 0,
82 szUserName,
83 UNLEN);
84
85 /* Display a warning message because the remove operation cannot be reverted */
86 wsprintf(szText, TEXT("Do you really want to remove the user \"%s\" from the group \"%s\"?"),
87 szUserName, pGroupData->szGroupName);
88 if (MessageBox(NULL, szText, TEXT("User Accounts"), MB_ICONWARNING | MB_YESNO) == IDNO)
89 return;
90
91 memberInfo.lgrmi3_domainandname = szUserName;
92
93 status = NetLocalGroupDelMembers(NULL, pGroupData->szGroupName,
94 3, (LPBYTE)&memberInfo, 1);
95 if (status != NERR_Success)
96 {
97 TCHAR szText[256];
98 wsprintf(szText, TEXT("Error: %u"), status);
99 MessageBox(NULL, szText, TEXT("NetLocalGroupDelMembers"), MB_ICONERROR | MB_OK);
100 return;
101 }
102
103 (void)ListView_DeleteItem(hwndLV, nItem);
104
105 if (ListView_GetItemCount(hwndLV) == 0)
106 EnableWindow(GetDlgItem(hwndDlg, IDC_GROUP_GENERAL_REMOVE), FALSE);
107 }
108
109
110 static BOOL
111 OnNotify(HWND hwndDlg,
112 PGENERAL_GROUP_DATA pGroupData,
113 LPARAM lParam)
114 {
115 LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lParam;
116
117 switch (((LPNMHDR)lParam)->idFrom)
118 {
119 case IDC_GROUP_GENERAL_MEMBERS:
120 switch (((LPNMHDR)lParam)->code)
121 {
122 case NM_CLICK:
123 EnableWindow(GetDlgItem(hwndDlg, IDC_GROUP_GENERAL_REMOVE), (lpnmlv->iItem != -1));
124 break;
125
126 case LVN_KEYDOWN:
127 if (((LPNMLVKEYDOWN)lParam)->wVKey == VK_DELETE)
128 {
129 RemoveUserFromGroup(hwndDlg, pGroupData);
130 }
131 break;
132
133 }
134 break;
135 }
136
137 return FALSE;
138 }
139
140
141 static VOID
142 GetGeneralGroupData(HWND hwndDlg,
143 PGENERAL_GROUP_DATA pGroupData)
144 {
145 PLOCALGROUP_INFO_1 groupInfo = NULL;
146 PLOCALGROUP_MEMBERS_INFO_1 membersInfo = NULL;
147 DWORD dwRead;
148 DWORD dwTotal;
149 DWORD_PTR resumeHandle = 0;
150 DWORD i;
151 LV_ITEM lvi;
152 HWND hwndLV;
153 LV_COLUMN column;
154 RECT rect;
155 HIMAGELIST hImgList;
156 HICON hIcon;
157 TCHAR szGroupName[256];
158
159
160 hwndLV = GetDlgItem(hwndDlg, IDC_GROUP_GENERAL_MEMBERS);
161
162 /* Create the image list */
163 hImgList = ImageList_Create(16, 16, ILC_COLOR8 | ILC_MASK, 5, 5);
164 hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_USER), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
165 ImageList_AddIcon(hImgList, hIcon);
166 hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_GROUP), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
167 ImageList_AddIcon(hImgList, hIcon);
168 DestroyIcon(hIcon);
169
170 (void)ListView_SetImageList(hwndLV, hImgList, LVSIL_SMALL);
171
172 /* Set the list column */
173 GetClientRect(hwndLV, &rect);
174
175 memset(&column, 0x00, sizeof(column));
176 column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM;
177 column.fmt = LVCFMT_LEFT;
178 column.cx = (INT)(rect.right - rect.left);
179 column.iSubItem = 0;
180 (void)ListView_InsertColumn(hwndLV, 0, &column);
181
182 /* Set group name */
183 SetDlgItemText(hwndDlg, IDC_GROUP_GENERAL_NAME, pGroupData->szGroupName);
184
185 /* Set group description */
186 NetLocalGroupGetInfo(NULL, pGroupData->szGroupName, 1, (LPBYTE*)&groupInfo);
187 SetDlgItemText(hwndDlg, IDC_GROUP_GENERAL_DESCRIPTION, groupInfo->lgrpi1_comment);
188 NetApiBufferFree(groupInfo);
189
190 /* Set group members */
191 NetLocalGroupGetMembers(NULL, pGroupData->szGroupName, 1, (LPBYTE*)&membersInfo,
192 MAX_PREFERRED_LENGTH, &dwRead, &dwTotal,
193 &resumeHandle);
194
195 for (i = 0; i < dwRead; i++)
196 {
197 ZeroMemory(&lvi, sizeof(lvi));
198 lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE;
199 lvi.pszText = membersInfo[i].lgrmi1_name;
200 lvi.state = 0;
201 lvi.iImage = (membersInfo[i].lgrmi1_sidusage == SidTypeGroup ||
202 membersInfo[i].lgrmi1_sidusage == SidTypeWellKnownGroup) ? 1 : 0;
203
204 if (membersInfo[i].lgrmi1_sidusage == SidTypeWellKnownGroup)
205 {
206 TCHAR szSid[256];
207
208 GetTextSid(membersInfo[i].lgrmi1_sid, szSid);
209
210 wsprintf(szGroupName,
211 TEXT("%s\\%s (%s)"),
212 membersInfo[i].lgrmi1_name,
213 szSid);
214
215 lvi.pszText = szGroupName;
216 }
217
218 (void)ListView_InsertItem(hwndLV, &lvi);
219 }
220
221 NetApiBufferFree(membersInfo);
222 }
223
224
225 static BOOL
226 SetGeneralGroupData(HWND hwndDlg,
227 PGENERAL_GROUP_DATA pGroupData)
228 {
229 LOCALGROUP_INFO_1 groupInfo;
230 LPTSTR pszComment = NULL;
231 INT nLength;
232 NET_API_STATUS status;
233 DWORD dwIndex;
234
235 /* Get the group description */
236 nLength = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_GROUP_GENERAL_DESCRIPTION));
237 if (nLength == 0)
238 {
239 groupInfo.lgrpi1_comment = NULL;
240 }
241 else
242 {
243 pszComment = HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(TCHAR));
244 GetDlgItemText(hwndDlg, IDC_GROUP_GENERAL_DESCRIPTION, pszComment, nLength + 1);
245 groupInfo.lgrpi1_comment = pszComment;
246 }
247
248 status = NetLocalGroupSetInfo(NULL, pGroupData->szGroupName, 1, (LPBYTE)&groupInfo, &dwIndex);
249 if (status != NERR_Success)
250 {
251 DebugPrintf(_T("Status: %lu Index: %lu"), status, dwIndex);
252 }
253
254 if (pszComment)
255 HeapFree(GetProcessHeap(), 0, pszComment);
256
257 return TRUE;
258 }
259
260
261 INT_PTR CALLBACK
262 GroupGeneralPageProc(HWND hwndDlg,
263 UINT uMsg,
264 WPARAM wParam,
265 LPARAM lParam)
266 {
267 PGENERAL_GROUP_DATA pGroupData;
268
269 UNREFERENCED_PARAMETER(lParam);
270 UNREFERENCED_PARAMETER(wParam);
271 UNREFERENCED_PARAMETER(hwndDlg);
272
273 pGroupData= (PGENERAL_GROUP_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
274
275 switch (uMsg)
276 {
277 case WM_INITDIALOG:
278 pGroupData = (PGENERAL_GROUP_DATA)HeapAlloc(GetProcessHeap(),
279 HEAP_ZERO_MEMORY,
280 sizeof(GENERAL_GROUP_DATA) +
281 lstrlen((LPTSTR)((PROPSHEETPAGE *)lParam)->lParam) * sizeof(TCHAR));
282 lstrcpy(pGroupData->szGroupName, (LPTSTR)((PROPSHEETPAGE *)lParam)->lParam);
283
284 SetWindowLongPtr(hwndDlg, DWLP_USER, (INT_PTR)pGroupData);
285
286 GetGeneralGroupData(hwndDlg,
287 pGroupData);
288 break;
289
290 case WM_COMMAND:
291 switch (LOWORD(wParam))
292 {
293 case IDC_GROUP_GENERAL_DESCRIPTION:
294 if (HIWORD(wParam) == EN_CHANGE)
295 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
296 break;
297
298 case IDC_GROUP_GENERAL_REMOVE:
299 RemoveUserFromGroup(hwndDlg, pGroupData);
300 break;
301 }
302 break;
303
304 case WM_NOTIFY:
305 if (((LPPSHNOTIFY)lParam)->hdr.code == PSN_APPLY)
306 {
307 SetGeneralGroupData(hwndDlg, pGroupData);
308 return TRUE;
309 }
310 else
311 {
312 return OnNotify(hwndDlg, pGroupData, lParam);
313 }
314 break;
315
316 case WM_DESTROY:
317 HeapFree(GetProcessHeap(), 0, pGroupData);
318 break;
319 }
320
321 return FALSE;
322 }
323
324
325 static VOID
326 InitPropSheetPage(PROPSHEETPAGE *psp, WORD idDlg, DLGPROC DlgProc, LPTSTR pszGroup)
327 {
328 ZeroMemory(psp, sizeof(PROPSHEETPAGE));
329 psp->dwSize = sizeof(PROPSHEETPAGE);
330 psp->dwFlags = PSP_DEFAULT;
331 psp->hInstance = hApplet;
332 psp->pszTemplate = MAKEINTRESOURCE(idDlg);
333 psp->pfnDlgProc = DlgProc;
334 psp->lParam = (LPARAM)pszGroup;
335 }
336
337
338 BOOL
339 GroupProperties(HWND hwndDlg)
340 {
341 PROPSHEETPAGE psp[1];
342 PROPSHEETHEADER psh;
343 TCHAR szGroupName[UNLEN];
344 INT nItem;
345 HWND hwndLV;
346
347 hwndLV = GetDlgItem(hwndDlg, IDC_GROUPS_LIST);
348 nItem = ListView_GetNextItem(hwndLV, -1, LVNI_SELECTED);
349 if (nItem == -1)
350 return FALSE;
351
352 /* Get the new user name */
353 ListView_GetItemText(hwndLV,
354 nItem, 0,
355 szGroupName,
356 UNLEN);
357
358 ZeroMemory(&psh, sizeof(PROPSHEETHEADER));
359 psh.dwSize = sizeof(PROPSHEETHEADER);
360 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_PROPTITLE;
361 psh.hwndParent = hwndDlg;
362 psh.hInstance = hApplet;
363 psh.hIcon = NULL;
364 psh.pszCaption = szGroupName;
365 psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
366 psh.nStartPage = 0;
367 psh.ppsp = psp;
368
369 InitPropSheetPage(&psp[0], IDD_GROUP_GENERAL, (DLGPROC)GroupGeneralPageProc, szGroupName);
370
371 return (PropertySheet(&psh) == IDOK);
372 }