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