5fa38313cf209eaca3e7e67a8b9144ba4067c3f5
[reactos.git] / dll / win32 / netapi32 / group_new.c
1 /*
2 * PROJECT: ReactOS NetAPI DLL
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: SAM service group interface code
5 * COPYRIGHT: Copyright 2018 Eric Kohl (eric.kohl@reactos.org)
6 */
7
8 /* INCLUDES ******************************************************************/
9
10 #include "netapi32.h"
11
12 WINE_DEFAULT_DEBUG_CHANNEL(netapi32);
13
14 typedef enum _ENUM_PHASE
15 {
16 BuiltinPhase,
17 AccountPhase,
18 DonePhase
19 } ENUM_PHASE;
20
21 typedef struct _ENUM_CONTEXT
22 {
23 SAM_HANDLE ServerHandle;
24 SAM_HANDLE DomainHandle;
25 SAM_HANDLE BuiltinDomainHandle;
26 SAM_HANDLE AccountDomainHandle;
27
28 SAM_ENUMERATE_HANDLE EnumerationContext;
29 PSAM_RID_ENUMERATION Buffer;
30 ULONG Returned;
31 ULONG Index;
32 ENUM_PHASE Phase;
33 } ENUM_CONTEXT, *PENUM_CONTEXT;
34
35
36 /* FUNCTIONS *****************************************************************/
37
38 static
39 NET_API_STATUS
40 BuildGroupInfoBuffer(
41 _In_ PGROUP_GENERAL_INFORMATION GroupInfo,
42 _In_ DWORD Level,
43 _In_ DWORD GroupId,
44 _Out_ LPVOID *Buffer)
45 {
46 PVOID GroupBuffer = NULL;
47 PGROUP_INFO_0 GroupInfo0;
48 PGROUP_INFO_1 GroupInfo1;
49 PGROUP_INFO_2 GroupInfo2;
50 PGROUP_INFO_3 GroupInfo3;
51 PWSTR Ptr;
52 ULONG Size = 0;
53 NET_API_STATUS ApiStatus = NERR_Success;
54
55 *Buffer = NULL;
56
57 switch (Level)
58 {
59 case 0:
60 Size = sizeof(GROUP_INFO_0) +
61 GroupInfo->Name.Length + sizeof(WCHAR);
62 break;
63
64 case 1:
65 Size = sizeof(GROUP_INFO_1) +
66 GroupInfo->Name.Length + sizeof(WCHAR) +
67 GroupInfo->AdminComment.Length + sizeof(WCHAR);
68 break;
69
70 case 2:
71 Size = sizeof(GROUP_INFO_2) +
72 GroupInfo->Name.Length + sizeof(WCHAR) +
73 GroupInfo->AdminComment.Length + sizeof(WCHAR);
74 break;
75
76 case 3:
77 Size = sizeof(GROUP_INFO_3) +
78 GroupInfo->Name.Length + sizeof(WCHAR) +
79 GroupInfo->AdminComment.Length + sizeof(WCHAR);
80 /* FIXME: Sid size */
81 break;
82
83 default:
84 ApiStatus = ERROR_INVALID_LEVEL;
85 goto done;
86 }
87
88 ApiStatus = NetApiBufferAllocate(Size, &GroupBuffer);
89 if (ApiStatus != NERR_Success)
90 goto done;
91
92 ZeroMemory(GroupBuffer, Size);
93
94 switch (Level)
95 {
96 case 0:
97 GroupInfo0 = (PGROUP_INFO_0)GroupBuffer;
98
99 Ptr = (PWSTR)((ULONG_PTR)GroupInfo0 + sizeof(LOCALGROUP_INFO_0));
100 GroupInfo0->grpi0_name = Ptr;
101
102 memcpy(GroupInfo0->grpi0_name,
103 GroupInfo->Name.Buffer,
104 GroupInfo->Name.Length);
105 GroupInfo0->grpi0_name[GroupInfo->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
106 break;
107
108 case 1:
109 GroupInfo1 = (PGROUP_INFO_1)GroupBuffer;
110
111 Ptr = (PWSTR)((ULONG_PTR)GroupInfo1 + sizeof(GROUP_INFO_1));
112 GroupInfo1->grpi1_name = Ptr;
113
114 memcpy(GroupInfo1->grpi1_name,
115 GroupInfo->Name.Buffer,
116 GroupInfo->Name.Length);
117 GroupInfo1->grpi1_name[GroupInfo->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
118
119 Ptr = (PWSTR)((ULONG_PTR)Ptr + GroupInfo->Name.Length + sizeof(WCHAR));
120 GroupInfo1->grpi1_comment = Ptr;
121
122 memcpy(GroupInfo1->grpi1_comment,
123 GroupInfo->AdminComment.Buffer,
124 GroupInfo->AdminComment.Length);
125 GroupInfo1->grpi1_comment[GroupInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
126 break;
127
128 case 2:
129 GroupInfo2 = (PGROUP_INFO_2)GroupBuffer;
130
131 Ptr = (PWSTR)((ULONG_PTR)GroupInfo2 + sizeof(GROUP_INFO_2));
132 GroupInfo2->grpi2_name = Ptr;
133
134 memcpy(GroupInfo2->grpi2_name,
135 GroupInfo->Name.Buffer,
136 GroupInfo->Name.Length);
137 GroupInfo2->grpi2_name[GroupInfo->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
138
139 Ptr = (PWSTR)((ULONG_PTR)Ptr + GroupInfo->Name.Length + sizeof(WCHAR));
140 GroupInfo2->grpi2_comment = Ptr;
141
142 memcpy(GroupInfo2->grpi2_comment,
143 GroupInfo->AdminComment.Buffer,
144 GroupInfo->AdminComment.Length);
145 GroupInfo2->grpi2_comment[GroupInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
146
147 GroupInfo2->grpi2_group_id = GroupId;
148
149 GroupInfo2->grpi2_attributes= GroupInfo->Attributes;
150 break;
151
152 case 3:
153 GroupInfo3 = (PGROUP_INFO_3)GroupBuffer;
154
155 Ptr = (PWSTR)((ULONG_PTR)GroupInfo3 + sizeof(GROUP_INFO_3));
156 GroupInfo3->grpi3_name = Ptr;
157
158 memcpy(GroupInfo3->grpi3_name,
159 GroupInfo->Name.Buffer,
160 GroupInfo->Name.Length);
161 GroupInfo3->grpi3_name[GroupInfo->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
162
163 Ptr = (PWSTR)((ULONG_PTR)Ptr + GroupInfo->Name.Length + sizeof(WCHAR));
164 GroupInfo3->grpi3_comment = Ptr;
165
166 memcpy(GroupInfo3->grpi3_comment,
167 GroupInfo->AdminComment.Buffer,
168 GroupInfo->AdminComment.Length);
169 GroupInfo3->grpi3_comment[GroupInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
170
171 GroupInfo3->grpi3_group_sid = NULL; /* FIXME */
172
173 GroupInfo3->grpi3_attributes= GroupInfo->Attributes;
174 break;
175 }
176
177 done:
178 if (ApiStatus == NERR_Success)
179 {
180 *Buffer = GroupBuffer;
181 }
182 else
183 {
184 if (GroupBuffer != NULL)
185 NetApiBufferFree(GroupBuffer);
186 }
187
188 return ApiStatus;
189 }
190
191
192 static
193 VOID
194 FreeGroupInfo(
195 PGROUP_GENERAL_INFORMATION GroupInfo)
196 {
197 if (GroupInfo->Name.Buffer != NULL)
198 SamFreeMemory(GroupInfo->Name.Buffer);
199
200 if (GroupInfo->AdminComment.Buffer != NULL)
201 SamFreeMemory(GroupInfo->AdminComment.Buffer);
202
203 SamFreeMemory(GroupInfo);
204 }
205
206
207 /* PUBLIC FUNCTIONS **********************************************************/
208
209 NET_API_STATUS
210 WINAPI
211 NetGroupEnum(
212 _In_opt_ LPCWSTR servername,
213 _In_ DWORD level,
214 _Out_ LPBYTE *bufptr,
215 _In_ DWORD prefmaxlen,
216 _Out_ LPDWORD entriesread,
217 _Out_ LPDWORD totalentries,
218 _Inout_opt_ PDWORD_PTR resume_handle)
219 {
220 UNICODE_STRING ServerName;
221 PSAM_RID_ENUMERATION CurrentGroup;
222 PENUM_CONTEXT EnumContext = NULL;
223 ULONG i;
224 SAM_HANDLE GroupHandle = NULL;
225 PGROUP_GENERAL_INFORMATION GroupInfo = NULL;
226 PVOID Buffer = NULL;
227 NET_API_STATUS ApiStatus = NERR_Success;
228 NTSTATUS Status = STATUS_SUCCESS;
229
230 TRACE("NetGroupEnum(%s, %d, %p, %d, %p, %p, %p)\n", debugstr_w(servername),
231 level, bufptr, prefmaxlen, entriesread, totalentries, resume_handle);
232
233 *entriesread = 0;
234 *totalentries = 0;
235 *bufptr = NULL;
236
237 if (servername != NULL)
238 RtlInitUnicodeString(&ServerName, servername);
239
240 if (resume_handle != NULL && *resume_handle != 0)
241 {
242 EnumContext = (PENUM_CONTEXT)*resume_handle;
243 }
244 else
245 {
246 ApiStatus = NetApiBufferAllocate(sizeof(ENUM_CONTEXT), (PVOID*)&EnumContext);
247 if (ApiStatus != NERR_Success)
248 goto done;
249
250 EnumContext->EnumerationContext = 0;
251 EnumContext->Buffer = NULL;
252 EnumContext->Returned = 0;
253 EnumContext->Index = 0;
254
255 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
256 &EnumContext->ServerHandle,
257 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
258 NULL);
259 if (!NT_SUCCESS(Status))
260 {
261 ERR("SamConnect failed (Status %08lx)\n", Status);
262 ApiStatus = NetpNtStatusToApiStatus(Status);
263 goto done;
264 }
265
266 Status = OpenAccountDomain(EnumContext->ServerHandle,
267 (servername != NULL) ? &ServerName : NULL,
268 DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
269 &EnumContext->AccountDomainHandle);
270 if (!NT_SUCCESS(Status))
271 {
272 ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
273 ApiStatus = NetpNtStatusToApiStatus(Status);
274 goto done;
275 }
276
277 Status = OpenBuiltinDomain(EnumContext->ServerHandle,
278 DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
279 &EnumContext->BuiltinDomainHandle);
280 if (!NT_SUCCESS(Status))
281 {
282 ERR("OpenBuiltinDomain failed (Status %08lx)\n", Status);
283 ApiStatus = NetpNtStatusToApiStatus(Status);
284 goto done;
285 }
286
287 EnumContext->Phase = AccountPhase; //BuiltinPhase;
288 EnumContext->DomainHandle = EnumContext->AccountDomainHandle; //BuiltinDomainHandle;
289 }
290
291
292 // while (TRUE)
293 // {
294 TRACE("EnumContext->Index: %lu\n", EnumContext->Index);
295 TRACE("EnumContext->Returned: %lu\n", EnumContext->Returned);
296
297 if (EnumContext->Index >= EnumContext->Returned)
298 {
299 TRACE("Calling SamEnumerateGroupsInDomain\n");
300
301 Status = SamEnumerateGroupsInDomain(EnumContext->DomainHandle,
302 &EnumContext->EnumerationContext,
303 (PVOID *)&EnumContext->Buffer,
304 prefmaxlen,
305 &EnumContext->Returned);
306
307 TRACE("SamEnumerateGroupsInDomain returned (Status %08lx)\n", Status);
308 if (!NT_SUCCESS(Status))
309 {
310 ERR("SamEnumerateAliasesInDomain failed (Status %08lx)\n", Status);
311 ApiStatus = NetpNtStatusToApiStatus(Status);
312 goto done;
313 }
314
315 if (Status == STATUS_MORE_ENTRIES)
316 {
317 ApiStatus = NERR_BufTooSmall;
318 goto done;
319 }
320 }
321
322 TRACE("EnumContext: %lu\n", EnumContext);
323 TRACE("EnumContext->Returned: %lu\n", EnumContext->Returned);
324 TRACE("EnumContext->Buffer: %p\n", EnumContext->Buffer);
325
326 /* Get a pointer to the current group */
327 CurrentGroup = &EnumContext->Buffer[EnumContext->Index];
328
329 TRACE("RID: %lu\n", CurrentGroup->RelativeId);
330
331 Status = SamOpenGroup(EnumContext->DomainHandle,
332 GROUP_READ_INFORMATION,
333 CurrentGroup->RelativeId,
334 &GroupHandle);
335 if (!NT_SUCCESS(Status))
336 {
337 ERR("SamOpenGroup failed (Status %08lx)\n", Status);
338 ApiStatus = NetpNtStatusToApiStatus(Status);
339 goto done;
340 }
341
342 Status = SamQueryInformationGroup(GroupHandle,
343 GroupGeneralInformation,
344 (PVOID *)&GroupInfo);
345 if (!NT_SUCCESS(Status))
346 {
347 ERR("SamQueryInformationGroup failed (Status %08lx)\n", Status);
348 ApiStatus = NetpNtStatusToApiStatus(Status);
349 goto done;
350 }
351
352 SamCloseHandle(GroupHandle);
353 GroupHandle = NULL;
354
355 TRACE("Name: %S\n", GroupInfo->Name.Buffer);
356 TRACE("Comment: %S\n", GroupInfo->AdminComment.Buffer);
357
358 ApiStatus = BuildGroupInfoBuffer(GroupInfo,
359 level,
360 CurrentGroup->RelativeId,
361 &Buffer);
362 if (ApiStatus != NERR_Success)
363 goto done;
364
365 if (GroupInfo != NULL)
366 {
367 FreeGroupInfo(GroupInfo);
368 GroupInfo = NULL;
369 }
370
371 EnumContext->Index++;
372
373 (*entriesread)++;
374
375 if (EnumContext->Index == EnumContext->Returned)
376 {
377 switch (EnumContext->Phase)
378 {
379 case BuiltinPhase:
380 EnumContext->Phase = AccountPhase;
381 EnumContext->DomainHandle = EnumContext->AccountDomainHandle;
382 EnumContext->EnumerationContext = 0;
383 EnumContext->Index = 0;
384 EnumContext->Returned = 0;
385
386 if (EnumContext->Buffer != NULL)
387 {
388 for (i = 0; i < EnumContext->Returned; i++)
389 {
390 SamFreeMemory(EnumContext->Buffer[i].Name.Buffer);
391 }
392
393 SamFreeMemory(EnumContext->Buffer);
394 EnumContext->Buffer = NULL;
395 }
396 break;
397
398 case AccountPhase:
399 case DonePhase:
400 EnumContext->Phase = DonePhase;
401 break;
402 }
403 }
404 // }
405
406 done:
407 if (ApiStatus == NERR_Success && EnumContext != NULL && EnumContext->Phase != DonePhase)
408 ApiStatus = ERROR_MORE_DATA;
409
410 if (EnumContext != NULL)
411 *totalentries = EnumContext->Returned;
412
413 if (resume_handle == NULL || ApiStatus != ERROR_MORE_DATA)
414 {
415 if (EnumContext != NULL)
416 {
417 if (EnumContext->BuiltinDomainHandle != NULL)
418 SamCloseHandle(EnumContext->BuiltinDomainHandle);
419
420 if (EnumContext->AccountDomainHandle != NULL)
421 SamCloseHandle(EnumContext->AccountDomainHandle);
422
423 if (EnumContext->ServerHandle != NULL)
424 SamCloseHandle(EnumContext->ServerHandle);
425
426 if (EnumContext->Buffer != NULL)
427 {
428 for (i = 0; i < EnumContext->Returned; i++)
429 {
430 SamFreeMemory(EnumContext->Buffer[i].Name.Buffer);
431 }
432
433 SamFreeMemory(EnumContext->Buffer);
434 }
435
436 NetApiBufferFree(EnumContext);
437 EnumContext = NULL;
438 }
439 }
440
441 if (GroupHandle != NULL)
442 SamCloseHandle(GroupHandle);
443
444 if (GroupInfo != NULL)
445 FreeGroupInfo(GroupInfo);
446
447 if (resume_handle != NULL)
448 *resume_handle = (DWORD_PTR)EnumContext;
449
450 *bufptr = (LPBYTE)Buffer;
451
452 TRACE("return %lu\n", ApiStatus);
453
454 return ApiStatus;
455 }
456
457 /* EOF */