e057e6de0235fe8e16b5ed0f9f707c2f8ca1629f
[kai/samba.git] / source3 / lib / netapi / group.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  NetApi Group Support
4  *  Copyright (C) Guenther Deschner 2008
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21
22 #include "librpc/gen_ndr/libnetapi.h"
23 #include "lib/netapi/netapi.h"
24 #include "lib/netapi/netapi_private.h"
25 #include "lib/netapi/libnetapi.h"
26
27 /****************************************************************
28 ****************************************************************/
29
30 WERROR NetGroupAdd_r(struct libnetapi_ctx *ctx,
31                      struct NetGroupAdd *r)
32 {
33         struct 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_ipc_connection(ctx, r->in.server_name, &cli);
75         if (!W_ERROR_IS_OK(werr)) {
76                 goto done;
77         }
78
79         werr = libnetapi_open_pipe(ctx, cli, &ndr_table_samr.syntax_id,
80                                    &pipe_cli);
81         if (!W_ERROR_IS_OK(werr)) {
82                 goto done;
83         }
84
85         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
86                                           SAMR_ACCESS_ENUM_DOMAINS |
87                                           SAMR_ACCESS_OPEN_DOMAIN,
88                                           SAMR_DOMAIN_ACCESS_CREATE_GROUP |
89                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
90                                           &connect_handle,
91                                           &domain_handle,
92                                           &domain_sid);
93         if (!W_ERROR_IS_OK(werr)) {
94                 goto done;
95         }
96
97         switch (r->in.level) {
98                 case 0:
99                         init_lsa_String(&lsa_group_name, info0->grpi0_name);
100                         break;
101                 case 1:
102                         init_lsa_String(&lsa_group_name, info1->grpi1_name);
103                         break;
104                 case 2:
105                         init_lsa_String(&lsa_group_name, info2->grpi2_name);
106                         break;
107                 case 3:
108                         init_lsa_String(&lsa_group_name, info3->grpi3_name);
109                         break;
110         }
111
112         status = rpccli_samr_CreateDomainGroup(pipe_cli, ctx,
113                                                &domain_handle,
114                                                &lsa_group_name,
115                                                SEC_STD_DELETE |
116                                                SAMR_GROUP_ACCESS_SET_INFO,
117                                                &group_handle,
118                                                &rid);
119
120         if (!NT_STATUS_IS_OK(status)) {
121                 werr = ntstatus_to_werror(status);
122                 goto done;
123         }
124
125         switch (r->in.level) {
126                 case 1:
127                         if (info1->grpi1_comment) {
128                                 init_lsa_String(&info.description,
129                                                 info1->grpi1_comment);
130
131                                 status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
132                                                                   &group_handle,
133                                                                   GROUPINFODESCRIPTION,
134                                                                   &info);
135                         }
136                         break;
137                 case 2:
138                         if (info2->grpi2_comment) {
139                                 init_lsa_String(&info.description,
140                                                 info2->grpi2_comment);
141
142                                 status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
143                                                                   &group_handle,
144                                                                   GROUPINFODESCRIPTION,
145                                                                   &info);
146                                 if (!NT_STATUS_IS_OK(status)) {
147                                         werr = ntstatus_to_werror(status);
148                                         goto failed;
149                                 }
150                         }
151
152                         if (info2->grpi2_attributes != 0) {
153                                 info.attributes.attributes = info2->grpi2_attributes;
154                                 status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
155                                                                   &group_handle,
156                                                                   GROUPINFOATTRIBUTES,
157                                                                   &info);
158
159                         }
160                         break;
161                 case 3:
162                         if (info3->grpi3_comment) {
163                                 init_lsa_String(&info.description,
164                                                 info3->grpi3_comment);
165
166                                 status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
167                                                                   &group_handle,
168                                                                   GROUPINFODESCRIPTION,
169                                                                   &info);
170                                 if (!NT_STATUS_IS_OK(status)) {
171                                         werr = ntstatus_to_werror(status);
172                                         goto failed;
173                                 }
174                         }
175
176                         if (info3->grpi3_attributes != 0) {
177                                 info.attributes.attributes = info3->grpi3_attributes;
178                                 status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
179                                                                   &group_handle,
180                                                                   GROUPINFOATTRIBUTES,
181                                                                   &info);
182                         }
183                         break;
184                 default:
185                         break;
186         }
187
188         if (!NT_STATUS_IS_OK(status)) {
189                 werr = ntstatus_to_werror(status);
190                 goto failed;
191         }
192
193         werr = WERR_OK;
194         goto done;
195
196  failed:
197         rpccli_samr_DeleteDomainGroup(pipe_cli, ctx,
198                                       &group_handle);
199
200  done:
201         if (!cli) {
202                 return werr;
203         }
204
205         if (is_valid_policy_hnd(&group_handle)) {
206                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
207         }
208
209         if (ctx->disable_policy_handle_cache) {
210                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
211                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
212         }
213
214         return werr;
215 }
216
217 /****************************************************************
218 ****************************************************************/
219
220 WERROR NetGroupAdd_l(struct libnetapi_ctx *ctx,
221                      struct NetGroupAdd *r)
222 {
223         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupAdd);
224 }
225
226 /****************************************************************
227 ****************************************************************/
228
229 WERROR NetGroupDel_r(struct libnetapi_ctx *ctx,
230                      struct NetGroupDel *r)
231 {
232         struct cli_state *cli = NULL;
233         struct rpc_pipe_client *pipe_cli = NULL;
234         NTSTATUS status;
235         WERROR werr;
236         POLICY_HND connect_handle, domain_handle, group_handle;
237         struct lsa_String lsa_group_name;
238         struct dom_sid2 *domain_sid = NULL;
239         int i = 0;
240
241         struct samr_Ids rids;
242         struct samr_Ids types;
243         union samr_GroupInfo *info = NULL;
244         struct samr_RidTypeArray *rid_array = NULL;
245
246         ZERO_STRUCT(connect_handle);
247         ZERO_STRUCT(domain_handle);
248         ZERO_STRUCT(group_handle);
249
250         if (!r->in.group_name) {
251                 return WERR_INVALID_PARAM;
252         }
253
254         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
255         if (!W_ERROR_IS_OK(werr)) {
256                 goto done;
257         }
258
259         werr = libnetapi_open_pipe(ctx, cli, &ndr_table_samr.syntax_id,
260                                    &pipe_cli);
261         if (!W_ERROR_IS_OK(werr)) {
262                 goto done;
263         }
264
265         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
266                                           SAMR_ACCESS_ENUM_DOMAINS |
267                                           SAMR_ACCESS_OPEN_DOMAIN,
268                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
269                                           &connect_handle,
270                                           &domain_handle,
271                                           &domain_sid);
272         if (!W_ERROR_IS_OK(werr)) {
273                 goto done;
274         }
275
276         init_lsa_String(&lsa_group_name, r->in.group_name);
277
278         status = rpccli_samr_LookupNames(pipe_cli, ctx,
279                                          &domain_handle,
280                                          1,
281                                          &lsa_group_name,
282                                          &rids,
283                                          &types);
284         if (!NT_STATUS_IS_OK(status)) {
285                 werr = ntstatus_to_werror(status);
286                 goto done;
287         }
288
289         if (types.ids[0] != SID_NAME_DOM_GRP) {
290                 werr = WERR_INVALID_DATATYPE;
291                 goto done;
292         }
293
294         status = rpccli_samr_OpenGroup(pipe_cli, ctx,
295                                        &domain_handle,
296                                        SEC_STD_DELETE |
297                                        SAMR_GROUP_ACCESS_GET_MEMBERS |
298                                        SAMR_GROUP_ACCESS_REMOVE_MEMBER |
299                                        SAMR_GROUP_ACCESS_ADD_MEMBER |
300                                        SAMR_GROUP_ACCESS_LOOKUP_INFO,
301                                        rids.ids[0],
302                                        &group_handle);
303         if (!NT_STATUS_IS_OK(status)) {
304                 werr = ntstatus_to_werror(status);
305                 goto done;
306         }
307
308         status = rpccli_samr_QueryGroupInfo(pipe_cli, ctx,
309                                             &group_handle,
310                                             GROUPINFOATTRIBUTES,
311                                             &info);
312         if (!NT_STATUS_IS_OK(status)) {
313                 werr = ntstatus_to_werror(status);
314                 goto done;
315         }
316
317 #if 0
318         /* breaks against NT4 */
319         if (!(info->attributes.attributes & SE_GROUP_ENABLED)) {
320                 werr = WERR_ACCESS_DENIED;
321                 goto done;
322         }
323 #endif
324         status = rpccli_samr_QueryGroupMember(pipe_cli, ctx,
325                                               &group_handle,
326                                               &rid_array);
327         if (!NT_STATUS_IS_OK(status)) {
328                 werr = ntstatus_to_werror(status);
329                 goto done;
330         }
331
332         {
333         struct lsa_Strings names;
334         struct samr_Ids member_types;
335
336         status = rpccli_samr_LookupRids(pipe_cli, ctx,
337                                         &domain_handle,
338                                         rid_array->count,
339                                         rid_array->rids,
340                                         &names,
341                                         &member_types);
342         if (!NT_STATUS_IS_OK(status)) {
343                 werr = ntstatus_to_werror(status);
344                 goto done;
345         }
346         }
347
348         for (i=0; i < rid_array->count; i++) {
349
350                 status = rpccli_samr_DeleteGroupMember(pipe_cli, ctx,
351                                                        &group_handle,
352                                                        rid_array->rids[i]);
353                 if (!NT_STATUS_IS_OK(status)) {
354                         werr = ntstatus_to_werror(status);
355                         goto done;
356                 }
357         }
358
359         status = rpccli_samr_DeleteDomainGroup(pipe_cli, ctx,
360                                                &group_handle);
361         if (!NT_STATUS_IS_OK(status)) {
362                 werr = ntstatus_to_werror(status);
363                 goto done;
364         }
365
366         ZERO_STRUCT(group_handle);
367
368         werr = WERR_OK;
369
370  done:
371         if (!cli) {
372                 return werr;
373         }
374
375         if (is_valid_policy_hnd(&group_handle)) {
376                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
377         }
378
379         if (ctx->disable_policy_handle_cache) {
380                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
381                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
382         }
383
384         return werr;
385 }
386
387 /****************************************************************
388 ****************************************************************/
389
390 WERROR NetGroupDel_l(struct libnetapi_ctx *ctx,
391                      struct NetGroupDel *r)
392 {
393         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupDel);
394 }
395
396 /****************************************************************
397 ****************************************************************/
398
399 WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
400                          struct NetGroupSetInfo *r)
401 {
402         struct cli_state *cli = NULL;
403         struct rpc_pipe_client *pipe_cli = NULL;
404         NTSTATUS status;
405         WERROR werr;
406         POLICY_HND connect_handle, domain_handle, group_handle;
407         struct lsa_String lsa_group_name;
408         struct dom_sid2 *domain_sid = NULL;
409
410         struct samr_Ids rids;
411         struct samr_Ids types;
412         union samr_GroupInfo info;
413         struct GROUP_INFO_0 *g0;
414         struct GROUP_INFO_1 *g1;
415         struct GROUP_INFO_2 *g2;
416         struct GROUP_INFO_3 *g3;
417         struct GROUP_INFO_1002 *g1002;
418         struct GROUP_INFO_1005 *g1005;
419
420         ZERO_STRUCT(connect_handle);
421         ZERO_STRUCT(domain_handle);
422         ZERO_STRUCT(group_handle);
423
424         if (!r->in.group_name) {
425                 return WERR_INVALID_PARAM;
426         }
427
428         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
429         if (!W_ERROR_IS_OK(werr)) {
430                 goto done;
431         }
432
433         werr = libnetapi_open_pipe(ctx, cli, &ndr_table_samr.syntax_id,
434                                    &pipe_cli);
435         if (!W_ERROR_IS_OK(werr)) {
436                 goto done;
437         }
438
439         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
440                                           SAMR_ACCESS_ENUM_DOMAINS |
441                                           SAMR_ACCESS_OPEN_DOMAIN,
442                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
443                                           &connect_handle,
444                                           &domain_handle,
445                                           &domain_sid);
446         if (!W_ERROR_IS_OK(werr)) {
447                 goto done;
448         }
449
450         init_lsa_String(&lsa_group_name, r->in.group_name);
451
452         status = rpccli_samr_LookupNames(pipe_cli, ctx,
453                                          &domain_handle,
454                                          1,
455                                          &lsa_group_name,
456                                          &rids,
457                                          &types);
458         if (!NT_STATUS_IS_OK(status)) {
459                 werr = ntstatus_to_werror(status);
460                 goto done;
461         }
462
463         if (types.ids[0] != SID_NAME_DOM_GRP) {
464                 werr = WERR_INVALID_DATATYPE;
465                 goto done;
466         }
467
468         status = rpccli_samr_OpenGroup(pipe_cli, ctx,
469                                        &domain_handle,
470                                        SAMR_GROUP_ACCESS_SET_INFO |
471                                        SAMR_GROUP_ACCESS_LOOKUP_INFO,
472                                        rids.ids[0],
473                                        &group_handle);
474         if (!NT_STATUS_IS_OK(status)) {
475                 werr = ntstatus_to_werror(status);
476                 goto done;
477         }
478
479         switch (r->in.level) {
480                 case 0:
481                         g0 = (struct GROUP_INFO_0 *)r->in.buffer;
482                         init_lsa_String(&info.name, g0->grpi0_name);
483                         status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
484                                                           &group_handle,
485                                                           GROUPINFONAME,
486                                                           &info);
487                         break;
488                 case 1:
489                         g1 = (struct GROUP_INFO_1 *)r->in.buffer;
490                         init_lsa_String(&info.description, g1->grpi1_comment);
491                         status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
492                                                           &group_handle,
493                                                           GROUPINFODESCRIPTION,
494                                                           &info);
495                         break;
496                 case 2:
497                         g2 = (struct GROUP_INFO_2 *)r->in.buffer;
498                         init_lsa_String(&info.description, g2->grpi2_comment);
499                         status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
500                                                           &group_handle,
501                                                           GROUPINFODESCRIPTION,
502                                                           &info);
503                         if (!NT_STATUS_IS_OK(status)) {
504                                 werr = ntstatus_to_werror(status);
505                                 goto done;
506                         }
507                         info.attributes.attributes = g2->grpi2_attributes;
508                         status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
509                                                           &group_handle,
510                                                           GROUPINFOATTRIBUTES,
511                                                           &info);
512                         break;
513                 case 3:
514                         g3 = (struct GROUP_INFO_3 *)r->in.buffer;
515                         init_lsa_String(&info.description, g3->grpi3_comment);
516                         status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
517                                                           &group_handle,
518                                                           GROUPINFODESCRIPTION,
519                                                           &info);
520                         if (!NT_STATUS_IS_OK(status)) {
521                                 werr = ntstatus_to_werror(status);
522                                 goto done;
523                         }
524                         info.attributes.attributes = g3->grpi3_attributes;
525                         status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
526                                                           &group_handle,
527                                                           GROUPINFOATTRIBUTES,
528                                                           &info);
529                         break;
530                 case 1002:
531                         g1002 = (struct GROUP_INFO_1002 *)r->in.buffer;
532                         init_lsa_String(&info.description, g1002->grpi1002_comment);
533                         status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
534                                                           &group_handle,
535                                                           GROUPINFODESCRIPTION,
536                                                           &info);
537                         break;
538                 case 1005:
539                         g1005 = (struct GROUP_INFO_1005 *)r->in.buffer;
540                         info.attributes.attributes = g1005->grpi1005_attributes;
541                         status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
542                                                           &group_handle,
543                                                           GROUPINFOATTRIBUTES,
544                                                           &info);
545                         break;
546                 default:
547                         status = NT_STATUS_INVALID_LEVEL;
548                         break;
549         }
550
551         if (!NT_STATUS_IS_OK(status)) {
552                 werr = ntstatus_to_werror(status);
553                 goto done;
554         }
555
556         werr = WERR_OK;
557
558  done:
559         if (!cli) {
560                 return werr;
561         }
562
563         if (is_valid_policy_hnd(&group_handle)) {
564                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
565         }
566
567         if (ctx->disable_policy_handle_cache) {
568                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
569                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
570         }
571
572         return werr;
573 }
574
575 /****************************************************************
576 ****************************************************************/
577
578 WERROR NetGroupSetInfo_l(struct libnetapi_ctx *ctx,
579                          struct NetGroupSetInfo *r)
580 {
581         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupSetInfo);
582 }
583
584 /****************************************************************
585 ****************************************************************/
586
587 static WERROR map_group_info_to_buffer(TALLOC_CTX *mem_ctx,
588                                        uint32_t level,
589                                        struct samr_GroupInfoAll *info,
590                                        struct dom_sid2 *domain_sid,
591                                        uint32_t rid,
592                                        uint8_t **buffer)
593 {
594         struct GROUP_INFO_0 info0;
595         struct GROUP_INFO_1 info1;
596         struct GROUP_INFO_2 info2;
597         struct GROUP_INFO_3 info3;
598         struct dom_sid sid;
599
600         switch (level) {
601                 case 0:
602                         info0.grpi0_name        = info->name.string;
603
604                         *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info0, sizeof(info0));
605
606                         break;
607                 case 1:
608                         info1.grpi1_name        = info->name.string;
609                         info1.grpi1_comment     = info->description.string;
610
611                         *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info1, sizeof(info1));
612
613                         break;
614                 case 2:
615                         info2.grpi2_name        = info->name.string;
616                         info2.grpi2_comment     = info->description.string;
617                         info2.grpi2_group_id    = rid;
618                         info2.grpi2_attributes  = info->attributes;
619
620                         *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info2, sizeof(info2));
621
622                         break;
623                 case 3:
624                         if (!sid_compose(&sid, domain_sid, rid)) {
625                                 return WERR_NOMEM;
626                         }
627
628                         info3.grpi3_name        = info->name.string;
629                         info3.grpi3_comment     = info->description.string;
630                         info3.grpi3_attributes  = info->attributes;
631                         info3.grpi3_group_sid   = (struct domsid *)sid_dup_talloc(mem_ctx, &sid);
632
633                         *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info3, sizeof(info3));
634
635                         break;
636                 default:
637                         return WERR_UNKNOWN_LEVEL;
638         }
639
640         W_ERROR_HAVE_NO_MEMORY(*buffer);
641
642         return WERR_OK;
643 }
644
645 /****************************************************************
646 ****************************************************************/
647
648 WERROR NetGroupGetInfo_r(struct libnetapi_ctx *ctx,
649                          struct NetGroupGetInfo *r)
650 {
651         struct cli_state *cli = NULL;
652         struct rpc_pipe_client *pipe_cli = NULL;
653         NTSTATUS status;
654         WERROR werr;
655         POLICY_HND connect_handle, domain_handle, group_handle;
656         struct lsa_String lsa_group_name;
657         struct dom_sid2 *domain_sid = NULL;
658
659         struct samr_Ids rids;
660         struct samr_Ids types;
661         union samr_GroupInfo *info = NULL;
662         bool group_info_all = false;
663
664         ZERO_STRUCT(connect_handle);
665         ZERO_STRUCT(domain_handle);
666         ZERO_STRUCT(group_handle);
667
668         if (!r->in.group_name) {
669                 return WERR_INVALID_PARAM;
670         }
671
672         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
673         if (!W_ERROR_IS_OK(werr)) {
674                 goto done;
675         }
676
677         werr = libnetapi_open_pipe(ctx, cli, &ndr_table_samr.syntax_id,
678                                    &pipe_cli);
679         if (!W_ERROR_IS_OK(werr)) {
680                 goto done;
681         }
682
683         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
684                                           SAMR_ACCESS_ENUM_DOMAINS |
685                                           SAMR_ACCESS_OPEN_DOMAIN,
686                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
687                                           &connect_handle,
688                                           &domain_handle,
689                                           &domain_sid);
690         if (!W_ERROR_IS_OK(werr)) {
691                 goto done;
692         }
693
694         init_lsa_String(&lsa_group_name, r->in.group_name);
695
696         status = rpccli_samr_LookupNames(pipe_cli, ctx,
697                                          &domain_handle,
698                                          1,
699                                          &lsa_group_name,
700                                          &rids,
701                                          &types);
702         if (!NT_STATUS_IS_OK(status)) {
703                 werr = ntstatus_to_werror(status);
704                 goto done;
705         }
706
707         if (types.ids[0] != SID_NAME_DOM_GRP) {
708                 werr = WERR_INVALID_DATATYPE;
709                 goto done;
710         }
711
712         status = rpccli_samr_OpenGroup(pipe_cli, ctx,
713                                        &domain_handle,
714                                        SAMR_GROUP_ACCESS_LOOKUP_INFO,
715                                        rids.ids[0],
716                                        &group_handle);
717         if (!NT_STATUS_IS_OK(status)) {
718                 werr = ntstatus_to_werror(status);
719                 goto done;
720         }
721
722         status = rpccli_samr_QueryGroupInfo(pipe_cli, ctx,
723                                             &group_handle,
724                                             GROUPINFOALL2,
725                                             &info);
726         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
727                 status = rpccli_samr_QueryGroupInfo(pipe_cli, ctx,
728                                                     &group_handle,
729                                                     GROUPINFOALL,
730                                                     &info);
731                 group_info_all = true;
732         }
733
734         if (!NT_STATUS_IS_OK(status)) {
735                 werr = ntstatus_to_werror(status);
736                 goto done;
737         }
738
739         werr = map_group_info_to_buffer(ctx, r->in.level,
740                                         group_info_all ? &info->all : &info->all2,
741                                         domain_sid, rids.ids[0],
742                                         r->out.buffer);
743         if (!W_ERROR_IS_OK(werr)) {
744                 goto done;
745         }
746  done:
747         if (!cli) {
748                 return werr;
749         }
750
751         if (is_valid_policy_hnd(&group_handle)) {
752                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
753         }
754
755         if (ctx->disable_policy_handle_cache) {
756                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
757                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
758         }
759
760         return werr;
761 }
762
763 /****************************************************************
764 ****************************************************************/
765
766 WERROR NetGroupGetInfo_l(struct libnetapi_ctx *ctx,
767                          struct NetGroupGetInfo *r)
768 {
769         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupGetInfo);
770 }
771
772 /****************************************************************
773 ****************************************************************/
774
775 WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx,
776                          struct NetGroupAddUser *r)
777 {
778         struct cli_state *cli = NULL;
779         struct rpc_pipe_client *pipe_cli = NULL;
780         NTSTATUS status;
781         WERROR werr;
782         POLICY_HND connect_handle, domain_handle, group_handle;
783         struct lsa_String lsa_group_name, lsa_user_name;
784         struct dom_sid2 *domain_sid = NULL;
785
786         struct samr_Ids rids;
787         struct samr_Ids types;
788
789         ZERO_STRUCT(connect_handle);
790         ZERO_STRUCT(domain_handle);
791         ZERO_STRUCT(group_handle);
792
793         if (!r->in.group_name) {
794                 return WERR_INVALID_PARAM;
795         }
796
797         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
798         if (!W_ERROR_IS_OK(werr)) {
799                 goto done;
800         }
801
802         werr = libnetapi_open_pipe(ctx, cli, &ndr_table_samr.syntax_id,
803                                    &pipe_cli);
804         if (!W_ERROR_IS_OK(werr)) {
805                 goto done;
806         }
807
808         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
809                                           SAMR_ACCESS_ENUM_DOMAINS |
810                                           SAMR_ACCESS_OPEN_DOMAIN,
811                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
812                                           &connect_handle,
813                                           &domain_handle,
814                                           &domain_sid);
815         if (!W_ERROR_IS_OK(werr)) {
816                 goto done;
817         }
818
819         init_lsa_String(&lsa_group_name, r->in.group_name);
820
821         status = rpccli_samr_LookupNames(pipe_cli, ctx,
822                                          &domain_handle,
823                                          1,
824                                          &lsa_group_name,
825                                          &rids,
826                                          &types);
827         if (!NT_STATUS_IS_OK(status)) {
828                 werr = WERR_GROUP_NOT_FOUND;
829                 goto done;
830         }
831
832         if (types.ids[0] != SID_NAME_DOM_GRP) {
833                 werr = WERR_GROUP_NOT_FOUND;
834                 goto done;
835         }
836
837         status = rpccli_samr_OpenGroup(pipe_cli, ctx,
838                                        &domain_handle,
839                                        SAMR_GROUP_ACCESS_ADD_MEMBER,
840                                        rids.ids[0],
841                                        &group_handle);
842         if (!NT_STATUS_IS_OK(status)) {
843                 werr = ntstatus_to_werror(status);
844                 goto done;
845         }
846
847         init_lsa_String(&lsa_user_name, r->in.user_name);
848
849         status = rpccli_samr_LookupNames(pipe_cli, ctx,
850                                          &domain_handle,
851                                          1,
852                                          &lsa_user_name,
853                                          &rids,
854                                          &types);
855         if (!NT_STATUS_IS_OK(status)) {
856                 werr = WERR_USER_NOT_FOUND;
857                 goto done;
858         }
859
860         if (types.ids[0] != SID_NAME_USER) {
861                 werr = WERR_USER_NOT_FOUND;
862                 goto done;
863         }
864
865         status = rpccli_samr_AddGroupMember(pipe_cli, ctx,
866                                             &group_handle,
867                                             rids.ids[0],
868                                             7); /* why ? */
869         if (!NT_STATUS_IS_OK(status)) {
870                 werr = ntstatus_to_werror(status);
871                 goto done;
872         }
873
874         werr = WERR_OK;
875
876  done:
877         if (!cli) {
878                 return werr;
879         }
880
881         if (is_valid_policy_hnd(&group_handle)) {
882                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
883         }
884
885         if (ctx->disable_policy_handle_cache) {
886                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
887                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
888         }
889
890         return werr;
891 }
892
893 /****************************************************************
894 ****************************************************************/
895
896 WERROR NetGroupAddUser_l(struct libnetapi_ctx *ctx,
897                          struct NetGroupAddUser *r)
898 {
899         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupAddUser);
900 }
901
902 /****************************************************************
903 ****************************************************************/
904
905 WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx,
906                          struct NetGroupDelUser *r)
907 {
908         struct cli_state *cli = NULL;
909         struct rpc_pipe_client *pipe_cli = NULL;
910         NTSTATUS status;
911         WERROR werr;
912         POLICY_HND connect_handle, domain_handle, group_handle;
913         struct lsa_String lsa_group_name, lsa_user_name;
914         struct dom_sid2 *domain_sid = NULL;
915
916         struct samr_Ids rids;
917         struct samr_Ids types;
918
919         ZERO_STRUCT(connect_handle);
920         ZERO_STRUCT(domain_handle);
921         ZERO_STRUCT(group_handle);
922
923         if (!r->in.group_name) {
924                 return WERR_INVALID_PARAM;
925         }
926
927         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
928         if (!W_ERROR_IS_OK(werr)) {
929                 goto done;
930         }
931
932         werr = libnetapi_open_pipe(ctx, cli, &ndr_table_samr.syntax_id,
933                                    &pipe_cli);
934         if (!W_ERROR_IS_OK(werr)) {
935                 goto done;
936         }
937
938         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
939                                           SAMR_ACCESS_ENUM_DOMAINS |
940                                           SAMR_ACCESS_OPEN_DOMAIN,
941                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
942                                           &connect_handle,
943                                           &domain_handle,
944                                           &domain_sid);
945         if (!W_ERROR_IS_OK(werr)) {
946                 goto done;
947         }
948
949         init_lsa_String(&lsa_group_name, r->in.group_name);
950
951         status = rpccli_samr_LookupNames(pipe_cli, ctx,
952                                          &domain_handle,
953                                          1,
954                                          &lsa_group_name,
955                                          &rids,
956                                          &types);
957         if (!NT_STATUS_IS_OK(status)) {
958                 werr = WERR_GROUP_NOT_FOUND;
959                 goto done;
960         }
961
962         if (types.ids[0] != SID_NAME_DOM_GRP) {
963                 werr = WERR_GROUP_NOT_FOUND;
964                 goto done;
965         }
966
967         status = rpccli_samr_OpenGroup(pipe_cli, ctx,
968                                        &domain_handle,
969                                        SAMR_GROUP_ACCESS_REMOVE_MEMBER,
970                                        rids.ids[0],
971                                        &group_handle);
972         if (!NT_STATUS_IS_OK(status)) {
973                 werr = ntstatus_to_werror(status);
974                 goto done;
975         }
976
977         init_lsa_String(&lsa_user_name, r->in.user_name);
978
979         status = rpccli_samr_LookupNames(pipe_cli, ctx,
980                                          &domain_handle,
981                                          1,
982                                          &lsa_user_name,
983                                          &rids,
984                                          &types);
985         if (!NT_STATUS_IS_OK(status)) {
986                 werr = WERR_USER_NOT_FOUND;
987                 goto done;
988         }
989
990         if (types.ids[0] != SID_NAME_USER) {
991                 werr = WERR_USER_NOT_FOUND;
992                 goto done;
993         }
994
995         status = rpccli_samr_DeleteGroupMember(pipe_cli, ctx,
996                                                &group_handle,
997                                                rids.ids[0]);
998         if (!NT_STATUS_IS_OK(status)) {
999                 werr = ntstatus_to_werror(status);
1000                 goto done;
1001         }
1002
1003         werr = WERR_OK;
1004
1005  done:
1006         if (!cli) {
1007                 return werr;
1008         }
1009
1010         if (is_valid_policy_hnd(&group_handle)) {
1011                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
1012         }
1013
1014         if (ctx->disable_policy_handle_cache) {
1015                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
1016                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
1017         }
1018
1019         return werr;
1020 }
1021
1022 /****************************************************************
1023 ****************************************************************/
1024
1025 WERROR NetGroupDelUser_l(struct libnetapi_ctx *ctx,
1026                          struct NetGroupDelUser *r)
1027 {
1028         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupDelUser);
1029 }
1030
1031 /****************************************************************
1032 ****************************************************************/
1033
1034 static WERROR convert_samr_disp_groups_to_GROUP_INFO_0_buffer(TALLOC_CTX *mem_ctx,
1035                                                               struct samr_DispInfoFullGroups *groups,
1036                                                               uint8_t **buffer)
1037 {
1038         struct GROUP_INFO_0 *g0;
1039         int i;
1040
1041         g0 = TALLOC_ZERO_ARRAY(mem_ctx, struct GROUP_INFO_0, groups->count);
1042         W_ERROR_HAVE_NO_MEMORY(g0);
1043
1044         for (i=0; i<groups->count; i++) {
1045                 g0[i].grpi0_name = talloc_strdup(mem_ctx,
1046                         groups->entries[i].account_name.string);
1047                 W_ERROR_HAVE_NO_MEMORY(g0[i].grpi0_name);
1048         }
1049
1050         *buffer = (uint8_t *)talloc_memdup(mem_ctx, g0,
1051                                            sizeof(struct GROUP_INFO_0) * groups->count);
1052         W_ERROR_HAVE_NO_MEMORY(*buffer);
1053
1054         return WERR_OK;
1055 }
1056
1057 /****************************************************************
1058 ****************************************************************/
1059
1060 static WERROR convert_samr_disp_groups_to_GROUP_INFO_1_buffer(TALLOC_CTX *mem_ctx,
1061                                                               struct samr_DispInfoFullGroups *groups,
1062                                                               uint8_t **buffer)
1063 {
1064         struct GROUP_INFO_1 *g1;
1065         int i;
1066
1067         g1 = TALLOC_ZERO_ARRAY(mem_ctx, struct GROUP_INFO_1, groups->count);
1068         W_ERROR_HAVE_NO_MEMORY(g1);
1069
1070         for (i=0; i<groups->count; i++) {
1071                 g1[i].grpi1_name = talloc_strdup(mem_ctx,
1072                         groups->entries[i].account_name.string);
1073                 g1[i].grpi1_comment = talloc_strdup(mem_ctx,
1074                         groups->entries[i].description.string);
1075                 W_ERROR_HAVE_NO_MEMORY(g1[i].grpi1_name);
1076         }
1077
1078         *buffer = (uint8_t *)talloc_memdup(mem_ctx, g1,
1079                                            sizeof(struct GROUP_INFO_1) * groups->count);
1080         W_ERROR_HAVE_NO_MEMORY(*buffer);
1081
1082         return WERR_OK;
1083 }
1084
1085 /****************************************************************
1086 ****************************************************************/
1087
1088 static WERROR convert_samr_disp_groups_to_GROUP_INFO_2_buffer(TALLOC_CTX *mem_ctx,
1089                                                               struct samr_DispInfoFullGroups *groups,
1090                                                               uint8_t **buffer)
1091 {
1092         struct GROUP_INFO_2 *g2;
1093         int i;
1094
1095         g2 = TALLOC_ZERO_ARRAY(mem_ctx, struct GROUP_INFO_2, groups->count);
1096         W_ERROR_HAVE_NO_MEMORY(g2);
1097
1098         for (i=0; i<groups->count; i++) {
1099                 g2[i].grpi2_name = talloc_strdup(mem_ctx,
1100                         groups->entries[i].account_name.string);
1101                 g2[i].grpi2_comment = talloc_strdup(mem_ctx,
1102                         groups->entries[i].description.string);
1103                 g2[i].grpi2_group_id = groups->entries[i].rid;
1104                 g2[i].grpi2_attributes = groups->entries[i].acct_flags;
1105                 W_ERROR_HAVE_NO_MEMORY(g2[i].grpi2_name);
1106         }
1107
1108         *buffer = (uint8_t *)talloc_memdup(mem_ctx, g2,
1109                                            sizeof(struct GROUP_INFO_2) * groups->count);
1110         W_ERROR_HAVE_NO_MEMORY(*buffer);
1111
1112         return WERR_OK;
1113 }
1114
1115 /****************************************************************
1116 ****************************************************************/
1117
1118 static WERROR convert_samr_disp_groups_to_GROUP_INFO_3_buffer(TALLOC_CTX *mem_ctx,
1119                                                               struct samr_DispInfoFullGroups *groups,
1120                                                               const struct dom_sid *domain_sid,
1121                                                               uint8_t **buffer)
1122 {
1123         struct GROUP_INFO_3 *g3;
1124         int i;
1125
1126         g3 = TALLOC_ZERO_ARRAY(mem_ctx, struct GROUP_INFO_3, groups->count);
1127         W_ERROR_HAVE_NO_MEMORY(g3);
1128
1129         for (i=0; i<groups->count; i++) {
1130
1131                 struct dom_sid sid;
1132
1133                 if (!sid_compose(&sid, domain_sid, groups->entries[i].rid)) {
1134                         return WERR_NOMEM;
1135                 }
1136
1137                 g3[i].grpi3_name = talloc_strdup(mem_ctx,
1138                         groups->entries[i].account_name.string);
1139                 g3[i].grpi3_comment = talloc_strdup(mem_ctx,
1140                         groups->entries[i].description.string);
1141                 g3[i].grpi3_group_sid = (struct domsid *)sid_dup_talloc(mem_ctx, &sid);
1142                 g3[i].grpi3_attributes = groups->entries[i].acct_flags;
1143                 W_ERROR_HAVE_NO_MEMORY(g3[i].grpi3_name);
1144         }
1145
1146         *buffer = (uint8_t *)talloc_memdup(mem_ctx, g3,
1147                                            sizeof(struct GROUP_INFO_3) * groups->count);
1148         W_ERROR_HAVE_NO_MEMORY(*buffer);
1149
1150         return WERR_OK;
1151 }
1152
1153 /****************************************************************
1154 ****************************************************************/
1155
1156 static WERROR convert_samr_disp_groups_to_GROUP_INFO_buffer(TALLOC_CTX *mem_ctx,
1157                                                             uint32_t level,
1158                                                             struct samr_DispInfoFullGroups *groups,
1159                                                             const struct dom_sid *domain_sid,
1160                                                             uint32_t *entries_read,
1161                                                             uint8_t **buffer)
1162 {
1163         if (entries_read) {
1164                 *entries_read = groups->count;
1165         }
1166
1167         switch (level) {
1168                 case 0:
1169                         return convert_samr_disp_groups_to_GROUP_INFO_0_buffer(mem_ctx, groups, buffer);
1170                 case 1:
1171                         return convert_samr_disp_groups_to_GROUP_INFO_1_buffer(mem_ctx, groups, buffer);
1172                 case 2:
1173                         return convert_samr_disp_groups_to_GROUP_INFO_2_buffer(mem_ctx, groups, buffer);
1174                 case 3:
1175                         return convert_samr_disp_groups_to_GROUP_INFO_3_buffer(mem_ctx, groups, domain_sid, buffer);
1176                 default:
1177                         return WERR_UNKNOWN_LEVEL;
1178         }
1179 }
1180
1181 /****************************************************************
1182 ****************************************************************/
1183
1184 WERROR NetGroupEnum_r(struct libnetapi_ctx *ctx,
1185                       struct NetGroupEnum *r)
1186 {
1187         struct cli_state *cli = NULL;
1188         struct rpc_pipe_client *pipe_cli = NULL;
1189         struct policy_handle connect_handle;
1190         struct dom_sid2 *domain_sid = NULL;
1191         struct policy_handle domain_handle;
1192         union samr_DispInfo info;
1193         union samr_DomainInfo *domain_info = NULL;
1194
1195         uint32_t total_size = 0;
1196         uint32_t returned_size = 0;
1197
1198         NTSTATUS status = NT_STATUS_OK;
1199         WERROR werr, tmp_werr;
1200
1201         ZERO_STRUCT(connect_handle);
1202         ZERO_STRUCT(domain_handle);
1203
1204         switch (r->in.level) {
1205                 case 0:
1206                 case 1:
1207                 case 2:
1208                 case 3:
1209                         break;
1210                 default:
1211                         return WERR_UNKNOWN_LEVEL;
1212         }
1213
1214         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
1215         if (!W_ERROR_IS_OK(werr)) {
1216                 goto done;
1217         }
1218
1219         werr = libnetapi_open_pipe(ctx, cli, &ndr_table_samr.syntax_id,
1220                                    &pipe_cli);
1221         if (!W_ERROR_IS_OK(werr)) {
1222                 goto done;
1223         }
1224
1225         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
1226                                           SAMR_ACCESS_ENUM_DOMAINS |
1227                                           SAMR_ACCESS_OPEN_DOMAIN,
1228                                           SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 |
1229                                           SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS |
1230                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1231                                           &connect_handle,
1232                                           &domain_handle,
1233                                           &domain_sid);
1234         if (!W_ERROR_IS_OK(werr)) {
1235                 goto done;
1236         }
1237
1238         status = rpccli_samr_QueryDomainInfo(pipe_cli, ctx,
1239                                              &domain_handle,
1240                                              2,
1241                                              &domain_info);
1242         if (!NT_STATUS_IS_OK(status)) {
1243                 werr = ntstatus_to_werror(status);
1244                 goto done;
1245         }
1246
1247         if (r->out.total_entries) {
1248                 *r->out.total_entries = domain_info->info2.num_groups;
1249         }
1250
1251         status = rpccli_samr_QueryDisplayInfo2(pipe_cli,
1252                                                ctx,
1253                                                &domain_handle,
1254                                                3,
1255                                                r->in.resume_handle ?
1256                                                *r->in.resume_handle : 0,
1257                                                (uint32_t)-1,
1258                                                r->in.prefmaxlen,
1259                                                &total_size,
1260                                                &returned_size,
1261                                                &info);
1262         werr = ntstatus_to_werror(status);
1263         if (NT_STATUS_IS_ERR(status)) {
1264                 goto done;
1265         }
1266
1267         if (r->out.resume_handle) {
1268                 *r->out.resume_handle =
1269                         info.info3.entries[info.info3.count-1].idx;
1270         }
1271
1272         tmp_werr = convert_samr_disp_groups_to_GROUP_INFO_buffer(ctx,
1273                                                                  r->in.level,
1274                                                                  &info.info3,
1275                                                                  domain_sid,
1276                                                                  r->out.entries_read,
1277                                                                  r->out.buffer);
1278         if (!W_ERROR_IS_OK(tmp_werr)) {
1279                 werr = tmp_werr;
1280                 goto done;
1281         }
1282
1283  done:
1284         if (!cli) {
1285                 return werr;
1286         }
1287
1288         /* if last query */
1289         if (NT_STATUS_IS_OK(status) ||
1290             NT_STATUS_IS_ERR(status)) {
1291
1292                 if (ctx->disable_policy_handle_cache) {
1293                         libnetapi_samr_close_domain_handle(ctx, &domain_handle);
1294                         libnetapi_samr_close_connect_handle(ctx, &connect_handle);
1295                 }
1296         }
1297
1298         return werr;
1299 }
1300
1301 /****************************************************************
1302 ****************************************************************/
1303
1304 WERROR NetGroupEnum_l(struct libnetapi_ctx *ctx,
1305                       struct NetGroupEnum *r)
1306 {
1307         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupEnum);
1308 }
1309
1310 /****************************************************************
1311 ****************************************************************/
1312
1313 WERROR NetGroupGetUsers_r(struct libnetapi_ctx *ctx,
1314                           struct NetGroupGetUsers *r)
1315 {
1316         return WERR_NOT_SUPPORTED;
1317 }
1318
1319 /****************************************************************
1320 ****************************************************************/
1321
1322 WERROR NetGroupGetUsers_l(struct libnetapi_ctx *ctx,
1323                           struct NetGroupGetUsers *r)
1324 {
1325         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupGetUsers);
1326 }