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