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