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