617bde2c9ae4b078afbb7ca47d834872b3f9ed19
[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         POLICY_HND 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         POLICY_HND 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         POLICY_HND 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         POLICY_HND 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         POLICY_HND 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         POLICY_HND 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
1280         switch (r->in.level) {
1281                 case 0:
1282                 case 1:
1283                         break;
1284                 default:
1285                         return WERR_UNKNOWN_LEVEL;
1286         }
1287
1288
1289         werr = libnetapi_open_pipe(ctx, r->in.server_name,
1290                                    &ndr_table_samr.syntax_id,
1291                                    &pipe_cli);
1292         if (!W_ERROR_IS_OK(werr)) {
1293                 goto done;
1294         }
1295
1296         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
1297                                           SAMR_ACCESS_ENUM_DOMAINS |
1298                                           SAMR_ACCESS_OPEN_DOMAIN,
1299                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1300                                           &connect_handle,
1301                                           &domain_handle,
1302                                           &domain_sid);
1303         if (!W_ERROR_IS_OK(werr)) {
1304                 goto done;
1305         }
1306
1307         init_lsa_String(&lsa_account_name, r->in.group_name);
1308
1309         status = rpccli_samr_LookupNames(pipe_cli, ctx,
1310                                          &domain_handle,
1311                                          1,
1312                                          &lsa_account_name,
1313                                          &group_rids,
1314                                          &name_types);
1315         if (!NT_STATUS_IS_OK(status)) {
1316                 werr = ntstatus_to_werror(status);
1317                 goto done;
1318         }
1319
1320         status = rpccli_samr_OpenGroup(pipe_cli, ctx,
1321                                        &domain_handle,
1322                                        SAMR_GROUP_ACCESS_GET_MEMBERS,
1323                                        group_rids.ids[0],
1324                                        &group_handle);
1325         if (!NT_STATUS_IS_OK(status)) {
1326                 werr = ntstatus_to_werror(status);
1327                 goto done;
1328         }
1329
1330         status = rpccli_samr_QueryGroupMember(pipe_cli, ctx,
1331                                               &group_handle,
1332                                               &rid_array);
1333         if (!NT_STATUS_IS_OK(status)) {
1334                 werr = ntstatus_to_werror(status);
1335                 goto done;
1336         }
1337
1338         status = rpccli_samr_LookupRids(pipe_cli, ctx,
1339                                         &domain_handle,
1340                                         rid_array->count,
1341                                         rid_array->rids,
1342                                         &names,
1343                                         &member_types);
1344         if (!NT_STATUS_IS_OK(status)) {
1345                 werr = ntstatus_to_werror(status);
1346                 goto done;
1347         }
1348
1349         for (i=0; i < names.count; i++) {
1350
1351                 if (member_types.ids[i] != SID_NAME_USER) {
1352                         continue;
1353                 }
1354
1355                 status = add_GROUP_USERS_INFO_X_buffer(ctx,
1356                                                        r->in.level,
1357                                                        names.names[i].string,
1358                                                        7,
1359                                                        r->out.buffer,
1360                                                        &entries_read);
1361                 if (!NT_STATUS_IS_OK(status)) {
1362                         werr = ntstatus_to_werror(status);
1363                         goto done;
1364                 }
1365         }
1366
1367         if (r->out.entries_read) {
1368                 *r->out.entries_read = entries_read;
1369         }
1370
1371         if (r->out.total_entries) {
1372                 *r->out.total_entries = entries_read;
1373         }
1374
1375         werr = WERR_OK;
1376
1377  done:
1378         if (is_valid_policy_hnd(&group_handle)) {
1379                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
1380         }
1381
1382         if (ctx->disable_policy_handle_cache) {
1383                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
1384                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
1385         }
1386
1387         return werr;
1388 }
1389
1390 /****************************************************************
1391 ****************************************************************/
1392
1393 WERROR NetGroupGetUsers_l(struct libnetapi_ctx *ctx,
1394                           struct NetGroupGetUsers *r)
1395 {
1396         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupGetUsers);
1397 }
1398
1399 /****************************************************************
1400 ****************************************************************/
1401
1402 WERROR NetGroupSetUsers_r(struct libnetapi_ctx *ctx,
1403                           struct NetGroupSetUsers *r)
1404 {
1405         struct rpc_pipe_client *pipe_cli = NULL;
1406         struct policy_handle connect_handle, domain_handle, group_handle;
1407         struct lsa_String lsa_account_name;
1408         struct dom_sid2 *domain_sid = NULL;
1409         union samr_GroupInfo *group_info = NULL;
1410         struct samr_Ids user_rids, name_types;
1411         struct samr_Ids group_rids, group_types;
1412         struct samr_RidTypeArray *rid_array = NULL;
1413         struct lsa_String *lsa_names = NULL;
1414
1415         uint32_t *add_rids = NULL;
1416         uint32_t *del_rids = NULL;
1417         size_t num_add_rids = 0;
1418         size_t num_del_rids = 0;
1419
1420         uint32_t *member_rids = NULL;
1421         size_t num_member_rids = 0;
1422
1423         struct GROUP_USERS_INFO_0 *i0 = NULL;
1424         struct GROUP_USERS_INFO_1 *i1 = NULL;
1425
1426         int i, k;
1427
1428         NTSTATUS status = NT_STATUS_OK;
1429         WERROR werr;
1430
1431         ZERO_STRUCT(connect_handle);
1432         ZERO_STRUCT(domain_handle);
1433
1434         if (!r->in.buffer) {
1435                 return WERR_INVALID_PARAM;
1436         }
1437
1438         switch (r->in.level) {
1439                 case 0:
1440                 case 1:
1441                         break;
1442                 default:
1443                         return WERR_UNKNOWN_LEVEL;
1444         }
1445
1446         werr = libnetapi_open_pipe(ctx, r->in.server_name,
1447                                    &ndr_table_samr.syntax_id,
1448                                    &pipe_cli);
1449         if (!W_ERROR_IS_OK(werr)) {
1450                 goto done;
1451         }
1452
1453         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
1454                                           SAMR_ACCESS_ENUM_DOMAINS |
1455                                           SAMR_ACCESS_OPEN_DOMAIN,
1456                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1457                                           &connect_handle,
1458                                           &domain_handle,
1459                                           &domain_sid);
1460         if (!W_ERROR_IS_OK(werr)) {
1461                 goto done;
1462         }
1463
1464         init_lsa_String(&lsa_account_name, r->in.group_name);
1465
1466         status = rpccli_samr_LookupNames(pipe_cli, ctx,
1467                                          &domain_handle,
1468                                          1,
1469                                          &lsa_account_name,
1470                                          &group_rids,
1471                                          &group_types);
1472         if (!NT_STATUS_IS_OK(status)) {
1473                 werr = ntstatus_to_werror(status);
1474                 goto done;
1475         }
1476
1477         status = rpccli_samr_OpenGroup(pipe_cli, ctx,
1478                                        &domain_handle,
1479                                        SAMR_GROUP_ACCESS_GET_MEMBERS |
1480                                        SAMR_GROUP_ACCESS_ADD_MEMBER |
1481                                        SAMR_GROUP_ACCESS_REMOVE_MEMBER |
1482                                        SAMR_GROUP_ACCESS_LOOKUP_INFO,
1483                                        group_rids.ids[0],
1484                                        &group_handle);
1485         if (!NT_STATUS_IS_OK(status)) {
1486                 werr = ntstatus_to_werror(status);
1487                 goto done;
1488         }
1489
1490         status = rpccli_samr_QueryGroupInfo(pipe_cli, ctx,
1491                                             &group_handle,
1492                                             GROUPINFOATTRIBUTES,
1493                                             &group_info);
1494         if (!NT_STATUS_IS_OK(status)) {
1495                 werr = ntstatus_to_werror(status);
1496                 goto done;
1497         }
1498
1499         switch (r->in.level) {
1500                 case 0:
1501                         i0 = (struct GROUP_USERS_INFO_0 *)r->in.buffer;
1502                         break;
1503                 case 1:
1504                         i1 = (struct GROUP_USERS_INFO_1 *)r->in.buffer;
1505                         break;
1506         }
1507
1508         lsa_names = talloc_array(ctx, struct lsa_String, r->in.num_entries);
1509         if (!lsa_names) {
1510                 werr = WERR_NOMEM;
1511                 goto done;
1512         }
1513
1514         for (i=0; i < r->in.num_entries; i++) {
1515
1516                 switch (r->in.level) {
1517                         case 0:
1518                                 init_lsa_String(&lsa_names[i], i0->grui0_name);
1519                                 i0++;
1520                                 break;
1521                         case 1:
1522                                 init_lsa_String(&lsa_names[i], i1->grui1_name);
1523                                 i1++;
1524                                 break;
1525                 }
1526         }
1527
1528         status = rpccli_samr_LookupNames(pipe_cli, ctx,
1529                                          &domain_handle,
1530                                          r->in.num_entries,
1531                                          lsa_names,
1532                                          &user_rids,
1533                                          &name_types);
1534         if (!NT_STATUS_IS_OK(status)) {
1535                 werr = ntstatus_to_werror(status);
1536                 goto done;
1537         }
1538
1539         member_rids = user_rids.ids;
1540         num_member_rids = user_rids.count;
1541
1542         status = rpccli_samr_QueryGroupMember(pipe_cli, ctx,
1543                                               &group_handle,
1544                                               &rid_array);
1545         if (!NT_STATUS_IS_OK(status)) {
1546                 werr = ntstatus_to_werror(status);
1547                 goto done;
1548         }
1549
1550         /* add list */
1551
1552         for (i=0; i < r->in.num_entries; i++) {
1553                 bool already_member = false;
1554                 for (k=0; k < rid_array->count; k++) {
1555                         if (member_rids[i] == rid_array->rids[k]) {
1556                                 already_member = true;
1557                                 break;
1558                         }
1559                 }
1560                 if (!already_member) {
1561                         if (!add_rid_to_array_unique(ctx,
1562                                                      member_rids[i],
1563                                                      &add_rids, &num_add_rids)) {
1564                                 werr = WERR_GENERAL_FAILURE;
1565                                 goto done;
1566                         }
1567                 }
1568         }
1569
1570         /* del list */
1571
1572         for (k=0; k < rid_array->count; k++) {
1573                 bool keep_member = false;
1574                 for (i=0; i < r->in.num_entries; i++) {
1575                         if (member_rids[i] == rid_array->rids[k]) {
1576                                 keep_member = true;
1577                                 break;
1578                         }
1579                 }
1580                 if (!keep_member) {
1581                         if (!add_rid_to_array_unique(ctx,
1582                                                      rid_array->rids[k],
1583                                                      &del_rids, &num_del_rids)) {
1584                                 werr = WERR_GENERAL_FAILURE;
1585                                 goto done;
1586                         }
1587                 }
1588         }
1589
1590         /* add list */
1591
1592         for (i=0; i < num_add_rids; i++) {
1593                 status = rpccli_samr_AddGroupMember(pipe_cli, ctx,
1594                                                     &group_handle,
1595                                                     add_rids[i],
1596                                                     7 /* ? */);
1597                 if (!NT_STATUS_IS_OK(status)) {
1598                         werr = ntstatus_to_werror(status);
1599                         goto done;
1600                 }
1601         }
1602
1603         /* del list */
1604
1605         for (i=0; i < num_del_rids; i++) {
1606                 status = rpccli_samr_DeleteGroupMember(pipe_cli, ctx,
1607                                                        &group_handle,
1608                                                        del_rids[i]);
1609                 if (!NT_STATUS_IS_OK(status)) {
1610                         werr = ntstatus_to_werror(status);
1611                         goto done;
1612                 }
1613         }
1614
1615         werr = WERR_OK;
1616
1617  done:
1618         if (is_valid_policy_hnd(&group_handle)) {
1619                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
1620         }
1621
1622         if (ctx->disable_policy_handle_cache) {
1623                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
1624                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
1625         }
1626
1627         return werr;
1628 }
1629
1630 /****************************************************************
1631 ****************************************************************/
1632
1633 WERROR NetGroupSetUsers_l(struct libnetapi_ctx *ctx,
1634                           struct NetGroupSetUsers *r)
1635 {
1636         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupSetUsers);
1637 }