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