23edfa1e465f104cff87e802a717a88f5adbe3c7
[reactos.git] / reactos / dll / win32 / netapi32 / local_group.c
1 /*
2 * Copyright 2006 Robert Reif
3 *
4 * netapi32 local group functions
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <stdarg.h>
22
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "lmcons.h"
29 #include "lmaccess.h"
30 #include "lmapibuf.h"
31 #include "lmerr.h"
32 #include "winreg.h"
33 #include "ntsecapi.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36
37 #define NTOS_MODE_USER
38 #include <ndk/rtlfuncs.h>
39 #include "ntsam.h"
40 #include "netapi32.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(netapi32);
43
44
45 typedef struct _ENUM_CONTEXT
46 {
47 SAM_HANDLE ServerHandle;
48 SAM_HANDLE BuiltinDomainHandle;
49 SAM_HANDLE AccountDomainHandle;
50
51 SAM_ENUMERATE_HANDLE EnumerationContext;
52 PSAM_RID_ENUMERATION Buffer;
53 ULONG Returned;
54 ULONG Index;
55 BOOLEAN BuiltinDone;
56
57 } ENUM_CONTEXT, *PENUM_CONTEXT;
58
59
60 static
61 NET_API_STATUS
62 BuildAliasInfoBuffer(PALIAS_GENERAL_INFORMATION AliasInfo,
63 DWORD level,
64 LPVOID *Buffer)
65 {
66 LPVOID LocalBuffer = NULL;
67 PLOCALGROUP_INFO_0 LocalInfo0;
68 PLOCALGROUP_INFO_1 LocalInfo1;
69 LPWSTR Ptr;
70 ULONG Size = 0;
71 NET_API_STATUS ApiStatus = NERR_Success;
72
73 *Buffer = NULL;
74
75 switch (level)
76 {
77 case 0:
78 Size = sizeof(LOCALGROUP_INFO_0) +
79 AliasInfo->Name.Length + sizeof(WCHAR);
80 break;
81
82 case 1:
83 Size = sizeof(LOCALGROUP_INFO_1) +
84 AliasInfo->Name.Length + sizeof(WCHAR) +
85 AliasInfo->AdminComment.Length + sizeof(WCHAR);
86 break;
87
88 default:
89 ApiStatus = ERROR_INVALID_LEVEL;
90 goto done;
91 }
92
93 ApiStatus = NetApiBufferAllocate(Size, &LocalBuffer);
94 if (ApiStatus != NERR_Success)
95 goto done;
96
97 ZeroMemory(LocalBuffer, Size);
98
99 switch (level)
100 {
101 case 0:
102 LocalInfo0 = (PLOCALGROUP_INFO_0)LocalBuffer;
103
104 Ptr = (LPWSTR)LocalInfo0++;
105 LocalInfo0->lgrpi0_name = Ptr;
106
107 memcpy(LocalInfo0->lgrpi0_name,
108 AliasInfo->Name.Buffer,
109 AliasInfo->Name.Length);
110 LocalInfo0->lgrpi0_name[AliasInfo->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
111 break;
112
113 case 1:
114 LocalInfo1 = (PLOCALGROUP_INFO_1)LocalBuffer;
115
116 Ptr = (LPWSTR)((ULONG_PTR)LocalInfo1 + sizeof(LOCALGROUP_INFO_1));
117 LocalInfo1->lgrpi1_name = Ptr;
118
119 memcpy(LocalInfo1->lgrpi1_name,
120 AliasInfo->Name.Buffer,
121 AliasInfo->Name.Length);
122 LocalInfo1->lgrpi1_name[AliasInfo->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
123
124 Ptr = (LPWSTR)((ULONG_PTR)Ptr + AliasInfo->Name.Length + sizeof(WCHAR));
125 LocalInfo1->lgrpi1_comment = Ptr;
126
127 memcpy(LocalInfo1->lgrpi1_comment,
128 AliasInfo->AdminComment.Buffer,
129 AliasInfo->AdminComment.Length);
130 LocalInfo1->lgrpi1_comment[AliasInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
131 break;
132 }
133
134 done:
135 if (ApiStatus == NERR_Success)
136 {
137 *Buffer = LocalBuffer;
138 }
139 else
140 {
141 if (LocalBuffer != NULL)
142 NetApiBufferFree(LocalBuffer);
143 }
144
145 return ApiStatus;
146 }
147
148
149 static
150 VOID
151 FreeAliasInfo(PALIAS_GENERAL_INFORMATION AliasInfo)
152 {
153 if (AliasInfo->Name.Buffer != NULL)
154 SamFreeMemory(AliasInfo->Name.Buffer);
155
156 if (AliasInfo->AdminComment.Buffer != NULL)
157 SamFreeMemory(AliasInfo->AdminComment.Buffer);
158
159 SamFreeMemory(AliasInfo);
160 }
161
162
163 /************************************************************
164 * NetLocalGroupAdd (NETAPI32.@)
165 */
166 NET_API_STATUS WINAPI NetLocalGroupAdd(
167 LPCWSTR servername,
168 DWORD level,
169 LPBYTE buf,
170 LPDWORD parm_err)
171 {
172 FIXME("(%s %d %p %p) stub!\n", debugstr_w(servername), level, buf,
173 parm_err);
174 return NERR_Success;
175 }
176
177 /************************************************************
178 * NetLocalGroupAddMember (NETAPI32.@)
179 */
180 NET_API_STATUS WINAPI NetLocalGroupAddMember(
181 LPCWSTR servername,
182 LPCWSTR groupname,
183 PSID membersid)
184 {
185 FIXME("(%s %s %p) stub!\n", debugstr_w(servername),
186 debugstr_w(groupname), membersid);
187 return NERR_Success;
188 }
189
190 /************************************************************
191 * NetLocalGroupAddMembers (NETAPI32.@)
192 */
193 NET_API_STATUS WINAPI NetLocalGroupAddMembers(
194 LPCWSTR servername,
195 LPCWSTR groupname,
196 DWORD level,
197 LPBYTE buf,
198 DWORD totalentries)
199 {
200 FIXME("(%s %s %d %p %d) stub!\n", debugstr_w(servername),
201 debugstr_w(groupname), level, buf, totalentries);
202 return NERR_Success;
203 }
204
205 /************************************************************
206 * NetLocalGroupDel (NETAPI32.@)
207 */
208 NET_API_STATUS WINAPI NetLocalGroupDel(
209 LPCWSTR servername,
210 LPCWSTR groupname)
211 {
212 FIXME("(%s %s) stub!\n", debugstr_w(servername), debugstr_w(groupname));
213 return NERR_Success;
214 }
215
216 /************************************************************
217 * NetLocalGroupDelMember (NETAPI32.@)
218 */
219 NET_API_STATUS WINAPI NetLocalGroupDelMember(
220 LPCWSTR servername,
221 LPCWSTR groupname,
222 PSID membersid)
223 {
224 FIXME("(%s %s %p) stub!\n", debugstr_w(servername),
225 debugstr_w(groupname), membersid);
226 return NERR_Success;
227 }
228
229 /************************************************************
230 * NetLocalGroupDelMembers (NETAPI32.@)
231 */
232 NET_API_STATUS WINAPI NetLocalGroupDelMembers(
233 LPCWSTR servername,
234 LPCWSTR groupname,
235 DWORD level,
236 LPBYTE buf,
237 DWORD totalentries)
238 {
239 FIXME("(%s %s %d %p %d) stub!\n", debugstr_w(servername),
240 debugstr_w(groupname), level, buf, totalentries);
241 return NERR_Success;
242 }
243
244 /************************************************************
245 * NetLocalGroupEnum (NETAPI32.@)
246 */
247 NET_API_STATUS WINAPI NetLocalGroupEnum(
248 LPCWSTR servername,
249 DWORD level,
250 LPBYTE* bufptr,
251 DWORD prefmaxlen,
252 LPDWORD entriesread,
253 LPDWORD totalentries,
254 PDWORD_PTR resumehandle)
255 {
256 UNICODE_STRING ServerName;
257 PSAM_RID_ENUMERATION CurrentAlias;
258 PENUM_CONTEXT EnumContext = NULL;
259 PSID DomainSid = NULL;
260 ULONG i;
261 SAM_HANDLE AliasHandle = NULL;
262 PALIAS_GENERAL_INFORMATION AliasInfo = NULL;
263 LPVOID Buffer = NULL;
264 NET_API_STATUS ApiStatus = NERR_Success;
265 NTSTATUS Status = STATUS_SUCCESS;
266
267 FIXME("(%s %d %p %d %p %p %p) stub!\n", debugstr_w(servername),
268 level, bufptr, prefmaxlen, entriesread, totalentries, resumehandle);
269
270 *entriesread = 0;
271 *totalentries = 0;
272 *bufptr = NULL;
273
274 if (servername != NULL)
275 RtlInitUnicodeString(&ServerName, servername);
276
277 if (resumehandle != NULL && *resumehandle != 0)
278 {
279 EnumContext = (PENUM_CONTEXT)*resumehandle;
280 }
281 else
282 {
283 ApiStatus = NetApiBufferAllocate(sizeof(ENUM_CONTEXT), (PVOID*)&EnumContext);
284 if (ApiStatus != NERR_Success)
285 goto done;
286
287 EnumContext->EnumerationContext = 0;
288 EnumContext->Buffer = NULL;
289 EnumContext->Returned = 0;
290 EnumContext->Index = 0;
291 EnumContext->BuiltinDone = FALSE;
292
293 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
294 &EnumContext->ServerHandle,
295 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
296 NULL);
297 if (!NT_SUCCESS(Status))
298 {
299 ERR("SamConnect failed (Status %08lx)\n", Status);
300 ApiStatus = NetpNtStatusToApiStatus(Status);
301 goto done;
302 }
303
304 Status = GetAccountDomainSid((servername != NULL) ? &ServerName : NULL,
305 &DomainSid);
306 if (!NT_SUCCESS(Status))
307 {
308 ERR("GetAccountDomainSid failed (Status %08lx)\n", Status);
309 ApiStatus = NetpNtStatusToApiStatus(Status);
310 goto done;
311 }
312
313 Status = SamOpenDomain(EnumContext->ServerHandle,
314 DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
315 DomainSid,
316 &EnumContext->AccountDomainHandle);
317
318 RtlFreeHeap(RtlGetProcessHeap(), 0, DomainSid);
319
320 if (!NT_SUCCESS(Status))
321 {
322 ERR("SamOpenDomain failed (Status %08lx)\n", Status);
323 ApiStatus = NetpNtStatusToApiStatus(Status);
324 goto done;
325 }
326
327 Status = GetBuiltinDomainSid(&DomainSid);
328 if (!NT_SUCCESS(Status))
329 {
330 ERR("GetAccountDomainSid failed (Status %08lx)\n", Status);
331 ApiStatus = NetpNtStatusToApiStatus(Status);
332 goto done;
333 }
334
335 Status = SamOpenDomain(EnumContext->ServerHandle,
336 DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
337 DomainSid,
338 &EnumContext->BuiltinDomainHandle);
339
340 RtlFreeHeap(RtlGetProcessHeap(), 0, DomainSid);
341
342 if (!NT_SUCCESS(Status))
343 {
344 ERR("SamOpenDomain failed (Status %08lx)\n", Status);
345 ApiStatus = NetpNtStatusToApiStatus(Status);
346 goto done;
347 }
348 }
349
350
351 // while (TRUE)
352 // {
353 TRACE("EnumContext->Index: %lu\n", EnumContext->Index);
354 TRACE("EnumContext->Returned: %lu\n", EnumContext->Returned);
355
356 if (EnumContext->Index >= EnumContext->Returned)
357 {
358 // if (EnumContext->BuiltinDone == TRUE)
359 // {
360 // ApiStatus = NERR_Success;
361 // goto done;
362 // }
363
364 TRACE("Calling SamEnumerateAliasesInDomain\n");
365
366 Status = SamEnumerateAliasesInDomain(EnumContext->BuiltinDomainHandle,
367 &EnumContext->EnumerationContext,
368 (PVOID *)&EnumContext->Buffer,
369 prefmaxlen,
370 &EnumContext->Returned);
371
372 TRACE("SamEnumerateAliasesInDomain returned (Status %08lx)\n", Status);
373 if (!NT_SUCCESS(Status))
374 {
375 ERR("SamEnumerateAliasesInDomain failed (Status %08lx)\n", Status);
376 ApiStatus = NetpNtStatusToApiStatus(Status);
377 goto done;
378 }
379
380 if (Status == STATUS_MORE_ENTRIES)
381 {
382 ApiStatus = NERR_BufTooSmall;
383 goto done;
384 }
385 else
386 {
387 EnumContext->BuiltinDone = TRUE;
388 }
389 }
390
391 TRACE("EnumContext: %lu\n", EnumContext);
392 TRACE("EnumContext->Returned: %lu\n", EnumContext->Returned);
393 TRACE("EnumContext->Buffer: %p\n", EnumContext->Buffer);
394
395 /* Get a pointer to the current alias */
396 CurrentAlias = &EnumContext->Buffer[EnumContext->Index];
397
398 TRACE("RID: %lu\n", CurrentAlias->RelativeId);
399
400 Status = SamOpenAlias(EnumContext->BuiltinDomainHandle,
401 ALIAS_READ_INFORMATION,
402 CurrentAlias->RelativeId,
403 &AliasHandle);
404 if (!NT_SUCCESS(Status))
405 {
406 ERR("SamOpenAlias failed (Status %08lx)\n", Status);
407 ApiStatus = NetpNtStatusToApiStatus(Status);
408 goto done;
409 }
410
411 Status = SamQueryInformationAlias(AliasHandle,
412 AliasGeneralInformation,
413 (PVOID *)&AliasInfo);
414 if (!NT_SUCCESS(Status))
415 {
416 ERR("SamQueryInformationAlias failed (Status %08lx)\n", Status);
417 ApiStatus = NetpNtStatusToApiStatus(Status);
418 goto done;
419 }
420
421 SamCloseHandle(AliasHandle);
422 AliasHandle = NULL;
423
424 TRACE("Name: %S\n", AliasInfo->Name.Buffer);
425 TRACE("Comment: %S\n", AliasInfo->AdminComment.Buffer);
426
427 ApiStatus = BuildAliasInfoBuffer(AliasInfo,
428 level,
429 &Buffer);
430 if (ApiStatus != NERR_Success)
431 goto done;
432
433 if (AliasInfo != NULL)
434 {
435 FreeAliasInfo(AliasInfo);
436 AliasInfo = NULL;
437 }
438
439 EnumContext->Index++;
440
441 (*entriesread)++;
442
443 // }
444
445 done:
446 if (ApiStatus == NERR_Success && EnumContext->Index < EnumContext->Returned)
447 ApiStatus = ERROR_MORE_DATA;
448
449 if (EnumContext != NULL)
450 *totalentries = EnumContext->Returned;
451
452 if (resumehandle == NULL || ApiStatus != ERROR_MORE_DATA)
453 {
454 if (EnumContext != NULL)
455 {
456 if (EnumContext->BuiltinDomainHandle != NULL)
457 SamCloseHandle(EnumContext->BuiltinDomainHandle);
458
459 if (EnumContext->AccountDomainHandle != NULL)
460 SamCloseHandle(EnumContext->AccountDomainHandle);
461
462 if (EnumContext->ServerHandle != NULL)
463 SamCloseHandle(EnumContext->ServerHandle);
464
465 if (EnumContext->Buffer != NULL)
466 {
467 for (i = 0; i < EnumContext->Returned; i++)
468 {
469 SamFreeMemory(EnumContext->Buffer[i].Name.Buffer);
470 }
471
472 SamFreeMemory(EnumContext->Buffer);
473 }
474
475 NetApiBufferFree(EnumContext);
476 EnumContext = NULL;
477 }
478 }
479
480 if (AliasHandle != NULL)
481 SamCloseHandle(AliasHandle);
482
483 if (AliasInfo != NULL)
484 FreeAliasInfo(AliasInfo);
485
486 if (resumehandle != NULL)
487 *resumehandle = (DWORD_PTR)EnumContext;
488
489 *bufptr = (LPBYTE)Buffer;
490
491 TRACE ("return %lu\n", ApiStatus);
492
493 return ApiStatus;
494 }
495
496
497 /************************************************************
498 * NetLocalGroupGetInfo (NETAPI32.@)
499 */
500 NET_API_STATUS
501 WINAPI
502 NetLocalGroupGetInfo(
503 LPCWSTR servername,
504 LPCWSTR groupname,
505 DWORD level,
506 LPBYTE* bufptr)
507 {
508 UNICODE_STRING ServerName;
509 UNICODE_STRING GroupName;
510 SAM_HANDLE ServerHandle = NULL;
511 SAM_HANDLE DomainHandle = NULL;
512 SAM_HANDLE AliasHandle = NULL;
513 PSID DomainSid = NULL;
514 PULONG RelativeIds = NULL;
515 PSID_NAME_USE Use = NULL;
516 PALIAS_GENERAL_INFORMATION AliasInfo = NULL;
517 LPVOID Buffer = NULL;
518 NET_API_STATUS ApiStatus = NERR_Success;
519 NTSTATUS Status = STATUS_SUCCESS;
520
521 FIXME("(%s %s %d %p) stub!\n", debugstr_w(servername),
522 debugstr_w(groupname), level, bufptr);
523
524 if (servername != NULL)
525 RtlInitUnicodeString(&ServerName, servername);
526
527 RtlInitUnicodeString(&GroupName, groupname);
528
529 /* Connect to the SAM Server */
530 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
531 &ServerHandle,
532 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
533 NULL);
534 if (!NT_SUCCESS(Status))
535 {
536 ERR("SamConnect failed (Status %08lx)\n", Status);
537 ApiStatus = NetpNtStatusToApiStatus(Status);
538 goto done;
539 }
540
541 /* Get the Builtin Domain SID */
542 Status = GetBuiltinDomainSid(&DomainSid);
543 if (!NT_SUCCESS(Status))
544 {
545 ERR("GetBuiltinDomainSid failed (Status %08lx)\n", Status);
546 ApiStatus = NetpNtStatusToApiStatus(Status);
547 goto done;
548 }
549
550 /* Open the Builtin Domain */
551 Status = SamOpenDomain(ServerHandle,
552 DOMAIN_LOOKUP,
553 DomainSid,
554 &DomainHandle);
555 if (!NT_SUCCESS(Status))
556 {
557 ERR("SamOpenDomain failed (Status %08lx)\n", Status);
558 ApiStatus = NetpNtStatusToApiStatus(Status);
559 goto done;
560 }
561
562 /* Get the RID for the given user name */
563 Status = SamLookupNamesInDomain(DomainHandle,
564 1,
565 &GroupName,
566 &RelativeIds,
567 &Use);
568 if (!NT_SUCCESS(Status) && Status != STATUS_NONE_MAPPED)
569 {
570 ERR("SamOpenDomain failed (Status %08lx)\n", Status);
571 ApiStatus = NetpNtStatusToApiStatus(Status);
572 goto done;
573 }
574
575 if (Status == STATUS_SUCCESS)
576 {
577 /* FIXME: Check Use*/
578
579 Status = SamOpenAlias(DomainHandle,
580 ALIAS_READ_INFORMATION,
581 RelativeIds[0],
582 &AliasHandle);
583 if (!NT_SUCCESS(Status))
584 {
585 ERR("SamOpenDomain failed (Status %08lx)\n", Status);
586 ApiStatus = NetpNtStatusToApiStatus(Status);
587 goto done;
588 }
589 }
590
591 if (AliasHandle == NULL)
592 {
593 if (RelativeIds != NULL)
594 SamFreeMemory(RelativeIds);
595
596 if (Use != NULL)
597 SamFreeMemory(Use);
598
599 if (DomainSid != NULL)
600 RtlFreeHeap(RtlGetProcessHeap(), 0, DomainSid);
601
602 if (DomainHandle != NULL)
603 SamCloseHandle(DomainHandle);
604
605
606 /* Get the Account Domain SID */
607 Status = GetAccountDomainSid((servername != NULL) ? &ServerName : NULL,
608 &DomainSid);
609 if (!NT_SUCCESS(Status))
610 {
611 ERR("GetAccountDomainSid failed (Status %08lx)\n", Status);
612 ApiStatus = NetpNtStatusToApiStatus(Status);
613 goto done;
614 }
615
616 /* Open the Acount Domain */
617 Status = SamOpenDomain(ServerHandle,
618 DOMAIN_LOOKUP,
619 DomainSid,
620 &DomainHandle);
621 if (!NT_SUCCESS(Status))
622 {
623 ERR("SamOpenDomain failed (Status %08lx)\n", Status);
624 ApiStatus = NetpNtStatusToApiStatus(Status);
625 goto done;
626 }
627
628 /* Get the RID for the given user name */
629 Status = SamLookupNamesInDomain(DomainHandle,
630 1,
631 &GroupName,
632 &RelativeIds,
633 &Use);
634 if (!NT_SUCCESS(Status))
635 {
636 ERR("SamOpenDomain failed (Status %08lx)\n", Status);
637 ApiStatus = NetpNtStatusToApiStatus(Status);
638 goto done;
639 }
640
641 /* FIXME: Check Use*/
642
643 Status = SamOpenAlias(DomainHandle,
644 ALIAS_READ_INFORMATION,
645 RelativeIds[0],
646 &AliasHandle);
647 if (!NT_SUCCESS(Status))
648 {
649 ERR("SamOpenDomain failed (Status %08lx)\n", Status);
650 ApiStatus = NetpNtStatusToApiStatus(Status);
651 goto done;
652 }
653 }
654
655 Status = SamQueryInformationAlias(AliasHandle,
656 AliasGeneralInformation,
657 (PVOID *)&AliasInfo);
658 if (!NT_SUCCESS(Status))
659 {
660 ERR("SamQueryInformationAlias failed (Status %08lx)\n", Status);
661 ApiStatus = NetpNtStatusToApiStatus(Status);
662 goto done;
663 }
664
665 ApiStatus = BuildAliasInfoBuffer(AliasInfo,
666 level,
667 &Buffer);
668 if (ApiStatus != NERR_Success)
669 goto done;
670
671 done:
672 if (AliasInfo != NULL)
673 FreeAliasInfo(AliasInfo);
674
675 if (AliasHandle != NULL)
676 SamCloseHandle(AliasHandle);
677
678 if (RelativeIds != NULL)
679 SamFreeMemory(RelativeIds);
680
681 if (Use != NULL)
682 SamFreeMemory(Use);
683
684 if (DomainSid != NULL)
685 RtlFreeHeap(RtlGetProcessHeap(), 0, DomainSid);
686
687 if (DomainHandle != NULL)
688 SamCloseHandle(DomainHandle);
689
690 if (ServerHandle != NULL)
691 SamCloseHandle(ServerHandle);
692
693 *bufptr = (LPBYTE)Buffer;
694
695 return NERR_Success;
696 }
697
698
699 /************************************************************
700 * NetLocalGroupGetMembers (NETAPI32.@)
701 */
702 NET_API_STATUS WINAPI NetLocalGroupGetMembers(
703 LPCWSTR servername,
704 LPCWSTR localgroupname,
705 DWORD level,
706 LPBYTE* bufptr,
707 DWORD prefmaxlen,
708 LPDWORD entriesread,
709 LPDWORD totalentries,
710 PDWORD_PTR resumehandle)
711 {
712 FIXME("(%s %s %d %p %d, %p %p %p) stub!\n", debugstr_w(servername),
713 debugstr_w(localgroupname), level, bufptr, prefmaxlen, entriesread,
714 totalentries, resumehandle);
715
716 if (level == 3)
717 {
718 WCHAR userName[MAX_COMPUTERNAME_LENGTH + 1];
719 DWORD userNameLen;
720 DWORD len,needlen;
721 PLOCALGROUP_MEMBERS_INFO_3 ptr;
722
723 /* still a stub, current user is belonging to all groups */
724
725 *totalentries = 1;
726 *entriesread = 0;
727
728 userNameLen = MAX_COMPUTERNAME_LENGTH + 1;
729 GetUserNameW(userName,&userNameLen);
730 needlen = sizeof(LOCALGROUP_MEMBERS_INFO_3) +
731 (userNameLen+2) * sizeof(WCHAR);
732 if (prefmaxlen != MAX_PREFERRED_LENGTH)
733 len = min(prefmaxlen,needlen);
734 else
735 len = needlen;
736
737 NetApiBufferAllocate(len, (LPVOID *) bufptr);
738 if (len < needlen)
739 return ERROR_MORE_DATA;
740
741 ptr = (PLOCALGROUP_MEMBERS_INFO_3)*bufptr;
742 ptr->lgrmi3_domainandname = (LPWSTR)(*bufptr+sizeof(LOCALGROUP_MEMBERS_INFO_3));
743 lstrcpyW(ptr->lgrmi3_domainandname,userName);
744
745 *entriesread = 1;
746 }
747
748 return NERR_Success;
749 }
750
751 /************************************************************
752 * NetLocalGroupSetInfo (NETAPI32.@)
753 */
754 NET_API_STATUS WINAPI NetLocalGroupSetInfo(
755 LPCWSTR servername,
756 LPCWSTR groupname,
757 DWORD level,
758 LPBYTE buf,
759 LPDWORD parm_err)
760 {
761 FIXME("(%s %s %d %p %p) stub!\n", debugstr_w(servername),
762 debugstr_w(groupname), level, buf, parm_err);
763 return NERR_Success;
764 }
765
766 /************************************************************
767 * NetLocalGroupSetMember (NETAPI32.@)
768 */
769 NET_API_STATUS WINAPI NetLocalGroupSetMembers(
770 LPCWSTR servername,
771 LPCWSTR groupname,
772 DWORD level,
773 LPBYTE buf,
774 DWORD totalentries)
775 {
776 FIXME("(%s %s %d %p %d) stub!\n", debugstr_w(servername),
777 debugstr_w(groupname), level, buf, totalentries);
778 return NERR_Success;
779 }