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