Merge branch 'v4-0-stable' into newmaster
[mat/samba.git] / source3 / lib / netapi / group.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  NetApi Group 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 "rpc_client/init_lsa.h"
28 #include "../libcli/security/dom_sid.h"
29
30 /****************************************************************
31 ****************************************************************/
32
33 WERROR NetGroupAdd_r(struct libnetapi_ctx *ctx,
34                      struct NetGroupAdd *r)
35 {
36         struct rpc_pipe_client *pipe_cli = NULL;
37         NTSTATUS status;
38         WERROR werr;
39         struct policy_handle connect_handle, domain_handle, group_handle;
40         struct lsa_String lsa_group_name;
41         struct dom_sid2 *domain_sid = NULL;
42         uint32_t rid = 0;
43
44         struct GROUP_INFO_0 *info0 = NULL;
45         struct GROUP_INFO_1 *info1 = NULL;
46         struct GROUP_INFO_2 *info2 = NULL;
47         struct GROUP_INFO_3 *info3 = NULL;
48         union samr_GroupInfo info;
49
50         ZERO_STRUCT(connect_handle);
51         ZERO_STRUCT(domain_handle);
52         ZERO_STRUCT(group_handle);
53
54         if (!r->in.buffer) {
55                 return WERR_INVALID_PARAM;
56         }
57
58         switch (r->in.level) {
59                 case 0:
60                         info0 = (struct GROUP_INFO_0 *)r->in.buffer;
61                         break;
62                 case 1:
63                         info1 = (struct GROUP_INFO_1 *)r->in.buffer;
64                         break;
65                 case 2:
66                         info2 = (struct GROUP_INFO_2 *)r->in.buffer;
67                         break;
68                 case 3:
69                         info3 = (struct GROUP_INFO_3 *)r->in.buffer;
70                         break;
71                 default:
72                         werr = WERR_UNKNOWN_LEVEL;
73                         goto done;
74         }
75
76         werr = libnetapi_open_pipe(ctx, r->in.server_name,
77                                    &ndr_table_samr.syntax_id,
78                                    &pipe_cli);
79         if (!W_ERROR_IS_OK(werr)) {
80                 goto done;
81         }
82
83         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
84                                           SAMR_ACCESS_ENUM_DOMAINS |
85                                           SAMR_ACCESS_LOOKUP_DOMAIN,
86                                           SAMR_DOMAIN_ACCESS_CREATE_GROUP |
87                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
88                                           &connect_handle,
89                                           &domain_handle,
90                                           &domain_sid);
91         if (!W_ERROR_IS_OK(werr)) {
92                 goto done;
93         }
94
95         switch (r->in.level) {
96                 case 0:
97                         init_lsa_String(&lsa_group_name, info0->grpi0_name);
98                         break;
99                 case 1:
100                         init_lsa_String(&lsa_group_name, info1->grpi1_name);
101                         break;
102                 case 2:
103                         init_lsa_String(&lsa_group_name, info2->grpi2_name);
104                         break;
105                 case 3:
106                         init_lsa_String(&lsa_group_name, info3->grpi3_name);
107                         break;
108         }
109
110         status = rpccli_samr_CreateDomainGroup(pipe_cli, ctx,
111                                                &domain_handle,
112                                                &lsa_group_name,
113                                                SEC_STD_DELETE |
114                                                SAMR_GROUP_ACCESS_SET_INFO,
115                                                &group_handle,
116                                                &rid);
117
118         if (!NT_STATUS_IS_OK(status)) {
119                 werr = ntstatus_to_werror(status);
120                 goto done;
121         }
122
123         switch (r->in.level) {
124                 case 1:
125                         if (info1->grpi1_comment) {
126                                 init_lsa_String(&info.description,
127                                                 info1->grpi1_comment);
128
129                                 status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
130                                                                   &group_handle,
131                                                                   GROUPINFODESCRIPTION,
132                                                                   &info);
133                         }
134                         break;
135                 case 2:
136                         if (info2->grpi2_comment) {
137                                 init_lsa_String(&info.description,
138                                                 info2->grpi2_comment);
139
140                                 status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
141                                                                   &group_handle,
142                                                                   GROUPINFODESCRIPTION,
143                                                                   &info);
144                                 if (!NT_STATUS_IS_OK(status)) {
145                                         werr = ntstatus_to_werror(status);
146                                         goto failed;
147                                 }
148                         }
149
150                         if (info2->grpi2_attributes != 0) {
151                                 info.attributes.attributes = info2->grpi2_attributes;
152                                 status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
153                                                                   &group_handle,
154                                                                   GROUPINFOATTRIBUTES,
155                                                                   &info);
156
157                         }
158                         break;
159                 case 3:
160                         if (info3->grpi3_comment) {
161                                 init_lsa_String(&info.description,
162                                                 info3->grpi3_comment);
163
164                                 status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
165                                                                   &group_handle,
166                                                                   GROUPINFODESCRIPTION,
167                                                                   &info);
168                                 if (!NT_STATUS_IS_OK(status)) {
169                                         werr = ntstatus_to_werror(status);
170                                         goto failed;
171                                 }
172                         }
173
174                         if (info3->grpi3_attributes != 0) {
175                                 info.attributes.attributes = info3->grpi3_attributes;
176                                 status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
177                                                                   &group_handle,
178                                                                   GROUPINFOATTRIBUTES,
179                                                                   &info);
180                         }
181                         break;
182                 default:
183                         break;
184         }
185
186         if (!NT_STATUS_IS_OK(status)) {
187                 werr = ntstatus_to_werror(status);
188                 goto failed;
189         }
190
191         werr = WERR_OK;
192         goto done;
193
194  failed:
195         rpccli_samr_DeleteDomainGroup(pipe_cli, ctx,
196                                       &group_handle);
197
198  done:
199         if (is_valid_policy_hnd(&group_handle)) {
200                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
201         }
202
203         if (ctx->disable_policy_handle_cache) {
204                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
205                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
206         }
207
208         return werr;
209 }
210
211 /****************************************************************
212 ****************************************************************/
213
214 WERROR NetGroupAdd_l(struct libnetapi_ctx *ctx,
215                      struct NetGroupAdd *r)
216 {
217         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupAdd);
218 }
219
220 /****************************************************************
221 ****************************************************************/
222
223 WERROR NetGroupDel_r(struct libnetapi_ctx *ctx,
224                      struct NetGroupDel *r)
225 {
226         struct rpc_pipe_client *pipe_cli = NULL;
227         NTSTATUS status;
228         WERROR werr;
229         struct policy_handle connect_handle, domain_handle, group_handle;
230         struct lsa_String lsa_group_name;
231         struct dom_sid2 *domain_sid = NULL;
232         int i = 0;
233
234         struct samr_Ids rids;
235         struct samr_Ids types;
236         union samr_GroupInfo *info = NULL;
237         struct samr_RidTypeArray *rid_array = NULL;
238
239         ZERO_STRUCT(connect_handle);
240         ZERO_STRUCT(domain_handle);
241         ZERO_STRUCT(group_handle);
242
243         if (!r->in.group_name) {
244                 return WERR_INVALID_PARAM;
245         }
246
247         werr = libnetapi_open_pipe(ctx, r->in.server_name,
248                                    &ndr_table_samr.syntax_id,
249                                    &pipe_cli);
250         if (!W_ERROR_IS_OK(werr)) {
251                 goto done;
252         }
253
254         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
255                                           SAMR_ACCESS_ENUM_DOMAINS |
256                                           SAMR_ACCESS_LOOKUP_DOMAIN,
257                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
258                                           &connect_handle,
259                                           &domain_handle,
260                                           &domain_sid);
261         if (!W_ERROR_IS_OK(werr)) {
262                 goto done;
263         }
264
265         init_lsa_String(&lsa_group_name, r->in.group_name);
266
267         status = rpccli_samr_LookupNames(pipe_cli, ctx,
268                                          &domain_handle,
269                                          1,
270                                          &lsa_group_name,
271                                          &rids,
272                                          &types);
273         if (!NT_STATUS_IS_OK(status)) {
274                 werr = ntstatus_to_werror(status);
275                 goto done;
276         }
277
278         if (types.ids[0] != SID_NAME_DOM_GRP) {
279                 werr = WERR_INVALID_DATATYPE;
280                 goto done;
281         }
282
283         status = rpccli_samr_OpenGroup(pipe_cli, ctx,
284                                        &domain_handle,
285                                        SEC_STD_DELETE |
286                                        SAMR_GROUP_ACCESS_GET_MEMBERS |
287                                        SAMR_GROUP_ACCESS_REMOVE_MEMBER |
288                                        SAMR_GROUP_ACCESS_ADD_MEMBER |
289                                        SAMR_GROUP_ACCESS_LOOKUP_INFO,
290                                        rids.ids[0],
291                                        &group_handle);
292         if (!NT_STATUS_IS_OK(status)) {
293                 werr = ntstatus_to_werror(status);
294                 goto done;
295         }
296
297         status = rpccli_samr_QueryGroupInfo(pipe_cli, ctx,
298                                             &group_handle,
299                                             GROUPINFOATTRIBUTES,
300                                             &info);
301         if (!NT_STATUS_IS_OK(status)) {
302                 werr = ntstatus_to_werror(status);
303                 goto done;
304         }
305
306 #if 0
307         /* breaks against NT4 */
308         if (!(info->attributes.attributes & SE_GROUP_ENABLED)) {
309                 werr = WERR_ACCESS_DENIED;
310                 goto done;
311         }
312 #endif
313         status = rpccli_samr_QueryGroupMember(pipe_cli, ctx,
314                                               &group_handle,
315                                               &rid_array);
316         if (!NT_STATUS_IS_OK(status)) {
317                 werr = ntstatus_to_werror(status);
318                 goto done;
319         }
320
321         {
322         struct lsa_Strings names;
323         struct samr_Ids member_types;
324
325         status = rpccli_samr_LookupRids(pipe_cli, ctx,
326                                         &domain_handle,
327                                         rid_array->count,
328                                         rid_array->rids,
329                                         &names,
330                                         &member_types);
331         if (!NT_STATUS_IS_OK(status)) {
332                 werr = ntstatus_to_werror(status);
333                 goto done;
334         }
335         }
336
337         for (i=0; i < rid_array->count; i++) {
338
339                 status = rpccli_samr_DeleteGroupMember(pipe_cli, ctx,
340                                                        &group_handle,
341                                                        rid_array->rids[i]);
342                 if (!NT_STATUS_IS_OK(status)) {
343                         werr = ntstatus_to_werror(status);
344                         goto done;
345                 }
346         }
347
348         status = rpccli_samr_DeleteDomainGroup(pipe_cli, ctx,
349                                                &group_handle);
350         if (!NT_STATUS_IS_OK(status)) {
351                 werr = ntstatus_to_werror(status);
352                 goto done;
353         }
354
355         ZERO_STRUCT(group_handle);
356
357         werr = WERR_OK;
358
359  done:
360         if (is_valid_policy_hnd(&group_handle)) {
361                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
362         }
363
364         if (ctx->disable_policy_handle_cache) {
365                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
366                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
367         }
368
369         return werr;
370 }
371
372 /****************************************************************
373 ****************************************************************/
374
375 WERROR NetGroupDel_l(struct libnetapi_ctx *ctx,
376                      struct NetGroupDel *r)
377 {
378         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupDel);
379 }
380
381 /****************************************************************
382 ****************************************************************/
383
384 WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
385                          struct NetGroupSetInfo *r)
386 {
387         struct rpc_pipe_client *pipe_cli = NULL;
388         NTSTATUS status;
389         WERROR werr;
390         struct policy_handle connect_handle, domain_handle, group_handle;
391         struct lsa_String lsa_group_name;
392         struct dom_sid2 *domain_sid = NULL;
393
394         struct samr_Ids rids;
395         struct samr_Ids types;
396         union samr_GroupInfo info;
397         struct GROUP_INFO_0 *g0;
398         struct GROUP_INFO_1 *g1;
399         struct GROUP_INFO_2 *g2;
400         struct GROUP_INFO_3 *g3;
401         struct GROUP_INFO_1002 *g1002;
402         struct GROUP_INFO_1005 *g1005;
403
404         ZERO_STRUCT(connect_handle);
405         ZERO_STRUCT(domain_handle);
406         ZERO_STRUCT(group_handle);
407
408         if (!r->in.group_name) {
409                 return WERR_INVALID_PARAM;
410         }
411
412         werr = libnetapi_open_pipe(ctx, r->in.server_name,
413                                    &ndr_table_samr.syntax_id,
414                                    &pipe_cli);
415         if (!W_ERROR_IS_OK(werr)) {
416                 goto done;
417         }
418
419         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
420                                           SAMR_ACCESS_ENUM_DOMAINS |
421                                           SAMR_ACCESS_LOOKUP_DOMAIN,
422                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
423                                           &connect_handle,
424                                           &domain_handle,
425                                           &domain_sid);
426         if (!W_ERROR_IS_OK(werr)) {
427                 goto done;
428         }
429
430         init_lsa_String(&lsa_group_name, r->in.group_name);
431
432         status = rpccli_samr_LookupNames(pipe_cli, ctx,
433                                          &domain_handle,
434                                          1,
435                                          &lsa_group_name,
436                                          &rids,
437                                          &types);
438         if (!NT_STATUS_IS_OK(status)) {
439                 werr = ntstatus_to_werror(status);
440                 goto done;
441         }
442
443         if (types.ids[0] != SID_NAME_DOM_GRP) {
444                 werr = WERR_INVALID_DATATYPE;
445                 goto done;
446         }
447
448         status = rpccli_samr_OpenGroup(pipe_cli, ctx,
449                                        &domain_handle,
450                                        SAMR_GROUP_ACCESS_SET_INFO |
451                                        SAMR_GROUP_ACCESS_LOOKUP_INFO,
452                                        rids.ids[0],
453                                        &group_handle);
454         if (!NT_STATUS_IS_OK(status)) {
455                 werr = ntstatus_to_werror(status);
456                 goto done;
457         }
458
459         switch (r->in.level) {
460                 case 0:
461                         g0 = (struct GROUP_INFO_0 *)r->in.buffer;
462                         init_lsa_String(&info.name, g0->grpi0_name);
463                         status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
464                                                           &group_handle,
465                                                           GROUPINFONAME,
466                                                           &info);
467                         break;
468                 case 1:
469                         g1 = (struct GROUP_INFO_1 *)r->in.buffer;
470                         init_lsa_String(&info.description, g1->grpi1_comment);
471                         status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
472                                                           &group_handle,
473                                                           GROUPINFODESCRIPTION,
474                                                           &info);
475                         break;
476                 case 2:
477                         g2 = (struct GROUP_INFO_2 *)r->in.buffer;
478                         init_lsa_String(&info.description, g2->grpi2_comment);
479                         status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
480                                                           &group_handle,
481                                                           GROUPINFODESCRIPTION,
482                                                           &info);
483                         if (!NT_STATUS_IS_OK(status)) {
484                                 werr = ntstatus_to_werror(status);
485                                 goto done;
486                         }
487                         info.attributes.attributes = g2->grpi2_attributes;
488                         status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
489                                                           &group_handle,
490                                                           GROUPINFOATTRIBUTES,
491                                                           &info);
492                         break;
493                 case 3:
494                         g3 = (struct GROUP_INFO_3 *)r->in.buffer;
495                         init_lsa_String(&info.description, g3->grpi3_comment);
496                         status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
497                                                           &group_handle,
498                                                           GROUPINFODESCRIPTION,
499                                                           &info);
500                         if (!NT_STATUS_IS_OK(status)) {
501                                 werr = ntstatus_to_werror(status);
502                                 goto done;
503                         }
504                         info.attributes.attributes = g3->grpi3_attributes;
505                         status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
506                                                           &group_handle,
507                                                           GROUPINFOATTRIBUTES,
508                                                           &info);
509                         break;
510                 case 1002:
511                         g1002 = (struct GROUP_INFO_1002 *)r->in.buffer;
512                         init_lsa_String(&info.description, g1002->grpi1002_comment);
513                         status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
514                                                           &group_handle,
515                                                           GROUPINFODESCRIPTION,
516                                                           &info);
517                         break;
518                 case 1005:
519                         g1005 = (struct GROUP_INFO_1005 *)r->in.buffer;
520                         info.attributes.attributes = g1005->grpi1005_attributes;
521                         status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
522                                                           &group_handle,
523                                                           GROUPINFOATTRIBUTES,
524                                                           &info);
525                         break;
526                 default:
527                         status = NT_STATUS_INVALID_LEVEL;
528                         break;
529         }
530
531         if (!NT_STATUS_IS_OK(status)) {
532                 werr = ntstatus_to_werror(status);
533                 goto done;
534         }
535
536         werr = WERR_OK;
537
538  done:
539         if (is_valid_policy_hnd(&group_handle)) {
540                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
541         }
542
543         if (ctx->disable_policy_handle_cache) {
544                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
545                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
546         }
547
548         return werr;
549 }
550
551 /****************************************************************
552 ****************************************************************/
553
554 WERROR NetGroupSetInfo_l(struct libnetapi_ctx *ctx,
555                          struct NetGroupSetInfo *r)
556 {
557         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupSetInfo);
558 }
559
560 /****************************************************************
561 ****************************************************************/
562
563 static WERROR map_group_info_to_buffer(TALLOC_CTX *mem_ctx,
564                                        uint32_t level,
565                                        struct samr_GroupInfoAll *info,
566                                        struct dom_sid2 *domain_sid,
567                                        uint32_t rid,
568                                        uint8_t **buffer)
569 {
570         struct GROUP_INFO_0 info0;
571         struct GROUP_INFO_1 info1;
572         struct GROUP_INFO_2 info2;
573         struct GROUP_INFO_3 info3;
574         struct dom_sid sid;
575
576         switch (level) {
577                 case 0:
578                         info0.grpi0_name        = info->name.string;
579
580                         *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info0, sizeof(info0));
581
582                         break;
583                 case 1:
584                         info1.grpi1_name        = info->name.string;
585                         info1.grpi1_comment     = info->description.string;
586
587                         *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info1, sizeof(info1));
588
589                         break;
590                 case 2:
591                         info2.grpi2_name        = info->name.string;
592                         info2.grpi2_comment     = info->description.string;
593                         info2.grpi2_group_id    = rid;
594                         info2.grpi2_attributes  = info->attributes;
595
596                         *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info2, sizeof(info2));
597
598                         break;
599                 case 3:
600                         if (!sid_compose(&sid, domain_sid, rid)) {
601                                 return WERR_NOMEM;
602                         }
603
604                         info3.grpi3_name        = info->name.string;
605                         info3.grpi3_comment     = info->description.string;
606                         info3.grpi3_attributes  = info->attributes;
607                         info3.grpi3_group_sid   = (struct domsid *)dom_sid_dup(mem_ctx, &sid);
608
609                         *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info3, sizeof(info3));
610
611                         break;
612                 default:
613                         return WERR_UNKNOWN_LEVEL;
614         }
615
616         W_ERROR_HAVE_NO_MEMORY(*buffer);
617
618         return WERR_OK;
619 }
620
621 /****************************************************************
622 ****************************************************************/
623
624 WERROR NetGroupGetInfo_r(struct libnetapi_ctx *ctx,
625                          struct NetGroupGetInfo *r)
626 {
627         struct rpc_pipe_client *pipe_cli = NULL;
628         NTSTATUS status;
629         WERROR werr;
630         struct policy_handle connect_handle, domain_handle, group_handle;
631         struct lsa_String lsa_group_name;
632         struct dom_sid2 *domain_sid = NULL;
633
634         struct samr_Ids rids;
635         struct samr_Ids types;
636         union samr_GroupInfo *info = NULL;
637         bool group_info_all = false;
638
639         ZERO_STRUCT(connect_handle);
640         ZERO_STRUCT(domain_handle);
641         ZERO_STRUCT(group_handle);
642
643         if (!r->in.group_name) {
644                 return WERR_INVALID_PARAM;
645         }
646
647         werr = libnetapi_open_pipe(ctx, r->in.server_name,
648                                    &ndr_table_samr.syntax_id,
649                                    &pipe_cli);
650         if (!W_ERROR_IS_OK(werr)) {
651                 goto done;
652         }
653
654         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
655                                           SAMR_ACCESS_ENUM_DOMAINS |
656                                           SAMR_ACCESS_LOOKUP_DOMAIN,
657                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
658                                           &connect_handle,
659                                           &domain_handle,
660                                           &domain_sid);
661         if (!W_ERROR_IS_OK(werr)) {
662                 goto done;
663         }
664
665         init_lsa_String(&lsa_group_name, r->in.group_name);
666
667         status = rpccli_samr_LookupNames(pipe_cli, ctx,
668                                          &domain_handle,
669                                          1,
670                                          &lsa_group_name,
671                                          &rids,
672                                          &types);
673         if (!NT_STATUS_IS_OK(status)) {
674                 werr = ntstatus_to_werror(status);
675                 goto done;
676         }
677
678         if (types.ids[0] != SID_NAME_DOM_GRP) {
679                 werr = WERR_INVALID_DATATYPE;
680                 goto done;
681         }
682
683         status = rpccli_samr_OpenGroup(pipe_cli, ctx,
684                                        &domain_handle,
685                                        SAMR_GROUP_ACCESS_LOOKUP_INFO,
686                                        rids.ids[0],
687                                        &group_handle);
688         if (!NT_STATUS_IS_OK(status)) {
689                 werr = ntstatus_to_werror(status);
690                 goto done;
691         }
692
693         status = rpccli_samr_QueryGroupInfo(pipe_cli, ctx,
694                                             &group_handle,
695                                             GROUPINFOALL2,
696                                             &info);
697         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
698                 status = rpccli_samr_QueryGroupInfo(pipe_cli, ctx,
699                                                     &group_handle,
700                                                     GROUPINFOALL,
701                                                     &info);
702                 group_info_all = true;
703         }
704
705         if (!NT_STATUS_IS_OK(status)) {
706                 werr = ntstatus_to_werror(status);
707                 goto done;
708         }
709
710         werr = map_group_info_to_buffer(ctx, r->in.level,
711                                         group_info_all ? &info->all : &info->all2,
712                                         domain_sid, rids.ids[0],
713                                         r->out.buffer);
714         if (!W_ERROR_IS_OK(werr)) {
715                 goto done;
716         }
717  done:
718         if (is_valid_policy_hnd(&group_handle)) {
719                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
720         }
721
722         if (ctx->disable_policy_handle_cache) {
723                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
724                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
725         }
726
727         return werr;
728 }
729
730 /****************************************************************
731 ****************************************************************/
732
733 WERROR NetGroupGetInfo_l(struct libnetapi_ctx *ctx,
734                          struct NetGroupGetInfo *r)
735 {
736         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupGetInfo);
737 }
738
739 /****************************************************************
740 ****************************************************************/
741
742 WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx,
743                          struct NetGroupAddUser *r)
744 {
745         struct rpc_pipe_client *pipe_cli = NULL;
746         NTSTATUS status;
747         WERROR werr;
748         struct policy_handle connect_handle, domain_handle, group_handle;
749         struct lsa_String lsa_group_name, lsa_user_name;
750         struct dom_sid2 *domain_sid = NULL;
751
752         struct samr_Ids rids;
753         struct samr_Ids types;
754
755         ZERO_STRUCT(connect_handle);
756         ZERO_STRUCT(domain_handle);
757         ZERO_STRUCT(group_handle);
758
759         if (!r->in.group_name) {
760                 return WERR_INVALID_PARAM;
761         }
762
763         werr = libnetapi_open_pipe(ctx, r->in.server_name,
764                                    &ndr_table_samr.syntax_id,
765                                    &pipe_cli);
766         if (!W_ERROR_IS_OK(werr)) {
767                 goto done;
768         }
769
770         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
771                                           SAMR_ACCESS_ENUM_DOMAINS |
772                                           SAMR_ACCESS_LOOKUP_DOMAIN,
773                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
774                                           &connect_handle,
775                                           &domain_handle,
776                                           &domain_sid);
777         if (!W_ERROR_IS_OK(werr)) {
778                 goto done;
779         }
780
781         init_lsa_String(&lsa_group_name, r->in.group_name);
782
783         status = rpccli_samr_LookupNames(pipe_cli, ctx,
784                                          &domain_handle,
785                                          1,
786                                          &lsa_group_name,
787                                          &rids,
788                                          &types);
789         if (!NT_STATUS_IS_OK(status)) {
790                 werr = WERR_GROUPNOTFOUND;
791                 goto done;
792         }
793
794         if (types.ids[0] != SID_NAME_DOM_GRP) {
795                 werr = WERR_GROUPNOTFOUND;
796                 goto done;
797         }
798
799         status = rpccli_samr_OpenGroup(pipe_cli, ctx,
800                                        &domain_handle,
801                                        SAMR_GROUP_ACCESS_ADD_MEMBER,
802                                        rids.ids[0],
803                                        &group_handle);
804         if (!NT_STATUS_IS_OK(status)) {
805                 werr = ntstatus_to_werror(status);
806                 goto done;
807         }
808
809         init_lsa_String(&lsa_user_name, r->in.user_name);
810
811         status = rpccli_samr_LookupNames(pipe_cli, ctx,
812                                          &domain_handle,
813                                          1,
814                                          &lsa_user_name,
815                                          &rids,
816                                          &types);
817         if (!NT_STATUS_IS_OK(status)) {
818                 werr = WERR_USER_NOT_FOUND;
819                 goto done;
820         }
821
822         if (types.ids[0] != SID_NAME_USER) {
823                 werr = WERR_USER_NOT_FOUND;
824                 goto done;
825         }
826
827         status = rpccli_samr_AddGroupMember(pipe_cli, ctx,
828                                             &group_handle,
829                                             rids.ids[0],
830                                             7); /* why ? */
831         if (!NT_STATUS_IS_OK(status)) {
832                 werr = ntstatus_to_werror(status);
833                 goto done;
834         }
835
836         werr = WERR_OK;
837
838  done:
839         if (is_valid_policy_hnd(&group_handle)) {
840                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
841         }
842
843         if (ctx->disable_policy_handle_cache) {
844                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
845                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
846         }
847
848         return werr;
849 }
850
851 /****************************************************************
852 ****************************************************************/
853
854 WERROR NetGroupAddUser_l(struct libnetapi_ctx *ctx,
855                          struct NetGroupAddUser *r)
856 {
857         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupAddUser);
858 }
859
860 /****************************************************************
861 ****************************************************************/
862
863 WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx,
864                          struct NetGroupDelUser *r)
865 {
866         struct rpc_pipe_client *pipe_cli = NULL;
867         NTSTATUS status;
868         WERROR werr;
869         struct policy_handle connect_handle, domain_handle, group_handle;
870         struct lsa_String lsa_group_name, lsa_user_name;
871         struct dom_sid2 *domain_sid = NULL;
872
873         struct samr_Ids rids;
874         struct samr_Ids types;
875
876         ZERO_STRUCT(connect_handle);
877         ZERO_STRUCT(domain_handle);
878         ZERO_STRUCT(group_handle);
879
880         if (!r->in.group_name) {
881                 return WERR_INVALID_PARAM;
882         }
883
884         werr = libnetapi_open_pipe(ctx, r->in.server_name,
885                                    &ndr_table_samr.syntax_id,
886                                    &pipe_cli);
887         if (!W_ERROR_IS_OK(werr)) {
888                 goto done;
889         }
890
891         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
892                                           SAMR_ACCESS_ENUM_DOMAINS |
893                                           SAMR_ACCESS_LOOKUP_DOMAIN,
894                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
895                                           &connect_handle,
896                                           &domain_handle,
897                                           &domain_sid);
898         if (!W_ERROR_IS_OK(werr)) {
899                 goto done;
900         }
901
902         init_lsa_String(&lsa_group_name, r->in.group_name);
903
904         status = rpccli_samr_LookupNames(pipe_cli, ctx,
905                                          &domain_handle,
906                                          1,
907                                          &lsa_group_name,
908                                          &rids,
909                                          &types);
910         if (!NT_STATUS_IS_OK(status)) {
911                 werr = WERR_GROUPNOTFOUND;
912                 goto done;
913         }
914
915         if (types.ids[0] != SID_NAME_DOM_GRP) {
916                 werr = WERR_GROUPNOTFOUND;
917                 goto done;
918         }
919
920         status = rpccli_samr_OpenGroup(pipe_cli, ctx,
921                                        &domain_handle,
922                                        SAMR_GROUP_ACCESS_REMOVE_MEMBER,
923                                        rids.ids[0],
924                                        &group_handle);
925         if (!NT_STATUS_IS_OK(status)) {
926                 werr = ntstatus_to_werror(status);
927                 goto done;
928         }
929
930         init_lsa_String(&lsa_user_name, r->in.user_name);
931
932         status = rpccli_samr_LookupNames(pipe_cli, ctx,
933                                          &domain_handle,
934                                          1,
935                                          &lsa_user_name,
936                                          &rids,
937                                          &types);
938         if (!NT_STATUS_IS_OK(status)) {
939                 werr = WERR_USER_NOT_FOUND;
940                 goto done;
941         }
942
943         if (types.ids[0] != SID_NAME_USER) {
944                 werr = WERR_USER_NOT_FOUND;
945                 goto done;
946         }
947
948         status = rpccli_samr_DeleteGroupMember(pipe_cli, ctx,
949                                                &group_handle,
950                                                rids.ids[0]);
951         if (!NT_STATUS_IS_OK(status)) {
952                 werr = ntstatus_to_werror(status);
953                 goto done;
954         }
955
956         werr = WERR_OK;
957
958  done:
959         if (is_valid_policy_hnd(&group_handle)) {
960                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
961         }
962
963         if (ctx->disable_policy_handle_cache) {
964                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
965                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
966         }
967
968         return werr;
969 }
970
971 /****************************************************************
972 ****************************************************************/
973
974 WERROR NetGroupDelUser_l(struct libnetapi_ctx *ctx,
975                          struct NetGroupDelUser *r)
976 {
977         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupDelUser);
978 }
979
980 /****************************************************************
981 ****************************************************************/
982
983 static WERROR convert_samr_disp_groups_to_GROUP_INFO_0_buffer(TALLOC_CTX *mem_ctx,
984                                                               struct samr_DispInfoFullGroups *groups,
985                                                               uint8_t **buffer)
986 {
987         struct GROUP_INFO_0 *g0;
988         int i;
989
990         g0 = TALLOC_ZERO_ARRAY(mem_ctx, struct GROUP_INFO_0, groups->count);
991         W_ERROR_HAVE_NO_MEMORY(g0);
992
993         for (i=0; i<groups->count; i++) {
994                 g0[i].grpi0_name = talloc_strdup(mem_ctx,
995                         groups->entries[i].account_name.string);
996                 W_ERROR_HAVE_NO_MEMORY(g0[i].grpi0_name);
997         }
998
999         *buffer = (uint8_t *)talloc_memdup(mem_ctx, g0,
1000                                            sizeof(struct GROUP_INFO_0) * groups->count);
1001         W_ERROR_HAVE_NO_MEMORY(*buffer);
1002
1003         return WERR_OK;
1004 }
1005
1006 /****************************************************************
1007 ****************************************************************/
1008
1009 static WERROR convert_samr_disp_groups_to_GROUP_INFO_1_buffer(TALLOC_CTX *mem_ctx,
1010                                                               struct samr_DispInfoFullGroups *groups,
1011                                                               uint8_t **buffer)
1012 {
1013         struct GROUP_INFO_1 *g1;
1014         int i;
1015
1016         g1 = TALLOC_ZERO_ARRAY(mem_ctx, struct GROUP_INFO_1, groups->count);
1017         W_ERROR_HAVE_NO_MEMORY(g1);
1018
1019         for (i=0; i<groups->count; i++) {
1020                 g1[i].grpi1_name = talloc_strdup(mem_ctx,
1021                         groups->entries[i].account_name.string);
1022                 g1[i].grpi1_comment = talloc_strdup(mem_ctx,
1023                         groups->entries[i].description.string);
1024                 W_ERROR_HAVE_NO_MEMORY(g1[i].grpi1_name);
1025         }
1026
1027         *buffer = (uint8_t *)talloc_memdup(mem_ctx, g1,
1028                                            sizeof(struct GROUP_INFO_1) * groups->count);
1029         W_ERROR_HAVE_NO_MEMORY(*buffer);
1030
1031         return WERR_OK;
1032 }
1033
1034 /****************************************************************
1035 ****************************************************************/
1036
1037 static WERROR convert_samr_disp_groups_to_GROUP_INFO_2_buffer(TALLOC_CTX *mem_ctx,
1038                                                               struct samr_DispInfoFullGroups *groups,
1039                                                               uint8_t **buffer)
1040 {
1041         struct GROUP_INFO_2 *g2;
1042         int i;
1043
1044         g2 = TALLOC_ZERO_ARRAY(mem_ctx, struct GROUP_INFO_2, groups->count);
1045         W_ERROR_HAVE_NO_MEMORY(g2);
1046
1047         for (i=0; i<groups->count; i++) {
1048                 g2[i].grpi2_name = talloc_strdup(mem_ctx,
1049                         groups->entries[i].account_name.string);
1050                 g2[i].grpi2_comment = talloc_strdup(mem_ctx,
1051                         groups->entries[i].description.string);
1052                 g2[i].grpi2_group_id = groups->entries[i].rid;
1053                 g2[i].grpi2_attributes = groups->entries[i].acct_flags;
1054                 W_ERROR_HAVE_NO_MEMORY(g2[i].grpi2_name);
1055         }
1056
1057         *buffer = (uint8_t *)talloc_memdup(mem_ctx, g2,
1058                                            sizeof(struct GROUP_INFO_2) * groups->count);
1059         W_ERROR_HAVE_NO_MEMORY(*buffer);
1060
1061         return WERR_OK;
1062 }
1063
1064 /****************************************************************
1065 ****************************************************************/
1066
1067 static WERROR convert_samr_disp_groups_to_GROUP_INFO_3_buffer(TALLOC_CTX *mem_ctx,
1068                                                               struct samr_DispInfoFullGroups *groups,
1069                                                               const struct dom_sid *domain_sid,
1070                                                               uint8_t **buffer)
1071 {
1072         struct GROUP_INFO_3 *g3;
1073         int i;
1074
1075         g3 = TALLOC_ZERO_ARRAY(mem_ctx, struct GROUP_INFO_3, groups->count);
1076         W_ERROR_HAVE_NO_MEMORY(g3);
1077
1078         for (i=0; i<groups->count; i++) {
1079
1080                 struct dom_sid sid;
1081
1082                 if (!sid_compose(&sid, domain_sid, groups->entries[i].rid)) {
1083                         return WERR_NOMEM;
1084                 }
1085
1086                 g3[i].grpi3_name = talloc_strdup(mem_ctx,
1087                         groups->entries[i].account_name.string);
1088                 g3[i].grpi3_comment = talloc_strdup(mem_ctx,
1089                         groups->entries[i].description.string);
1090                 g3[i].grpi3_group_sid = (struct domsid *)dom_sid_dup(mem_ctx, &sid);
1091                 g3[i].grpi3_attributes = groups->entries[i].acct_flags;
1092                 W_ERROR_HAVE_NO_MEMORY(g3[i].grpi3_name);
1093         }
1094
1095         *buffer = (uint8_t *)talloc_memdup(mem_ctx, g3,
1096                                            sizeof(struct GROUP_INFO_3) * groups->count);
1097         W_ERROR_HAVE_NO_MEMORY(*buffer);
1098
1099         return WERR_OK;
1100 }
1101
1102 /****************************************************************
1103 ****************************************************************/
1104
1105 static WERROR convert_samr_disp_groups_to_GROUP_INFO_buffer(TALLOC_CTX *mem_ctx,
1106                                                             uint32_t level,
1107                                                             struct samr_DispInfoFullGroups *groups,
1108                                                             const struct dom_sid *domain_sid,
1109                                                             uint32_t *entries_read,
1110                                                             uint8_t **buffer)
1111 {
1112         if (entries_read) {
1113                 *entries_read = groups->count;
1114         }
1115
1116         switch (level) {
1117                 case 0:
1118                         return convert_samr_disp_groups_to_GROUP_INFO_0_buffer(mem_ctx, groups, buffer);
1119                 case 1:
1120                         return convert_samr_disp_groups_to_GROUP_INFO_1_buffer(mem_ctx, groups, buffer);
1121                 case 2:
1122                         return convert_samr_disp_groups_to_GROUP_INFO_2_buffer(mem_ctx, groups, buffer);
1123                 case 3:
1124                         return convert_samr_disp_groups_to_GROUP_INFO_3_buffer(mem_ctx, groups, domain_sid, buffer);
1125                 default:
1126                         return WERR_UNKNOWN_LEVEL;
1127         }
1128 }
1129
1130 /****************************************************************
1131 ****************************************************************/
1132
1133 WERROR NetGroupEnum_r(struct libnetapi_ctx *ctx,
1134                       struct NetGroupEnum *r)
1135 {
1136         struct rpc_pipe_client *pipe_cli = NULL;
1137         struct policy_handle connect_handle;
1138         struct dom_sid2 *domain_sid = NULL;
1139         struct policy_handle domain_handle;
1140         union samr_DispInfo info;
1141         union samr_DomainInfo *domain_info = NULL;
1142
1143         uint32_t total_size = 0;
1144         uint32_t returned_size = 0;
1145
1146         NTSTATUS status = NT_STATUS_OK;
1147         WERROR werr, tmp_werr;
1148
1149         ZERO_STRUCT(connect_handle);
1150         ZERO_STRUCT(domain_handle);
1151
1152         switch (r->in.level) {
1153                 case 0:
1154                 case 1:
1155                 case 2:
1156                 case 3:
1157                         break;
1158                 default:
1159                         return WERR_UNKNOWN_LEVEL;
1160         }
1161
1162         werr = libnetapi_open_pipe(ctx, r->in.server_name,
1163                                    &ndr_table_samr.syntax_id,
1164                                    &pipe_cli);
1165         if (!W_ERROR_IS_OK(werr)) {
1166                 goto done;
1167         }
1168
1169         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
1170                                           SAMR_ACCESS_ENUM_DOMAINS |
1171                                           SAMR_ACCESS_LOOKUP_DOMAIN,
1172                                           SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 |
1173                                           SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS |
1174                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1175                                           &connect_handle,
1176                                           &domain_handle,
1177                                           &domain_sid);
1178         if (!W_ERROR_IS_OK(werr)) {
1179                 goto done;
1180         }
1181
1182         status = rpccli_samr_QueryDomainInfo(pipe_cli, ctx,
1183                                              &domain_handle,
1184                                              2,
1185                                              &domain_info);
1186         if (!NT_STATUS_IS_OK(status)) {
1187                 werr = ntstatus_to_werror(status);
1188                 goto done;
1189         }
1190
1191         if (r->out.total_entries) {
1192                 *r->out.total_entries = domain_info->general.num_groups;
1193         }
1194
1195         status = rpccli_samr_QueryDisplayInfo2(pipe_cli,
1196                                                ctx,
1197                                                &domain_handle,
1198                                                3,
1199                                                r->in.resume_handle ?
1200                                                *r->in.resume_handle : 0,
1201                                                (uint32_t)-1,
1202                                                r->in.prefmaxlen,
1203                                                &total_size,
1204                                                &returned_size,
1205                                                &info);
1206         werr = ntstatus_to_werror(status);
1207         if (NT_STATUS_IS_ERR(status)) {
1208                 goto done;
1209         }
1210
1211         if (r->out.resume_handle && info.info3.count > 0) {
1212                 *r->out.resume_handle =
1213                         info.info3.entries[info.info3.count-1].idx;
1214         }
1215
1216         tmp_werr = convert_samr_disp_groups_to_GROUP_INFO_buffer(ctx,
1217                                                                  r->in.level,
1218                                                                  &info.info3,
1219                                                                  domain_sid,
1220                                                                  r->out.entries_read,
1221                                                                  r->out.buffer);
1222         if (!W_ERROR_IS_OK(tmp_werr)) {
1223                 werr = tmp_werr;
1224                 goto done;
1225         }
1226
1227  done:
1228         /* if last query */
1229         if (NT_STATUS_IS_OK(status) ||
1230             NT_STATUS_IS_ERR(status)) {
1231
1232                 if (ctx->disable_policy_handle_cache) {
1233                         libnetapi_samr_close_domain_handle(ctx, &domain_handle);
1234                         libnetapi_samr_close_connect_handle(ctx, &connect_handle);
1235                 }
1236         }
1237
1238         return werr;
1239 }
1240
1241 /****************************************************************
1242 ****************************************************************/
1243
1244 WERROR NetGroupEnum_l(struct libnetapi_ctx *ctx,
1245                       struct NetGroupEnum *r)
1246 {
1247         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupEnum);
1248 }
1249
1250 /****************************************************************
1251 ****************************************************************/
1252
1253 WERROR NetGroupGetUsers_r(struct libnetapi_ctx *ctx,
1254                           struct NetGroupGetUsers *r)
1255 {
1256         /* FIXME: this call needs to cope with large replies */
1257
1258         struct rpc_pipe_client *pipe_cli = NULL;
1259         struct policy_handle connect_handle, domain_handle, group_handle;
1260         struct lsa_String lsa_account_name;
1261         struct dom_sid2 *domain_sid = NULL;
1262         struct samr_Ids group_rids, name_types;
1263         struct samr_RidTypeArray *rid_array = NULL;
1264         struct lsa_Strings names;
1265         struct samr_Ids member_types;
1266
1267         int i;
1268         uint32_t entries_read = 0;
1269
1270         NTSTATUS status = NT_STATUS_OK;
1271         WERROR werr;
1272
1273         ZERO_STRUCT(connect_handle);
1274         ZERO_STRUCT(domain_handle);
1275
1276         if (!r->out.buffer) {
1277                 return WERR_INVALID_PARAM;
1278         }
1279
1280         *r->out.buffer = NULL;
1281         *r->out.entries_read = 0;
1282         *r->out.total_entries = 0;
1283
1284         switch (r->in.level) {
1285                 case 0:
1286                 case 1:
1287                         break;
1288                 default:
1289                         return WERR_UNKNOWN_LEVEL;
1290         }
1291
1292
1293         werr = libnetapi_open_pipe(ctx, r->in.server_name,
1294                                    &ndr_table_samr.syntax_id,
1295                                    &pipe_cli);
1296         if (!W_ERROR_IS_OK(werr)) {
1297                 goto done;
1298         }
1299
1300         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
1301                                           SAMR_ACCESS_ENUM_DOMAINS |
1302                                           SAMR_ACCESS_LOOKUP_DOMAIN,
1303                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1304                                           &connect_handle,
1305                                           &domain_handle,
1306                                           &domain_sid);
1307         if (!W_ERROR_IS_OK(werr)) {
1308                 goto done;
1309         }
1310
1311         init_lsa_String(&lsa_account_name, r->in.group_name);
1312
1313         status = rpccli_samr_LookupNames(pipe_cli, ctx,
1314                                          &domain_handle,
1315                                          1,
1316                                          &lsa_account_name,
1317                                          &group_rids,
1318                                          &name_types);
1319         if (!NT_STATUS_IS_OK(status)) {
1320                 werr = ntstatus_to_werror(status);
1321                 goto done;
1322         }
1323
1324         status = rpccli_samr_OpenGroup(pipe_cli, ctx,
1325                                        &domain_handle,
1326                                        SAMR_GROUP_ACCESS_GET_MEMBERS,
1327                                        group_rids.ids[0],
1328                                        &group_handle);
1329         if (!NT_STATUS_IS_OK(status)) {
1330                 werr = ntstatus_to_werror(status);
1331                 goto done;
1332         }
1333
1334         status = rpccli_samr_QueryGroupMember(pipe_cli, ctx,
1335                                               &group_handle,
1336                                               &rid_array);
1337         if (!NT_STATUS_IS_OK(status)) {
1338                 werr = ntstatus_to_werror(status);
1339                 goto done;
1340         }
1341
1342         status = rpccli_samr_LookupRids(pipe_cli, ctx,
1343                                         &domain_handle,
1344                                         rid_array->count,
1345                                         rid_array->rids,
1346                                         &names,
1347                                         &member_types);
1348         if (!NT_STATUS_IS_OK(status)) {
1349                 werr = ntstatus_to_werror(status);
1350                 goto done;
1351         }
1352
1353         for (i=0; i < names.count; i++) {
1354
1355                 if (member_types.ids[i] != SID_NAME_USER) {
1356                         continue;
1357                 }
1358
1359                 status = add_GROUP_USERS_INFO_X_buffer(ctx,
1360                                                        r->in.level,
1361                                                        names.names[i].string,
1362                                                        7,
1363                                                        r->out.buffer,
1364                                                        &entries_read);
1365                 if (!NT_STATUS_IS_OK(status)) {
1366                         werr = ntstatus_to_werror(status);
1367                         goto done;
1368                 }
1369         }
1370
1371         *r->out.entries_read = entries_read;
1372         *r->out.total_entries = entries_read;
1373
1374         werr = WERR_OK;
1375
1376  done:
1377         if (is_valid_policy_hnd(&group_handle)) {
1378                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
1379         }
1380
1381         if (ctx->disable_policy_handle_cache) {
1382                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
1383                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
1384         }
1385
1386         return werr;
1387 }
1388
1389 /****************************************************************
1390 ****************************************************************/
1391
1392 WERROR NetGroupGetUsers_l(struct libnetapi_ctx *ctx,
1393                           struct NetGroupGetUsers *r)
1394 {
1395         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupGetUsers);
1396 }
1397
1398 /****************************************************************
1399 ****************************************************************/
1400
1401 WERROR NetGroupSetUsers_r(struct libnetapi_ctx *ctx,
1402                           struct NetGroupSetUsers *r)
1403 {
1404         struct rpc_pipe_client *pipe_cli = NULL;
1405         struct policy_handle connect_handle, domain_handle, group_handle;
1406         struct lsa_String lsa_account_name;
1407         struct dom_sid2 *domain_sid = NULL;
1408         union samr_GroupInfo *group_info = NULL;
1409         struct samr_Ids user_rids, name_types;
1410         struct samr_Ids group_rids, group_types;
1411         struct samr_RidTypeArray *rid_array = NULL;
1412         struct lsa_String *lsa_names = NULL;
1413
1414         uint32_t *add_rids = NULL;
1415         uint32_t *del_rids = NULL;
1416         size_t num_add_rids = 0;
1417         size_t num_del_rids = 0;
1418
1419         uint32_t *member_rids = NULL;
1420
1421         struct GROUP_USERS_INFO_0 *i0 = NULL;
1422         struct GROUP_USERS_INFO_1 *i1 = NULL;
1423
1424         int i, k;
1425
1426         NTSTATUS status = NT_STATUS_OK;
1427         WERROR werr;
1428
1429         ZERO_STRUCT(connect_handle);
1430         ZERO_STRUCT(domain_handle);
1431
1432         if (!r->in.buffer) {
1433                 return WERR_INVALID_PARAM;
1434         }
1435
1436         switch (r->in.level) {
1437                 case 0:
1438                 case 1:
1439                         break;
1440                 default:
1441                         return WERR_UNKNOWN_LEVEL;
1442         }
1443
1444         werr = libnetapi_open_pipe(ctx, r->in.server_name,
1445                                    &ndr_table_samr.syntax_id,
1446                                    &pipe_cli);
1447         if (!W_ERROR_IS_OK(werr)) {
1448                 goto done;
1449         }
1450
1451         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
1452                                           SAMR_ACCESS_ENUM_DOMAINS |
1453                                           SAMR_ACCESS_LOOKUP_DOMAIN,
1454                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1455                                           &connect_handle,
1456                                           &domain_handle,
1457                                           &domain_sid);
1458         if (!W_ERROR_IS_OK(werr)) {
1459                 goto done;
1460         }
1461
1462         init_lsa_String(&lsa_account_name, r->in.group_name);
1463
1464         status = rpccli_samr_LookupNames(pipe_cli, ctx,
1465                                          &domain_handle,
1466                                          1,
1467                                          &lsa_account_name,
1468                                          &group_rids,
1469                                          &group_types);
1470         if (!NT_STATUS_IS_OK(status)) {
1471                 werr = ntstatus_to_werror(status);
1472                 goto done;
1473         }
1474
1475         status = rpccli_samr_OpenGroup(pipe_cli, ctx,
1476                                        &domain_handle,
1477                                        SAMR_GROUP_ACCESS_GET_MEMBERS |
1478                                        SAMR_GROUP_ACCESS_ADD_MEMBER |
1479                                        SAMR_GROUP_ACCESS_REMOVE_MEMBER |
1480                                        SAMR_GROUP_ACCESS_LOOKUP_INFO,
1481                                        group_rids.ids[0],
1482                                        &group_handle);
1483         if (!NT_STATUS_IS_OK(status)) {
1484                 werr = ntstatus_to_werror(status);
1485                 goto done;
1486         }
1487
1488         status = rpccli_samr_QueryGroupInfo(pipe_cli, ctx,
1489                                             &group_handle,
1490                                             GROUPINFOATTRIBUTES,
1491                                             &group_info);
1492         if (!NT_STATUS_IS_OK(status)) {
1493                 werr = ntstatus_to_werror(status);
1494                 goto done;
1495         }
1496
1497         switch (r->in.level) {
1498                 case 0:
1499                         i0 = (struct GROUP_USERS_INFO_0 *)r->in.buffer;
1500                         break;
1501                 case 1:
1502                         i1 = (struct GROUP_USERS_INFO_1 *)r->in.buffer;
1503                         break;
1504         }
1505
1506         lsa_names = talloc_array(ctx, struct lsa_String, r->in.num_entries);
1507         if (!lsa_names) {
1508                 werr = WERR_NOMEM;
1509                 goto done;
1510         }
1511
1512         for (i=0; i < r->in.num_entries; i++) {
1513
1514                 switch (r->in.level) {
1515                         case 0:
1516                                 init_lsa_String(&lsa_names[i], i0->grui0_name);
1517                                 i0++;
1518                                 break;
1519                         case 1:
1520                                 init_lsa_String(&lsa_names[i], i1->grui1_name);
1521                                 i1++;
1522                                 break;
1523                 }
1524         }
1525
1526         status = rpccli_samr_LookupNames(pipe_cli, ctx,
1527                                          &domain_handle,
1528                                          r->in.num_entries,
1529                                          lsa_names,
1530                                          &user_rids,
1531                                          &name_types);
1532         if (!NT_STATUS_IS_OK(status)) {
1533                 werr = ntstatus_to_werror(status);
1534                 goto done;
1535         }
1536
1537         member_rids = user_rids.ids;
1538
1539         status = rpccli_samr_QueryGroupMember(pipe_cli, ctx,
1540                                               &group_handle,
1541                                               &rid_array);
1542         if (!NT_STATUS_IS_OK(status)) {
1543                 werr = ntstatus_to_werror(status);
1544                 goto done;
1545         }
1546
1547         /* add list */
1548
1549         for (i=0; i < r->in.num_entries; i++) {
1550                 bool already_member = false;
1551                 for (k=0; k < rid_array->count; k++) {
1552                         if (member_rids[i] == rid_array->rids[k]) {
1553                                 already_member = true;
1554                                 break;
1555                         }
1556                 }
1557                 if (!already_member) {
1558                         if (!add_rid_to_array_unique(ctx,
1559                                                      member_rids[i],
1560                                                      &add_rids, &num_add_rids)) {
1561                                 werr = WERR_GENERAL_FAILURE;
1562                                 goto done;
1563                         }
1564                 }
1565         }
1566
1567         /* del list */
1568
1569         for (k=0; k < rid_array->count; k++) {
1570                 bool keep_member = false;
1571                 for (i=0; i < r->in.num_entries; i++) {
1572                         if (member_rids[i] == rid_array->rids[k]) {
1573                                 keep_member = true;
1574                                 break;
1575                         }
1576                 }
1577                 if (!keep_member) {
1578                         if (!add_rid_to_array_unique(ctx,
1579                                                      rid_array->rids[k],
1580                                                      &del_rids, &num_del_rids)) {
1581                                 werr = WERR_GENERAL_FAILURE;
1582                                 goto done;
1583                         }
1584                 }
1585         }
1586
1587         /* add list */
1588
1589         for (i=0; i < num_add_rids; i++) {
1590                 status = rpccli_samr_AddGroupMember(pipe_cli, ctx,
1591                                                     &group_handle,
1592                                                     add_rids[i],
1593                                                     7 /* ? */);
1594                 if (!NT_STATUS_IS_OK(status)) {
1595                         werr = ntstatus_to_werror(status);
1596                         goto done;
1597                 }
1598         }
1599
1600         /* del list */
1601
1602         for (i=0; i < num_del_rids; i++) {
1603                 status = rpccli_samr_DeleteGroupMember(pipe_cli, ctx,
1604                                                        &group_handle,
1605                                                        del_rids[i]);
1606                 if (!NT_STATUS_IS_OK(status)) {
1607                         werr = ntstatus_to_werror(status);
1608                         goto done;
1609                 }
1610         }
1611
1612         werr = WERR_OK;
1613
1614  done:
1615         if (is_valid_policy_hnd(&group_handle)) {
1616                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
1617         }
1618
1619         if (ctx->disable_policy_handle_cache) {
1620                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
1621                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
1622         }
1623
1624         return werr;
1625 }
1626
1627 /****************************************************************
1628 ****************************************************************/
1629
1630 WERROR NetGroupSetUsers_l(struct libnetapi_ctx *ctx,
1631                           struct NetGroupSetUsers *r)
1632 {
1633         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupSetUsers);
1634 }