03a7a71588e69fc5c018b42f59c5cf723438fbe1
[samba.git] / source3 / lib / netapi / localgroup.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  NetApi LocalGroup Support
4  *  Copyright (C) Guenther Deschner 2008
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program 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
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21
22 #include "librpc/gen_ndr/libnetapi.h"
23 #include "lib/netapi/netapi.h"
24 #include "lib/netapi/netapi_private.h"
25 #include "lib/netapi/libnetapi.h"
26 #include "../librpc/gen_ndr/cli_samr.h"
27 #include "../librpc/gen_ndr/cli_lsa.h"
28 #include "rpc_client/cli_lsarpc.h"
29 #include "rpc_client/init_lsa.h"
30
31 static NTSTATUS libnetapi_samr_lookup_and_open_alias(TALLOC_CTX *mem_ctx,
32                                                      struct rpc_pipe_client *pipe_cli,
33                                                      struct policy_handle *domain_handle,
34                                                      const char *group_name,
35                                                      uint32_t access_rights,
36                                                      struct policy_handle *alias_handle)
37 {
38         NTSTATUS status;
39
40         struct lsa_String lsa_account_name;
41         struct samr_Ids user_rids, name_types;
42
43         init_lsa_String(&lsa_account_name, group_name);
44
45         status = rpccli_samr_LookupNames(pipe_cli, mem_ctx,
46                                          domain_handle,
47                                          1,
48                                          &lsa_account_name,
49                                          &user_rids,
50                                          &name_types);
51         if (!NT_STATUS_IS_OK(status)) {
52                 return status;
53         }
54
55         switch (name_types.ids[0]) {
56                 case SID_NAME_ALIAS:
57                 case SID_NAME_WKN_GRP:
58                         break;
59                 default:
60                         return NT_STATUS_INVALID_SID;
61         }
62
63         return rpccli_samr_OpenAlias(pipe_cli, mem_ctx,
64                                      domain_handle,
65                                      access_rights,
66                                      user_rids.ids[0],
67                                      alias_handle);
68 }
69
70 /****************************************************************
71 ****************************************************************/
72
73 static NTSTATUS libnetapi_samr_open_alias_queryinfo(TALLOC_CTX *mem_ctx,
74                                                     struct rpc_pipe_client *pipe_cli,
75                                                     struct policy_handle *handle,
76                                                     uint32_t rid,
77                                                     uint32_t access_rights,
78                                                     enum samr_AliasInfoEnum level,
79                                                     union samr_AliasInfo **alias_info)
80 {
81         NTSTATUS status;
82         struct policy_handle alias_handle;
83         union samr_AliasInfo *_alias_info = NULL;
84
85         ZERO_STRUCT(alias_handle);
86
87         status = rpccli_samr_OpenAlias(pipe_cli, mem_ctx,
88                                        handle,
89                                        access_rights,
90                                        rid,
91                                        &alias_handle);
92         if (!NT_STATUS_IS_OK(status)) {
93                 goto done;
94         }
95
96         status = rpccli_samr_QueryAliasInfo(pipe_cli, mem_ctx,
97                                             &alias_handle,
98                                             level,
99                                             &_alias_info);
100         if (!NT_STATUS_IS_OK(status)) {
101                 goto done;
102         }
103
104         *alias_info = _alias_info;
105
106  done:
107         if (is_valid_policy_hnd(&alias_handle)) {
108                 rpccli_samr_Close(pipe_cli, mem_ctx, &alias_handle);
109         }
110
111         return status;
112 }
113
114 /****************************************************************
115 ****************************************************************/
116
117 WERROR NetLocalGroupAdd_r(struct libnetapi_ctx *ctx,
118                           struct NetLocalGroupAdd *r)
119 {
120         struct rpc_pipe_client *pipe_cli = NULL;
121         NTSTATUS status;
122         WERROR werr;
123         struct lsa_String lsa_account_name;
124         struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
125         struct dom_sid2 *domain_sid = NULL;
126         uint32_t rid;
127
128         struct LOCALGROUP_INFO_0 *info0 = NULL;
129         struct LOCALGROUP_INFO_1 *info1 = NULL;
130
131         const char *alias_name = NULL;
132
133         if (!r->in.buffer) {
134                 return WERR_INVALID_PARAM;
135         }
136
137         switch (r->in.level) {
138                 case 0:
139                         info0 = (struct LOCALGROUP_INFO_0 *)r->in.buffer;
140                         alias_name = info0->lgrpi0_name;
141                         break;
142                 case 1:
143                         info1 = (struct LOCALGROUP_INFO_1 *)r->in.buffer;
144                         alias_name = info1->lgrpi1_name;
145                         break;
146                 default:
147                         werr = WERR_UNKNOWN_LEVEL;
148                         goto done;
149         }
150
151         ZERO_STRUCT(connect_handle);
152         ZERO_STRUCT(builtin_handle);
153         ZERO_STRUCT(domain_handle);
154         ZERO_STRUCT(alias_handle);
155
156         werr = libnetapi_open_pipe(ctx, r->in.server_name,
157                                    &ndr_table_samr.syntax_id,
158                                    &pipe_cli);
159         if (!W_ERROR_IS_OK(werr)) {
160                 goto done;
161         }
162
163         werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
164                                                   SAMR_ACCESS_LOOKUP_DOMAIN |
165                                                   SAMR_ACCESS_ENUM_DOMAINS,
166                                                   SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
167                                                   &connect_handle,
168                                                   &builtin_handle);
169         if (!W_ERROR_IS_OK(werr)) {
170                 goto done;
171         }
172
173         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
174                                                       &builtin_handle,
175                                                       alias_name,
176                                                       SAMR_ALIAS_ACCESS_LOOKUP_INFO,
177                                                       &alias_handle);
178         if (ctx->disable_policy_handle_cache) {
179                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
180         }
181
182         if (NT_STATUS_IS_OK(status)) {
183                 werr = WERR_ALIAS_EXISTS;
184                 goto done;
185         }
186
187         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
188                                           SAMR_ACCESS_ENUM_DOMAINS |
189                                           SAMR_ACCESS_LOOKUP_DOMAIN,
190                                           SAMR_DOMAIN_ACCESS_CREATE_ALIAS |
191                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
192                                           &connect_handle,
193                                           &domain_handle,
194                                           &domain_sid);
195         if (!W_ERROR_IS_OK(werr)) {
196                 goto done;
197         }
198
199         init_lsa_String(&lsa_account_name, alias_name);
200
201         status = rpccli_samr_CreateDomAlias(pipe_cli, ctx,
202                                             &domain_handle,
203                                             &lsa_account_name,
204                                             SEC_STD_DELETE |
205                                             SAMR_ALIAS_ACCESS_SET_INFO,
206                                             &alias_handle,
207                                             &rid);
208         if (!NT_STATUS_IS_OK(status)) {
209                 werr = ntstatus_to_werror(status);
210                 goto done;
211         }
212
213         if (r->in.level == 1 && info1->lgrpi1_comment) {
214
215                 union samr_AliasInfo alias_info;
216
217                 init_lsa_String(&alias_info.description, info1->lgrpi1_comment);
218
219                 status = rpccli_samr_SetAliasInfo(pipe_cli, ctx,
220                                                   &alias_handle,
221                                                   ALIASINFODESCRIPTION,
222                                                   &alias_info);
223                 if (!NT_STATUS_IS_OK(status)) {
224                         werr = ntstatus_to_werror(status);
225                         goto done;
226                 }
227         }
228
229         werr = WERR_OK;
230
231  done:
232         if (is_valid_policy_hnd(&alias_handle)) {
233                 rpccli_samr_Close(pipe_cli, ctx, &alias_handle);
234         }
235
236         if (ctx->disable_policy_handle_cache) {
237                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
238                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
239                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
240         }
241
242         return werr;
243 }
244
245 /****************************************************************
246 ****************************************************************/
247
248 WERROR NetLocalGroupAdd_l(struct libnetapi_ctx *ctx,
249                           struct NetLocalGroupAdd *r)
250 {
251         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupAdd);
252 }
253
254 /****************************************************************
255 ****************************************************************/
256
257
258 WERROR NetLocalGroupDel_r(struct libnetapi_ctx *ctx,
259                           struct NetLocalGroupDel *r)
260 {
261         struct rpc_pipe_client *pipe_cli = NULL;
262         NTSTATUS status;
263         WERROR werr;
264         struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
265         struct dom_sid2 *domain_sid = NULL;
266
267         if (!r->in.group_name) {
268                 return WERR_INVALID_PARAM;
269         }
270
271         ZERO_STRUCT(connect_handle);
272         ZERO_STRUCT(builtin_handle);
273         ZERO_STRUCT(domain_handle);
274         ZERO_STRUCT(alias_handle);
275
276         werr = libnetapi_open_pipe(ctx, r->in.server_name,
277                                    &ndr_table_samr.syntax_id,
278                                    &pipe_cli);
279         if (!W_ERROR_IS_OK(werr)) {
280                 goto done;
281         }
282
283         werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
284                                                   SAMR_ACCESS_LOOKUP_DOMAIN |
285                                                   SAMR_ACCESS_ENUM_DOMAINS,
286                                                   SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
287                                                   &connect_handle,
288                                                   &builtin_handle);
289         if (!W_ERROR_IS_OK(werr)) {
290                 goto done;
291         }
292
293         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
294                                                       &builtin_handle,
295                                                       r->in.group_name,
296                                                       SEC_STD_DELETE,
297                                                       &alias_handle);
298
299         if (ctx->disable_policy_handle_cache) {
300                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
301         }
302
303         if (NT_STATUS_IS_OK(status)) {
304                 goto delete_alias;
305         }
306
307         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
308                                           SAMR_ACCESS_ENUM_DOMAINS |
309                                           SAMR_ACCESS_LOOKUP_DOMAIN,
310                                           SAMR_DOMAIN_ACCESS_CREATE_ALIAS |
311                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
312                                           &connect_handle,
313                                           &domain_handle,
314                                           &domain_sid);
315         if (!W_ERROR_IS_OK(werr)) {
316                 goto done;
317         }
318
319         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
320                                                       &domain_handle,
321                                                       r->in.group_name,
322                                                       SEC_STD_DELETE,
323                                                       &alias_handle);
324
325         if (ctx->disable_policy_handle_cache) {
326                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
327         }
328
329         if (!NT_STATUS_IS_OK(status)) {
330                 werr = ntstatus_to_werror(status);
331                 goto done;
332         }
333
334
335  delete_alias:
336         status = rpccli_samr_DeleteDomAlias(pipe_cli, ctx,
337                                             &alias_handle);
338         if (!NT_STATUS_IS_OK(status)) {
339                 werr = ntstatus_to_werror(status);
340                 goto done;
341         }
342
343         ZERO_STRUCT(alias_handle);
344
345         werr = WERR_OK;
346
347  done:
348         if (is_valid_policy_hnd(&alias_handle)) {
349                 rpccli_samr_Close(pipe_cli, ctx, &alias_handle);
350         }
351
352         if (ctx->disable_policy_handle_cache) {
353                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
354                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
355                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
356         }
357
358         return werr;
359 }
360
361 /****************************************************************
362 ****************************************************************/
363
364 WERROR NetLocalGroupDel_l(struct libnetapi_ctx *ctx,
365                           struct NetLocalGroupDel *r)
366 {
367         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupDel);
368 }
369
370 /****************************************************************
371 ****************************************************************/
372
373 static WERROR map_alias_info_to_buffer(TALLOC_CTX *mem_ctx,
374                                        const char *alias_name,
375                                        struct samr_AliasInfoAll *info,
376                                        uint32_t level,
377                                        uint32_t *entries_read,
378                                        uint8_t **buffer)
379 {
380         struct LOCALGROUP_INFO_0 g0;
381         struct LOCALGROUP_INFO_1 g1;
382         struct LOCALGROUP_INFO_1002 g1002;
383
384         switch (level) {
385                 case 0:
386                         g0.lgrpi0_name          = talloc_strdup(mem_ctx, alias_name);
387                         W_ERROR_HAVE_NO_MEMORY(g0.lgrpi0_name);
388
389                         ADD_TO_ARRAY(mem_ctx, struct LOCALGROUP_INFO_0, g0,
390                                      (struct LOCALGROUP_INFO_0 **)buffer, entries_read);
391
392                         break;
393                 case 1:
394                         g1.lgrpi1_name          = talloc_strdup(mem_ctx, alias_name);
395                         g1.lgrpi1_comment       = talloc_strdup(mem_ctx, info->description.string);
396                         W_ERROR_HAVE_NO_MEMORY(g1.lgrpi1_name);
397
398                         ADD_TO_ARRAY(mem_ctx, struct LOCALGROUP_INFO_1, g1,
399                                      (struct LOCALGROUP_INFO_1 **)buffer, entries_read);
400
401                         break;
402                 case 1002:
403                         g1002.lgrpi1002_comment = talloc_strdup(mem_ctx, info->description.string);
404
405                         ADD_TO_ARRAY(mem_ctx, struct LOCALGROUP_INFO_1002, g1002,
406                                      (struct LOCALGROUP_INFO_1002 **)buffer, entries_read);
407
408                         break;
409                 default:
410                         return WERR_UNKNOWN_LEVEL;
411         }
412
413         return WERR_OK;
414 }
415
416 /****************************************************************
417 ****************************************************************/
418
419 WERROR NetLocalGroupGetInfo_r(struct libnetapi_ctx *ctx,
420                               struct NetLocalGroupGetInfo *r)
421 {
422         struct rpc_pipe_client *pipe_cli = NULL;
423         NTSTATUS status;
424         WERROR werr;
425         struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
426         struct dom_sid2 *domain_sid = NULL;
427         union samr_AliasInfo *alias_info = NULL;
428         uint32_t entries_read = 0;
429
430         if (!r->in.group_name) {
431                 return WERR_INVALID_PARAM;
432         }
433
434         switch (r->in.level) {
435                 case 0:
436                 case 1:
437                 case 1002:
438                         break;
439                 default:
440                         return WERR_UNKNOWN_LEVEL;
441         }
442
443         ZERO_STRUCT(connect_handle);
444         ZERO_STRUCT(builtin_handle);
445         ZERO_STRUCT(domain_handle);
446         ZERO_STRUCT(alias_handle);
447
448         werr = libnetapi_open_pipe(ctx, r->in.server_name,
449                                    &ndr_table_samr.syntax_id,
450                                    &pipe_cli);
451         if (!W_ERROR_IS_OK(werr)) {
452                 goto done;
453         }
454
455         werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
456                                                   SAMR_ACCESS_LOOKUP_DOMAIN |
457                                                   SAMR_ACCESS_ENUM_DOMAINS,
458                                                   SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
459                                                   &connect_handle,
460                                                   &builtin_handle);
461         if (!W_ERROR_IS_OK(werr)) {
462                 goto done;
463         }
464
465         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
466                                                       &builtin_handle,
467                                                       r->in.group_name,
468                                                       SAMR_ALIAS_ACCESS_LOOKUP_INFO,
469                                                       &alias_handle);
470
471         if (ctx->disable_policy_handle_cache) {
472                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
473         }
474
475         if (NT_STATUS_IS_OK(status)) {
476                 goto query_alias;
477         }
478
479         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
480                                           SAMR_ACCESS_ENUM_DOMAINS |
481                                           SAMR_ACCESS_LOOKUP_DOMAIN,
482                                           SAMR_DOMAIN_ACCESS_CREATE_ALIAS |
483                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
484                                           &connect_handle,
485                                           &domain_handle,
486                                           &domain_sid);
487         if (!W_ERROR_IS_OK(werr)) {
488                 goto done;
489         }
490
491         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
492                                                       &domain_handle,
493                                                       r->in.group_name,
494                                                       SAMR_ALIAS_ACCESS_LOOKUP_INFO,
495                                                       &alias_handle);
496
497         if (ctx->disable_policy_handle_cache) {
498                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
499         }
500
501         if (!NT_STATUS_IS_OK(status)) {
502                 werr = ntstatus_to_werror(status);
503                 goto done;
504         }
505
506  query_alias:
507         status = rpccli_samr_QueryAliasInfo(pipe_cli, ctx,
508                                             &alias_handle,
509                                             ALIASINFOALL,
510                                             &alias_info);
511         if (!NT_STATUS_IS_OK(status)) {
512                 werr = ntstatus_to_werror(status);
513                 goto done;
514         }
515
516         werr = map_alias_info_to_buffer(ctx,
517                                         r->in.group_name,
518                                         &alias_info->all,
519                                         r->in.level, &entries_read,
520                                         r->out.buffer);
521
522  done:
523         if (is_valid_policy_hnd(&alias_handle)) {
524                 rpccli_samr_Close(pipe_cli, ctx, &alias_handle);
525         }
526
527         if (ctx->disable_policy_handle_cache) {
528                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
529                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
530                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
531         }
532
533         return werr;
534 }
535
536 /****************************************************************
537 ****************************************************************/
538
539 WERROR NetLocalGroupGetInfo_l(struct libnetapi_ctx *ctx,
540                               struct NetLocalGroupGetInfo *r)
541 {
542         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupGetInfo);
543 }
544
545 /****************************************************************
546 ****************************************************************/
547
548 static WERROR map_buffer_to_alias_info(TALLOC_CTX *mem_ctx,
549                                        uint32_t level,
550                                        uint8_t *buffer,
551                                        enum samr_AliasInfoEnum *alias_level,
552                                        union samr_AliasInfo **alias_info)
553 {
554         struct LOCALGROUP_INFO_0 *info0;
555         struct LOCALGROUP_INFO_1 *info1;
556         struct LOCALGROUP_INFO_1002 *info1002;
557         union samr_AliasInfo *info = NULL;
558
559         info = TALLOC_ZERO_P(mem_ctx, union samr_AliasInfo);
560         W_ERROR_HAVE_NO_MEMORY(info);
561
562         switch (level) {
563                 case 0:
564                         info0 = (struct LOCALGROUP_INFO_0 *)buffer;
565                         init_lsa_String(&info->name, info0->lgrpi0_name);
566                         *alias_level = ALIASINFONAME;
567                         break;
568                 case 1:
569                         info1 = (struct LOCALGROUP_INFO_1 *)buffer;
570                         /* group name will be ignored */
571                         init_lsa_String(&info->description, info1->lgrpi1_comment);
572                         *alias_level = ALIASINFODESCRIPTION;
573                         break;
574                 case 1002:
575                         info1002 = (struct LOCALGROUP_INFO_1002 *)buffer;
576                         init_lsa_String(&info->description, info1002->lgrpi1002_comment);
577                         *alias_level = ALIASINFODESCRIPTION;
578                         break;
579         }
580
581         *alias_info = info;
582
583         return WERR_OK;
584 }
585
586 /****************************************************************
587 ****************************************************************/
588
589 WERROR NetLocalGroupSetInfo_r(struct libnetapi_ctx *ctx,
590                               struct NetLocalGroupSetInfo *r)
591 {
592         struct rpc_pipe_client *pipe_cli = NULL;
593         NTSTATUS status;
594         WERROR werr;
595         struct lsa_String lsa_account_name;
596         struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
597         struct dom_sid2 *domain_sid = NULL;
598         enum samr_AliasInfoEnum alias_level = 0;
599         union samr_AliasInfo *alias_info = NULL;
600
601         if (!r->in.group_name) {
602                 return WERR_INVALID_PARAM;
603         }
604
605         switch (r->in.level) {
606                 case 0:
607                 case 1:
608                 case 1002:
609                         break;
610                 default:
611                         return WERR_UNKNOWN_LEVEL;
612         }
613
614         ZERO_STRUCT(connect_handle);
615         ZERO_STRUCT(builtin_handle);
616         ZERO_STRUCT(domain_handle);
617         ZERO_STRUCT(alias_handle);
618
619         werr = libnetapi_open_pipe(ctx, r->in.server_name,
620                                    &ndr_table_samr.syntax_id,
621                                    &pipe_cli);
622         if (!W_ERROR_IS_OK(werr)) {
623                 goto done;
624         }
625
626         werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
627                                                   SAMR_ACCESS_LOOKUP_DOMAIN |
628                                                   SAMR_ACCESS_ENUM_DOMAINS,
629                                                   SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
630                                                   &connect_handle,
631                                                   &builtin_handle);
632         if (!W_ERROR_IS_OK(werr)) {
633                 goto done;
634         }
635
636         init_lsa_String(&lsa_account_name, r->in.group_name);
637
638         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
639                                                       &builtin_handle,
640                                                       r->in.group_name,
641                                                       SAMR_ALIAS_ACCESS_SET_INFO,
642                                                       &alias_handle);
643
644         if (ctx->disable_policy_handle_cache) {
645                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
646         }
647
648         if (NT_STATUS_IS_OK(status)) {
649                 goto set_alias;
650         }
651
652         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
653                                           SAMR_ACCESS_ENUM_DOMAINS |
654                                           SAMR_ACCESS_LOOKUP_DOMAIN,
655                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
656                                           &connect_handle,
657                                           &domain_handle,
658                                           &domain_sid);
659         if (!W_ERROR_IS_OK(werr)) {
660                 goto done;
661         }
662
663         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
664                                                       &domain_handle,
665                                                       r->in.group_name,
666                                                       SAMR_ALIAS_ACCESS_SET_INFO,
667                                                       &alias_handle);
668         if (!NT_STATUS_IS_OK(status)) {
669                 werr = ntstatus_to_werror(status);
670                 goto done;
671         }
672
673         if (ctx->disable_policy_handle_cache) {
674                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
675         }
676
677  set_alias:
678
679         werr = map_buffer_to_alias_info(ctx, r->in.level, r->in.buffer,
680                                         &alias_level, &alias_info);
681         if (!W_ERROR_IS_OK(werr)) {
682                 goto done;
683         }
684
685         status = rpccli_samr_SetAliasInfo(pipe_cli, ctx,
686                                           &alias_handle,
687                                           alias_level,
688                                           alias_info);
689         if (!NT_STATUS_IS_OK(status)) {
690                 werr = ntstatus_to_werror(status);
691                 goto done;
692         }
693
694         werr = WERR_OK;
695
696  done:
697         if (is_valid_policy_hnd(&alias_handle)) {
698                 rpccli_samr_Close(pipe_cli, ctx, &alias_handle);
699         }
700
701         if (ctx->disable_policy_handle_cache) {
702                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
703                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
704                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
705         }
706
707         return werr;
708 }
709
710 /****************************************************************
711 ****************************************************************/
712
713 WERROR NetLocalGroupSetInfo_l(struct libnetapi_ctx *ctx,
714                               struct NetLocalGroupSetInfo *r)
715 {
716         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupSetInfo);
717 }
718
719 /****************************************************************
720 ****************************************************************/
721
722 WERROR NetLocalGroupEnum_r(struct libnetapi_ctx *ctx,
723                            struct NetLocalGroupEnum *r)
724 {
725         struct rpc_pipe_client *pipe_cli = NULL;
726         NTSTATUS status;
727         WERROR werr;
728         struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
729         struct dom_sid2 *domain_sid = NULL;
730         uint32_t entries_read = 0;
731         union samr_DomainInfo *domain_info = NULL;
732         union samr_DomainInfo *builtin_info = NULL;
733         struct samr_SamArray *domain_sam_array = NULL;
734         struct samr_SamArray *builtin_sam_array = NULL;
735         int i;
736
737         if (!r->out.buffer) {
738                 return WERR_INVALID_PARAM;
739         }
740
741         switch (r->in.level) {
742                 case 0:
743                 case 1:
744                         break;
745                 default:
746                         return WERR_UNKNOWN_LEVEL;
747         }
748
749         if (r->out.total_entries) {
750                 *r->out.total_entries = 0;
751         }
752         if (r->out.entries_read) {
753                 *r->out.entries_read = 0;
754         }
755
756         ZERO_STRUCT(connect_handle);
757         ZERO_STRUCT(builtin_handle);
758         ZERO_STRUCT(domain_handle);
759         ZERO_STRUCT(alias_handle);
760
761         werr = libnetapi_open_pipe(ctx, r->in.server_name,
762                                    &ndr_table_samr.syntax_id,
763                                    &pipe_cli);
764         if (!W_ERROR_IS_OK(werr)) {
765                 goto done;
766         }
767
768         werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
769                                                   SAMR_ACCESS_LOOKUP_DOMAIN |
770                                                   SAMR_ACCESS_ENUM_DOMAINS,
771                                                   SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 |
772                                                   SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS |
773                                                   SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
774                                                   &connect_handle,
775                                                   &builtin_handle);
776         if (!W_ERROR_IS_OK(werr)) {
777                 goto done;
778         }
779
780         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
781                                           SAMR_ACCESS_LOOKUP_DOMAIN |
782                                           SAMR_ACCESS_ENUM_DOMAINS,
783                                           SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 |
784                                           SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS |
785                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
786                                           &connect_handle,
787                                           &domain_handle,
788                                           &domain_sid);
789         if (!W_ERROR_IS_OK(werr)) {
790                 goto done;
791         }
792
793         status = rpccli_samr_QueryDomainInfo(pipe_cli, ctx,
794                                              &builtin_handle,
795                                              2,
796                                              &builtin_info);
797         if (!NT_STATUS_IS_OK(status)) {
798                 werr = ntstatus_to_werror(status);
799                 goto done;
800         }
801
802         if (r->out.total_entries) {
803                 *r->out.total_entries += builtin_info->general.num_aliases;
804         }
805
806         status = rpccli_samr_QueryDomainInfo(pipe_cli, ctx,
807                                              &domain_handle,
808                                              2,
809                                              &domain_info);
810         if (!NT_STATUS_IS_OK(status)) {
811                 werr = ntstatus_to_werror(status);
812                 goto done;
813         }
814
815         if (r->out.total_entries) {
816                 *r->out.total_entries += domain_info->general.num_aliases;
817         }
818
819         status = rpccli_samr_EnumDomainAliases(pipe_cli, ctx,
820                                                &builtin_handle,
821                                                r->in.resume_handle,
822                                                &builtin_sam_array,
823                                                r->in.prefmaxlen,
824                                                &entries_read);
825         if (!NT_STATUS_IS_OK(status)) {
826                 werr = ntstatus_to_werror(status);
827                 goto done;
828         }
829
830         for (i=0; i<builtin_sam_array->count; i++) {
831                 union samr_AliasInfo *alias_info = NULL;
832
833                 if (r->in.level == 1) {
834
835                         status = libnetapi_samr_open_alias_queryinfo(ctx, pipe_cli,
836                                                                      &builtin_handle,
837                                                                      builtin_sam_array->entries[i].idx,
838                                                                      SAMR_ALIAS_ACCESS_LOOKUP_INFO,
839                                                                      ALIASINFOALL,
840                                                                      &alias_info);
841                         if (!NT_STATUS_IS_OK(status)) {
842                                 werr = ntstatus_to_werror(status);
843                                 goto done;
844                         }
845                 }
846
847                 werr = map_alias_info_to_buffer(ctx,
848                                                 builtin_sam_array->entries[i].name.string,
849                                                 alias_info ? &alias_info->all : NULL,
850                                                 r->in.level,
851                                                 r->out.entries_read,
852                                                 r->out.buffer);
853         }
854
855         status = rpccli_samr_EnumDomainAliases(pipe_cli, ctx,
856                                                &domain_handle,
857                                                r->in.resume_handle,
858                                                &domain_sam_array,
859                                                r->in.prefmaxlen,
860                                                &entries_read);
861         if (!NT_STATUS_IS_OK(status)) {
862                 werr = ntstatus_to_werror(status);
863                 goto done;
864         }
865
866         for (i=0; i<domain_sam_array->count; i++) {
867
868                 union samr_AliasInfo *alias_info = NULL;
869
870                 if (r->in.level == 1) {
871                         status = libnetapi_samr_open_alias_queryinfo(ctx, pipe_cli,
872                                                                      &domain_handle,
873                                                                      domain_sam_array->entries[i].idx,
874                                                                      SAMR_ALIAS_ACCESS_LOOKUP_INFO,
875                                                                      ALIASINFOALL,
876                                                                      &alias_info);
877                         if (!NT_STATUS_IS_OK(status)) {
878                                 werr = ntstatus_to_werror(status);
879                                 goto done;
880                         }
881                 }
882
883                 werr = map_alias_info_to_buffer(ctx,
884                                                 domain_sam_array->entries[i].name.string,
885                                                 alias_info ? &alias_info->all : NULL,
886                                                 r->in.level,
887                                                 r->out.entries_read,
888                                                 r->out.buffer);
889         }
890
891  done:
892         if (ctx->disable_policy_handle_cache) {
893                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
894                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
895                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
896         }
897
898         return werr;
899 }
900
901 /****************************************************************
902 ****************************************************************/
903
904 WERROR NetLocalGroupEnum_l(struct libnetapi_ctx *ctx,
905                            struct NetLocalGroupEnum *r)
906 {
907         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupEnum);
908 }
909
910 /****************************************************************
911 ****************************************************************/
912
913 static NTSTATUS libnetapi_lsa_lookup_names3(TALLOC_CTX *mem_ctx,
914                                             struct rpc_pipe_client *lsa_pipe,
915                                             const char *name,
916                                             struct dom_sid *sid)
917 {
918         NTSTATUS status;
919         struct policy_handle lsa_handle;
920
921         struct lsa_RefDomainList *domains = NULL;
922         struct lsa_TransSidArray3 sids;
923         uint32_t count = 0;
924
925         struct lsa_String names;
926         uint32_t num_names = 1;
927
928         if (!sid || !name) {
929                 return NT_STATUS_INVALID_PARAMETER;
930         }
931
932         ZERO_STRUCT(sids);
933
934         init_lsa_String(&names, name);
935
936         status = rpccli_lsa_open_policy2(lsa_pipe, mem_ctx,
937                                          false,
938                                          SEC_STD_READ_CONTROL |
939                                          LSA_POLICY_VIEW_LOCAL_INFORMATION |
940                                          LSA_POLICY_LOOKUP_NAMES,
941                                          &lsa_handle);
942         NT_STATUS_NOT_OK_RETURN(status);
943
944         status = rpccli_lsa_LookupNames3(lsa_pipe, mem_ctx,
945                                          &lsa_handle,
946                                          num_names,
947                                          &names,
948                                          &domains,
949                                          &sids,
950                                          LSA_LOOKUP_NAMES_ALL, /* sure ? */
951                                          &count,
952                                          0, 0);
953         NT_STATUS_NOT_OK_RETURN(status);
954
955         if (count != 1 || sids.count != 1) {
956                 return NT_STATUS_NONE_MAPPED;
957         }
958
959         sid_copy(sid, sids.sids[0].sid);
960
961         return NT_STATUS_OK;
962 }
963
964 /****************************************************************
965 ****************************************************************/
966
967 static WERROR NetLocalGroupModifyMembers_r(struct libnetapi_ctx *ctx,
968                                            struct NetLocalGroupAddMembers *add,
969                                            struct NetLocalGroupDelMembers *del,
970                                            struct NetLocalGroupSetMembers *set)
971 {
972         struct NetLocalGroupAddMembers *r = NULL;
973
974         struct rpc_pipe_client *pipe_cli = NULL;
975         struct rpc_pipe_client *lsa_pipe = NULL;
976         NTSTATUS status;
977         WERROR werr;
978         struct lsa_String lsa_account_name;
979         struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
980         struct dom_sid2 *domain_sid = NULL;
981         struct dom_sid *member_sids = NULL;
982         int i = 0, k = 0;
983
984         struct LOCALGROUP_MEMBERS_INFO_0 *info0 = NULL;
985         struct LOCALGROUP_MEMBERS_INFO_3 *info3 = NULL;
986
987         struct dom_sid *add_sids = NULL;
988         struct dom_sid *del_sids = NULL;
989         size_t num_add_sids = 0;
990         size_t num_del_sids = 0;
991
992         if ((!add && !del && !set) || (add && del && set)) {
993                 return WERR_INVALID_PARAM;
994         }
995
996         if (add) {
997                 r = add;
998         }
999
1000         if (del) {
1001                 r = (struct NetLocalGroupAddMembers *)del;
1002         }
1003
1004         if (set) {
1005                 r = (struct NetLocalGroupAddMembers *)set;
1006         }
1007
1008         if (!r->in.group_name) {
1009                 return WERR_INVALID_PARAM;
1010         }
1011
1012         switch (r->in.level) {
1013                 case 0:
1014                 case 3:
1015                         break;
1016                 default:
1017                         return WERR_UNKNOWN_LEVEL;
1018         }
1019
1020         if (r->in.total_entries == 0 || !r->in.buffer) {
1021                 return WERR_INVALID_PARAM;
1022         }
1023
1024         ZERO_STRUCT(connect_handle);
1025         ZERO_STRUCT(builtin_handle);
1026         ZERO_STRUCT(domain_handle);
1027         ZERO_STRUCT(alias_handle);
1028
1029         member_sids = TALLOC_ZERO_ARRAY(ctx, struct dom_sid,
1030                                         r->in.total_entries);
1031         W_ERROR_HAVE_NO_MEMORY(member_sids);
1032
1033         switch (r->in.level) {
1034                 case 0:
1035                         info0 = (struct LOCALGROUP_MEMBERS_INFO_0 *)r->in.buffer;
1036                         for (i=0; i < r->in.total_entries; i++) {
1037                                 sid_copy(&member_sids[i], (struct dom_sid *)info0[i].lgrmi0_sid);
1038                         }
1039                         break;
1040                 case 3:
1041                         info3 = (struct LOCALGROUP_MEMBERS_INFO_3 *)r->in.buffer;
1042                         break;
1043                 default:
1044                         break;
1045         }
1046
1047         if (r->in.level == 3) {
1048                 werr = libnetapi_open_pipe(ctx, r->in.server_name,
1049                                            &ndr_table_lsarpc.syntax_id,
1050                                            &lsa_pipe);
1051                 if (!W_ERROR_IS_OK(werr)) {
1052                         goto done;
1053                 }
1054
1055                 for (i=0; i < r->in.total_entries; i++) {
1056                         status = libnetapi_lsa_lookup_names3(ctx, lsa_pipe,
1057                                                              info3[i].lgrmi3_domainandname,
1058                                                              &member_sids[i]);
1059                         if (!NT_STATUS_IS_OK(status)) {
1060                                 werr = ntstatus_to_werror(status);
1061                                 goto done;
1062                         }
1063                 }
1064                 TALLOC_FREE(lsa_pipe);
1065         }
1066
1067         werr = libnetapi_open_pipe(ctx, r->in.server_name,
1068                                    &ndr_table_samr.syntax_id,
1069                                    &pipe_cli);
1070         if (!W_ERROR_IS_OK(werr)) {
1071                 goto done;
1072         }
1073
1074         werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
1075                                                   SAMR_ACCESS_LOOKUP_DOMAIN |
1076                                                   SAMR_ACCESS_ENUM_DOMAINS,
1077                                                   SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1078                                                   &connect_handle,
1079                                                   &builtin_handle);
1080         if (!W_ERROR_IS_OK(werr)) {
1081                 goto done;
1082         }
1083
1084         init_lsa_String(&lsa_account_name, r->in.group_name);
1085
1086         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
1087                                                       &builtin_handle,
1088                                                       r->in.group_name,
1089                                                       SAMR_ALIAS_ACCESS_ADD_MEMBER |
1090                                                       SAMR_ALIAS_ACCESS_REMOVE_MEMBER |
1091                                                       SAMR_ALIAS_ACCESS_GET_MEMBERS |
1092                                                       SAMR_ALIAS_ACCESS_LOOKUP_INFO,
1093                                                       &alias_handle);
1094
1095         if (ctx->disable_policy_handle_cache) {
1096                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
1097         }
1098
1099         if (NT_STATUS_IS_OK(status)) {
1100                 goto modify_membership;
1101         }
1102
1103         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
1104                                           SAMR_ACCESS_ENUM_DOMAINS |
1105                                           SAMR_ACCESS_LOOKUP_DOMAIN,
1106                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1107                                           &connect_handle,
1108                                           &domain_handle,
1109                                           &domain_sid);
1110         if (!W_ERROR_IS_OK(werr)) {
1111                 goto done;
1112         }
1113
1114         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
1115                                                       &domain_handle,
1116                                                       r->in.group_name,
1117                                                       SAMR_ALIAS_ACCESS_ADD_MEMBER |
1118                                                       SAMR_ALIAS_ACCESS_REMOVE_MEMBER |
1119                                                       SAMR_ALIAS_ACCESS_GET_MEMBERS |
1120                                                       SAMR_ALIAS_ACCESS_LOOKUP_INFO,
1121                                                       &alias_handle);
1122         if (!NT_STATUS_IS_OK(status)) {
1123                 werr = ntstatus_to_werror(status);
1124                 goto done;
1125         }
1126
1127         if (ctx->disable_policy_handle_cache) {
1128                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
1129         }
1130
1131  modify_membership:
1132
1133         if (add) {
1134                 for (i=0; i < r->in.total_entries; i++) {
1135                         status = add_sid_to_array_unique(ctx, &member_sids[i],
1136                                                          &add_sids,
1137                                                          &num_add_sids);
1138                         if (!NT_STATUS_IS_OK(status)) {
1139                                 werr = ntstatus_to_werror(status);
1140                                 goto done;
1141                         }
1142                 }
1143         }
1144
1145         if (del) {
1146                 for (i=0; i < r->in.total_entries; i++) {
1147                         status = add_sid_to_array_unique(ctx, &member_sids[i],
1148                                                          &del_sids,
1149                                                          &num_del_sids);
1150                         if (!NT_STATUS_IS_OK(status)) {
1151                                 werr = ntstatus_to_werror(status);
1152                                 goto done;
1153                         }
1154                 }
1155         }
1156
1157         if (set) {
1158
1159                 struct lsa_SidArray current_sids;
1160
1161                 status = rpccli_samr_GetMembersInAlias(pipe_cli, ctx,
1162                                                        &alias_handle,
1163                                                        &current_sids);
1164                 if (!NT_STATUS_IS_OK(status)) {
1165                         werr = ntstatus_to_werror(status);
1166                         goto done;
1167                 }
1168
1169                 /* add list */
1170
1171                 for (i=0; i < r->in.total_entries; i++) {
1172                         bool already_member = false;
1173                         for (k=0; k < current_sids.num_sids; k++) {
1174                                 if (sid_equal(&member_sids[i],
1175                                               current_sids.sids[k].sid)) {
1176                                         already_member = true;
1177                                         break;
1178                                 }
1179                         }
1180                         if (!already_member) {
1181                                 status = add_sid_to_array_unique(ctx,
1182                                         &member_sids[i],
1183                                         &add_sids, &num_add_sids);
1184                                 if (!NT_STATUS_IS_OK(status)) {
1185                                         werr = ntstatus_to_werror(status);
1186                                         goto done;
1187                                 }
1188                         }
1189                 }
1190
1191                 /* del list */
1192
1193                 for (k=0; k < current_sids.num_sids; k++) {
1194                         bool keep_member = false;
1195                         for (i=0; i < r->in.total_entries; i++) {
1196                                 if (sid_equal(&member_sids[i],
1197                                               current_sids.sids[k].sid)) {
1198                                         keep_member = true;
1199                                         break;
1200                                 }
1201                         }
1202                         if (!keep_member) {
1203                                 status = add_sid_to_array_unique(ctx,
1204                                                 current_sids.sids[k].sid,
1205                                                 &del_sids, &num_del_sids);
1206                                 if (!NT_STATUS_IS_OK(status)) {
1207                                         werr = ntstatus_to_werror(status);
1208                                         goto done;
1209                                 }
1210                         }
1211                 }
1212         }
1213
1214         /* add list */
1215
1216         for (i=0; i < num_add_sids; i++) {
1217                 status = rpccli_samr_AddAliasMember(pipe_cli, ctx,
1218                                                     &alias_handle,
1219                                                     &add_sids[i]);
1220                 if (!NT_STATUS_IS_OK(status)) {
1221                         werr = ntstatus_to_werror(status);
1222                         goto done;
1223                 }
1224         }
1225
1226         /* del list */
1227
1228         for (i=0; i < num_del_sids; i++) {
1229                 status = rpccli_samr_DeleteAliasMember(pipe_cli, ctx,
1230                                                        &alias_handle,
1231                                                        &del_sids[i]);
1232                 if (!NT_STATUS_IS_OK(status)) {
1233                         werr = ntstatus_to_werror(status);
1234                         goto done;
1235                 }
1236         }
1237
1238         werr = WERR_OK;
1239
1240  done:
1241         if (is_valid_policy_hnd(&alias_handle)) {
1242                 rpccli_samr_Close(pipe_cli, ctx, &alias_handle);
1243         }
1244
1245         if (ctx->disable_policy_handle_cache) {
1246                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
1247                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
1248                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
1249         }
1250
1251         return werr;
1252 }
1253
1254 /****************************************************************
1255 ****************************************************************/
1256
1257 WERROR NetLocalGroupAddMembers_r(struct libnetapi_ctx *ctx,
1258                                  struct NetLocalGroupAddMembers *r)
1259 {
1260         return NetLocalGroupModifyMembers_r(ctx, r, NULL, NULL);
1261 }
1262
1263 /****************************************************************
1264 ****************************************************************/
1265
1266 WERROR NetLocalGroupAddMembers_l(struct libnetapi_ctx *ctx,
1267                                  struct NetLocalGroupAddMembers *r)
1268 {
1269         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupAddMembers);
1270 }
1271
1272 /****************************************************************
1273 ****************************************************************/
1274
1275 WERROR NetLocalGroupDelMembers_r(struct libnetapi_ctx *ctx,
1276                                  struct NetLocalGroupDelMembers *r)
1277 {
1278         return NetLocalGroupModifyMembers_r(ctx, NULL, r, NULL);
1279 }
1280
1281 /****************************************************************
1282 ****************************************************************/
1283
1284 WERROR NetLocalGroupDelMembers_l(struct libnetapi_ctx *ctx,
1285                                  struct NetLocalGroupDelMembers *r)
1286 {
1287         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupDelMembers);
1288 }
1289
1290 /****************************************************************
1291 ****************************************************************/
1292
1293 WERROR NetLocalGroupGetMembers_r(struct libnetapi_ctx *ctx,
1294                                  struct NetLocalGroupGetMembers *r)
1295 {
1296         return WERR_NOT_SUPPORTED;
1297 }
1298
1299 /****************************************************************
1300 ****************************************************************/
1301
1302 WERROR NetLocalGroupGetMembers_l(struct libnetapi_ctx *ctx,
1303                                  struct NetLocalGroupGetMembers *r)
1304 {
1305         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupGetMembers);
1306 }
1307
1308 /****************************************************************
1309 ****************************************************************/
1310
1311 WERROR NetLocalGroupSetMembers_r(struct libnetapi_ctx *ctx,
1312                                  struct NetLocalGroupSetMembers *r)
1313 {
1314         return NetLocalGroupModifyMembers_r(ctx, NULL, NULL, r);
1315 }
1316
1317 /****************************************************************
1318 ****************************************************************/
1319
1320 WERROR NetLocalGroupSetMembers_l(struct libnetapi_ctx *ctx,
1321                                  struct NetLocalGroupSetMembers *r)
1322 {
1323         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupSetMembers);
1324 }