ce9df27181cd93ab316a0e30b9ac16bf283f3aff
[samba.git] / source3 / lib / netapi / localgroup.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  NetApi LocalGroup Support
4  *  Copyright (C) Guenther Deschner 2008
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21
22 #include "librpc/gen_ndr/libnetapi.h"
23 #include "lib/netapi/netapi.h"
24 #include "lib/netapi/netapi_private.h"
25 #include "lib/netapi/libnetapi.h"
26 #include "../librpc/gen_ndr/ndr_samr_c.h"
27 #include "../librpc/gen_ndr/ndr_lsa_c.h"
28 #include "rpc_client/cli_lsarpc.h"
29 #include "rpc_client/init_lsa.h"
30 #include "../libcli/security/security.h"
31
32 static NTSTATUS libnetapi_samr_lookup_and_open_alias(TALLOC_CTX *mem_ctx,
33                                                      struct rpc_pipe_client *pipe_cli,
34                                                      struct policy_handle *domain_handle,
35                                                      const char *group_name,
36                                                      uint32_t access_rights,
37                                                      struct policy_handle *alias_handle)
38 {
39         NTSTATUS status, result;
40
41         struct lsa_String lsa_account_name;
42         struct samr_Ids user_rids, name_types;
43         struct dcerpc_binding_handle *b = pipe_cli->binding_handle;
44
45         init_lsa_String(&lsa_account_name, group_name);
46
47         status = dcerpc_samr_LookupNames(b, mem_ctx,
48                                          domain_handle,
49                                          1,
50                                          &lsa_account_name,
51                                          &user_rids,
52                                          &name_types,
53                                          &result);
54         if (!NT_STATUS_IS_OK(status)) {
55                 return status;
56         }
57         if (!NT_STATUS_IS_OK(result)) {
58                 return result;
59         }
60
61         switch (name_types.ids[0]) {
62                 case SID_NAME_ALIAS:
63                 case SID_NAME_WKN_GRP:
64                         break;
65                 default:
66                         return NT_STATUS_INVALID_SID;
67         }
68
69         status = dcerpc_samr_OpenAlias(b, mem_ctx,
70                                        domain_handle,
71                                        access_rights,
72                                        user_rids.ids[0],
73                                        alias_handle,
74                                        &result);
75         if (!NT_STATUS_IS_OK(status)) {
76                 return status;
77         }
78
79         return result;
80 }
81
82 /****************************************************************
83 ****************************************************************/
84
85 static NTSTATUS libnetapi_samr_open_alias_queryinfo(TALLOC_CTX *mem_ctx,
86                                                     struct rpc_pipe_client *pipe_cli,
87                                                     struct policy_handle *handle,
88                                                     uint32_t rid,
89                                                     uint32_t access_rights,
90                                                     enum samr_AliasInfoEnum level,
91                                                     union samr_AliasInfo **alias_info)
92 {
93         NTSTATUS status, result;
94         struct policy_handle alias_handle;
95         union samr_AliasInfo *_alias_info = NULL;
96         struct dcerpc_binding_handle *b = pipe_cli->binding_handle;
97
98         ZERO_STRUCT(alias_handle);
99
100         status = dcerpc_samr_OpenAlias(b, mem_ctx,
101                                        handle,
102                                        access_rights,
103                                        rid,
104                                        &alias_handle,
105                                        &result);
106         if (!NT_STATUS_IS_OK(status)) {
107                 goto done;
108         }
109         if (!NT_STATUS_IS_OK(result)) {
110                 status = result;
111                 goto done;
112         }
113
114         status = dcerpc_samr_QueryAliasInfo(b, mem_ctx,
115                                             &alias_handle,
116                                             level,
117                                             &_alias_info,
118                                             &result);
119         if (!NT_STATUS_IS_OK(status)) {
120                 goto done;
121         }
122         if (!NT_STATUS_IS_OK(result)) {
123                 status = result;
124                 goto done;
125         }
126
127         *alias_info = _alias_info;
128
129  done:
130         if (is_valid_policy_hnd(&alias_handle)) {
131                 dcerpc_samr_Close(b, mem_ctx, &alias_handle, &result);
132         }
133
134         return status;
135 }
136
137 /****************************************************************
138 ****************************************************************/
139
140 WERROR NetLocalGroupAdd_r(struct libnetapi_ctx *ctx,
141                           struct NetLocalGroupAdd *r)
142 {
143         struct rpc_pipe_client *pipe_cli = NULL;
144         NTSTATUS status, result;
145         WERROR werr;
146         struct lsa_String lsa_account_name;
147         struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
148         struct dom_sid2 *domain_sid = NULL;
149         uint32_t rid;
150         struct dcerpc_binding_handle *b = NULL;
151
152         struct LOCALGROUP_INFO_0 *info0 = NULL;
153         struct LOCALGROUP_INFO_1 *info1 = NULL;
154
155         const char *alias_name = NULL;
156
157         if (!r->in.buffer) {
158                 return WERR_INVALID_PARAM;
159         }
160
161         switch (r->in.level) {
162                 case 0:
163                         info0 = (struct LOCALGROUP_INFO_0 *)r->in.buffer;
164                         alias_name = info0->lgrpi0_name;
165                         break;
166                 case 1:
167                         info1 = (struct LOCALGROUP_INFO_1 *)r->in.buffer;
168                         alias_name = info1->lgrpi1_name;
169                         break;
170                 default:
171                         werr = WERR_UNKNOWN_LEVEL;
172                         goto done;
173         }
174
175         ZERO_STRUCT(connect_handle);
176         ZERO_STRUCT(builtin_handle);
177         ZERO_STRUCT(domain_handle);
178         ZERO_STRUCT(alias_handle);
179
180         werr = libnetapi_open_pipe(ctx, r->in.server_name,
181                                    &ndr_table_samr.syntax_id,
182                                    &pipe_cli);
183         if (!W_ERROR_IS_OK(werr)) {
184                 goto done;
185         }
186
187         b = pipe_cli->binding_handle;
188
189         werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
190                                                   SAMR_ACCESS_LOOKUP_DOMAIN |
191                                                   SAMR_ACCESS_ENUM_DOMAINS,
192                                                   SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
193                                                   &connect_handle,
194                                                   &builtin_handle);
195         if (!W_ERROR_IS_OK(werr)) {
196                 goto done;
197         }
198
199         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
200                                                       &builtin_handle,
201                                                       alias_name,
202                                                       SAMR_ALIAS_ACCESS_LOOKUP_INFO,
203                                                       &alias_handle);
204         if (ctx->disable_policy_handle_cache) {
205                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
206         }
207
208         if (NT_STATUS_IS_OK(status)) {
209                 werr = WERR_ALIAS_EXISTS;
210                 goto done;
211         }
212
213         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
214                                           SAMR_ACCESS_ENUM_DOMAINS |
215                                           SAMR_ACCESS_LOOKUP_DOMAIN,
216                                           SAMR_DOMAIN_ACCESS_CREATE_ALIAS |
217                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
218                                           &connect_handle,
219                                           &domain_handle,
220                                           &domain_sid);
221         if (!W_ERROR_IS_OK(werr)) {
222                 goto done;
223         }
224
225         init_lsa_String(&lsa_account_name, alias_name);
226
227         status = dcerpc_samr_CreateDomAlias(b, talloc_tos(),
228                                             &domain_handle,
229                                             &lsa_account_name,
230                                             SEC_STD_DELETE |
231                                             SAMR_ALIAS_ACCESS_SET_INFO,
232                                             &alias_handle,
233                                             &rid,
234                                             &result);
235         if (!NT_STATUS_IS_OK(status)) {
236                 werr = ntstatus_to_werror(status);
237                 goto done;
238         }
239         if (!NT_STATUS_IS_OK(result)) {
240                 werr = ntstatus_to_werror(result);
241                 goto done;
242         }
243
244
245         if (r->in.level == 1 && info1->lgrpi1_comment) {
246
247                 union samr_AliasInfo alias_info;
248
249                 init_lsa_String(&alias_info.description, info1->lgrpi1_comment);
250
251                 status = dcerpc_samr_SetAliasInfo(b, talloc_tos(),
252                                                   &alias_handle,
253                                                   ALIASINFODESCRIPTION,
254                                                   &alias_info,
255                                                   &result);
256                 if (!NT_STATUS_IS_OK(status)) {
257                         werr = ntstatus_to_werror(status);
258                         goto done;
259                 }
260                 if (!NT_STATUS_IS_OK(result)) {
261                         werr = ntstatus_to_werror(result);
262                         goto done;
263                 }
264         }
265
266         werr = WERR_OK;
267
268  done:
269         if (is_valid_policy_hnd(&alias_handle)) {
270                 dcerpc_samr_Close(b, talloc_tos(), &alias_handle, &result);
271         }
272
273         if (ctx->disable_policy_handle_cache) {
274                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
275                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
276                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
277         }
278
279         return werr;
280 }
281
282 /****************************************************************
283 ****************************************************************/
284
285 WERROR NetLocalGroupAdd_l(struct libnetapi_ctx *ctx,
286                           struct NetLocalGroupAdd *r)
287 {
288         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupAdd);
289 }
290
291 /****************************************************************
292 ****************************************************************/
293
294
295 WERROR NetLocalGroupDel_r(struct libnetapi_ctx *ctx,
296                           struct NetLocalGroupDel *r)
297 {
298         struct rpc_pipe_client *pipe_cli = NULL;
299         NTSTATUS status, result;
300         WERROR werr;
301         struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
302         struct dom_sid2 *domain_sid = NULL;
303         struct dcerpc_binding_handle *b = NULL;
304
305         if (!r->in.group_name) {
306                 return WERR_INVALID_PARAM;
307         }
308
309         ZERO_STRUCT(connect_handle);
310         ZERO_STRUCT(builtin_handle);
311         ZERO_STRUCT(domain_handle);
312         ZERO_STRUCT(alias_handle);
313
314         werr = libnetapi_open_pipe(ctx, r->in.server_name,
315                                    &ndr_table_samr.syntax_id,
316                                    &pipe_cli);
317         if (!W_ERROR_IS_OK(werr)) {
318                 goto done;
319         }
320
321         b = pipe_cli->binding_handle;
322
323         werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
324                                                   SAMR_ACCESS_LOOKUP_DOMAIN |
325                                                   SAMR_ACCESS_ENUM_DOMAINS,
326                                                   SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
327                                                   &connect_handle,
328                                                   &builtin_handle);
329         if (!W_ERROR_IS_OK(werr)) {
330                 goto done;
331         }
332
333         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
334                                                       &builtin_handle,
335                                                       r->in.group_name,
336                                                       SEC_STD_DELETE,
337                                                       &alias_handle);
338
339         if (ctx->disable_policy_handle_cache) {
340                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
341         }
342
343         if (NT_STATUS_IS_OK(status)) {
344                 goto delete_alias;
345         }
346
347         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
348                                           SAMR_ACCESS_ENUM_DOMAINS |
349                                           SAMR_ACCESS_LOOKUP_DOMAIN,
350                                           SAMR_DOMAIN_ACCESS_CREATE_ALIAS |
351                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
352                                           &connect_handle,
353                                           &domain_handle,
354                                           &domain_sid);
355         if (!W_ERROR_IS_OK(werr)) {
356                 goto done;
357         }
358
359         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
360                                                       &domain_handle,
361                                                       r->in.group_name,
362                                                       SEC_STD_DELETE,
363                                                       &alias_handle);
364
365         if (ctx->disable_policy_handle_cache) {
366                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
367         }
368
369         if (!NT_STATUS_IS_OK(status)) {
370                 werr = ntstatus_to_werror(status);
371                 goto done;
372         }
373
374
375  delete_alias:
376         status = dcerpc_samr_DeleteDomAlias(b, talloc_tos(),
377                                             &alias_handle,
378                                             &result);
379         if (!NT_STATUS_IS_OK(status)) {
380                 werr = ntstatus_to_werror(status);
381                 goto done;
382         }
383         if (!NT_STATUS_IS_OK(result)) {
384                 werr = ntstatus_to_werror(result);
385                 goto done;
386         }
387
388         ZERO_STRUCT(alias_handle);
389
390         werr = WERR_OK;
391
392  done:
393         if (is_valid_policy_hnd(&alias_handle)) {
394                 dcerpc_samr_Close(b, talloc_tos(), &alias_handle, &result);
395         }
396
397         if (ctx->disable_policy_handle_cache) {
398                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
399                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
400                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
401         }
402
403         return werr;
404 }
405
406 /****************************************************************
407 ****************************************************************/
408
409 WERROR NetLocalGroupDel_l(struct libnetapi_ctx *ctx,
410                           struct NetLocalGroupDel *r)
411 {
412         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupDel);
413 }
414
415 /****************************************************************
416 ****************************************************************/
417
418 static WERROR map_alias_info_to_buffer(TALLOC_CTX *mem_ctx,
419                                        const char *alias_name,
420                                        struct samr_AliasInfoAll *info,
421                                        uint32_t level,
422                                        uint32_t *entries_read,
423                                        uint8_t **buffer)
424 {
425         struct LOCALGROUP_INFO_0 g0;
426         struct LOCALGROUP_INFO_1 g1;
427         struct LOCALGROUP_INFO_1002 g1002;
428
429         switch (level) {
430                 case 0:
431                         g0.lgrpi0_name          = talloc_strdup(mem_ctx, alias_name);
432                         W_ERROR_HAVE_NO_MEMORY(g0.lgrpi0_name);
433
434                         ADD_TO_ARRAY(mem_ctx, struct LOCALGROUP_INFO_0, g0,
435                                      (struct LOCALGROUP_INFO_0 **)buffer, entries_read);
436
437                         break;
438                 case 1:
439                         g1.lgrpi1_name          = talloc_strdup(mem_ctx, alias_name);
440                         g1.lgrpi1_comment       = talloc_strdup(mem_ctx, info->description.string);
441                         W_ERROR_HAVE_NO_MEMORY(g1.lgrpi1_name);
442
443                         ADD_TO_ARRAY(mem_ctx, struct LOCALGROUP_INFO_1, g1,
444                                      (struct LOCALGROUP_INFO_1 **)buffer, entries_read);
445
446                         break;
447                 case 1002:
448                         g1002.lgrpi1002_comment = talloc_strdup(mem_ctx, info->description.string);
449
450                         ADD_TO_ARRAY(mem_ctx, struct LOCALGROUP_INFO_1002, g1002,
451                                      (struct LOCALGROUP_INFO_1002 **)buffer, entries_read);
452
453                         break;
454                 default:
455                         return WERR_UNKNOWN_LEVEL;
456         }
457
458         return WERR_OK;
459 }
460
461 /****************************************************************
462 ****************************************************************/
463
464 WERROR NetLocalGroupGetInfo_r(struct libnetapi_ctx *ctx,
465                               struct NetLocalGroupGetInfo *r)
466 {
467         struct rpc_pipe_client *pipe_cli = NULL;
468         NTSTATUS status, result;
469         WERROR werr;
470         struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
471         struct dom_sid2 *domain_sid = NULL;
472         union samr_AliasInfo *alias_info = NULL;
473         uint32_t entries_read = 0;
474         struct dcerpc_binding_handle *b = NULL;
475
476         if (!r->in.group_name) {
477                 return WERR_INVALID_PARAM;
478         }
479
480         switch (r->in.level) {
481                 case 0:
482                 case 1:
483                 case 1002:
484                         break;
485                 default:
486                         return WERR_UNKNOWN_LEVEL;
487         }
488
489         ZERO_STRUCT(connect_handle);
490         ZERO_STRUCT(builtin_handle);
491         ZERO_STRUCT(domain_handle);
492         ZERO_STRUCT(alias_handle);
493
494         werr = libnetapi_open_pipe(ctx, r->in.server_name,
495                                    &ndr_table_samr.syntax_id,
496                                    &pipe_cli);
497         if (!W_ERROR_IS_OK(werr)) {
498                 goto done;
499         }
500
501         b = pipe_cli->binding_handle;
502
503         werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
504                                                   SAMR_ACCESS_LOOKUP_DOMAIN |
505                                                   SAMR_ACCESS_ENUM_DOMAINS,
506                                                   SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
507                                                   &connect_handle,
508                                                   &builtin_handle);
509         if (!W_ERROR_IS_OK(werr)) {
510                 goto done;
511         }
512
513         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
514                                                       &builtin_handle,
515                                                       r->in.group_name,
516                                                       SAMR_ALIAS_ACCESS_LOOKUP_INFO,
517                                                       &alias_handle);
518
519         if (ctx->disable_policy_handle_cache) {
520                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
521         }
522
523         if (NT_STATUS_IS_OK(status)) {
524                 goto query_alias;
525         }
526
527         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
528                                           SAMR_ACCESS_ENUM_DOMAINS |
529                                           SAMR_ACCESS_LOOKUP_DOMAIN,
530                                           SAMR_DOMAIN_ACCESS_CREATE_ALIAS |
531                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
532                                           &connect_handle,
533                                           &domain_handle,
534                                           &domain_sid);
535         if (!W_ERROR_IS_OK(werr)) {
536                 goto done;
537         }
538
539         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
540                                                       &domain_handle,
541                                                       r->in.group_name,
542                                                       SAMR_ALIAS_ACCESS_LOOKUP_INFO,
543                                                       &alias_handle);
544
545         if (ctx->disable_policy_handle_cache) {
546                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
547         }
548
549         if (!NT_STATUS_IS_OK(status)) {
550                 werr = ntstatus_to_werror(status);
551                 goto done;
552         }
553
554  query_alias:
555         status = dcerpc_samr_QueryAliasInfo(b, talloc_tos(),
556                                             &alias_handle,
557                                             ALIASINFOALL,
558                                             &alias_info,
559                                             &result);
560         if (!NT_STATUS_IS_OK(status)) {
561                 werr = ntstatus_to_werror(status);
562                 goto done;
563         }
564         if (!NT_STATUS_IS_OK(result)) {
565                 werr = ntstatus_to_werror(result);
566                 goto done;
567         }
568
569         werr = map_alias_info_to_buffer(ctx,
570                                         r->in.group_name,
571                                         &alias_info->all,
572                                         r->in.level, &entries_read,
573                                         r->out.buffer);
574
575  done:
576         if (is_valid_policy_hnd(&alias_handle)) {
577                 dcerpc_samr_Close(b, talloc_tos(), &alias_handle, &result);
578         }
579
580         if (ctx->disable_policy_handle_cache) {
581                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
582                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
583                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
584         }
585
586         return werr;
587 }
588
589 /****************************************************************
590 ****************************************************************/
591
592 WERROR NetLocalGroupGetInfo_l(struct libnetapi_ctx *ctx,
593                               struct NetLocalGroupGetInfo *r)
594 {
595         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupGetInfo);
596 }
597
598 /****************************************************************
599 ****************************************************************/
600
601 static WERROR map_buffer_to_alias_info(TALLOC_CTX *mem_ctx,
602                                        uint32_t level,
603                                        uint8_t *buffer,
604                                        enum samr_AliasInfoEnum *alias_level,
605                                        union samr_AliasInfo **alias_info)
606 {
607         struct LOCALGROUP_INFO_0 *info0;
608         struct LOCALGROUP_INFO_1 *info1;
609         struct LOCALGROUP_INFO_1002 *info1002;
610         union samr_AliasInfo *info = NULL;
611
612         info = TALLOC_ZERO_P(mem_ctx, union samr_AliasInfo);
613         W_ERROR_HAVE_NO_MEMORY(info);
614
615         switch (level) {
616                 case 0:
617                         info0 = (struct LOCALGROUP_INFO_0 *)buffer;
618                         init_lsa_String(&info->name, info0->lgrpi0_name);
619                         *alias_level = ALIASINFONAME;
620                         break;
621                 case 1:
622                         info1 = (struct LOCALGROUP_INFO_1 *)buffer;
623                         /* group name will be ignored */
624                         init_lsa_String(&info->description, info1->lgrpi1_comment);
625                         *alias_level = ALIASINFODESCRIPTION;
626                         break;
627                 case 1002:
628                         info1002 = (struct LOCALGROUP_INFO_1002 *)buffer;
629                         init_lsa_String(&info->description, info1002->lgrpi1002_comment);
630                         *alias_level = ALIASINFODESCRIPTION;
631                         break;
632         }
633
634         *alias_info = info;
635
636         return WERR_OK;
637 }
638
639 /****************************************************************
640 ****************************************************************/
641
642 WERROR NetLocalGroupSetInfo_r(struct libnetapi_ctx *ctx,
643                               struct NetLocalGroupSetInfo *r)
644 {
645         struct rpc_pipe_client *pipe_cli = NULL;
646         NTSTATUS status, result;
647         WERROR werr;
648         struct lsa_String lsa_account_name;
649         struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
650         struct dom_sid2 *domain_sid = NULL;
651         enum samr_AliasInfoEnum alias_level = 0;
652         union samr_AliasInfo *alias_info = NULL;
653         struct dcerpc_binding_handle *b = NULL;
654
655         if (!r->in.group_name) {
656                 return WERR_INVALID_PARAM;
657         }
658
659         switch (r->in.level) {
660                 case 0:
661                 case 1:
662                 case 1002:
663                         break;
664                 default:
665                         return WERR_UNKNOWN_LEVEL;
666         }
667
668         ZERO_STRUCT(connect_handle);
669         ZERO_STRUCT(builtin_handle);
670         ZERO_STRUCT(domain_handle);
671         ZERO_STRUCT(alias_handle);
672
673         werr = libnetapi_open_pipe(ctx, r->in.server_name,
674                                    &ndr_table_samr.syntax_id,
675                                    &pipe_cli);
676         if (!W_ERROR_IS_OK(werr)) {
677                 goto done;
678         }
679
680         b = pipe_cli->binding_handle;
681
682         werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
683                                                   SAMR_ACCESS_LOOKUP_DOMAIN |
684                                                   SAMR_ACCESS_ENUM_DOMAINS,
685                                                   SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
686                                                   &connect_handle,
687                                                   &builtin_handle);
688         if (!W_ERROR_IS_OK(werr)) {
689                 goto done;
690         }
691
692         init_lsa_String(&lsa_account_name, r->in.group_name);
693
694         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
695                                                       &builtin_handle,
696                                                       r->in.group_name,
697                                                       SAMR_ALIAS_ACCESS_SET_INFO,
698                                                       &alias_handle);
699
700         if (ctx->disable_policy_handle_cache) {
701                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
702         }
703
704         if (NT_STATUS_IS_OK(status)) {
705                 goto set_alias;
706         }
707
708         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
709                                           SAMR_ACCESS_ENUM_DOMAINS |
710                                           SAMR_ACCESS_LOOKUP_DOMAIN,
711                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
712                                           &connect_handle,
713                                           &domain_handle,
714                                           &domain_sid);
715         if (!W_ERROR_IS_OK(werr)) {
716                 goto done;
717         }
718
719         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
720                                                       &domain_handle,
721                                                       r->in.group_name,
722                                                       SAMR_ALIAS_ACCESS_SET_INFO,
723                                                       &alias_handle);
724         if (!NT_STATUS_IS_OK(status)) {
725                 werr = ntstatus_to_werror(status);
726                 goto done;
727         }
728
729         if (ctx->disable_policy_handle_cache) {
730                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
731         }
732
733  set_alias:
734
735         werr = map_buffer_to_alias_info(ctx, r->in.level, r->in.buffer,
736                                         &alias_level, &alias_info);
737         if (!W_ERROR_IS_OK(werr)) {
738                 goto done;
739         }
740
741         status = dcerpc_samr_SetAliasInfo(b, talloc_tos(),
742                                           &alias_handle,
743                                           alias_level,
744                                           alias_info,
745                                           &result);
746         if (!NT_STATUS_IS_OK(status)) {
747                 werr = ntstatus_to_werror(status);
748                 goto done;
749         }
750         if (!NT_STATUS_IS_OK(result)) {
751                 werr = ntstatus_to_werror(result);
752                 goto done;
753         }
754
755         werr = WERR_OK;
756
757  done:
758         if (is_valid_policy_hnd(&alias_handle)) {
759                 dcerpc_samr_Close(b, talloc_tos(), &alias_handle, &result);
760         }
761
762         if (ctx->disable_policy_handle_cache) {
763                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
764                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
765                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
766         }
767
768         return werr;
769 }
770
771 /****************************************************************
772 ****************************************************************/
773
774 WERROR NetLocalGroupSetInfo_l(struct libnetapi_ctx *ctx,
775                               struct NetLocalGroupSetInfo *r)
776 {
777         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupSetInfo);
778 }
779
780 /****************************************************************
781 ****************************************************************/
782
783 WERROR NetLocalGroupEnum_r(struct libnetapi_ctx *ctx,
784                            struct NetLocalGroupEnum *r)
785 {
786         struct rpc_pipe_client *pipe_cli = NULL;
787         NTSTATUS status, result;
788         WERROR werr;
789         struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
790         struct dom_sid2 *domain_sid = NULL;
791         uint32_t entries_read = 0;
792         union samr_DomainInfo *domain_info = NULL;
793         union samr_DomainInfo *builtin_info = NULL;
794         struct samr_SamArray *domain_sam_array = NULL;
795         struct samr_SamArray *builtin_sam_array = NULL;
796         int i;
797         struct dcerpc_binding_handle *b = NULL;
798
799         if (!r->out.buffer) {
800                 return WERR_INVALID_PARAM;
801         }
802
803         switch (r->in.level) {
804                 case 0:
805                 case 1:
806                         break;
807                 default:
808                         return WERR_UNKNOWN_LEVEL;
809         }
810
811         if (r->out.total_entries) {
812                 *r->out.total_entries = 0;
813         }
814         if (r->out.entries_read) {
815                 *r->out.entries_read = 0;
816         }
817
818         ZERO_STRUCT(connect_handle);
819         ZERO_STRUCT(builtin_handle);
820         ZERO_STRUCT(domain_handle);
821         ZERO_STRUCT(alias_handle);
822
823         werr = libnetapi_open_pipe(ctx, r->in.server_name,
824                                    &ndr_table_samr.syntax_id,
825                                    &pipe_cli);
826         if (!W_ERROR_IS_OK(werr)) {
827                 goto done;
828         }
829
830         b = pipe_cli->binding_handle;
831
832         werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
833                                                   SAMR_ACCESS_LOOKUP_DOMAIN |
834                                                   SAMR_ACCESS_ENUM_DOMAINS,
835                                                   SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 |
836                                                   SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS |
837                                                   SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
838                                                   &connect_handle,
839                                                   &builtin_handle);
840         if (!W_ERROR_IS_OK(werr)) {
841                 goto done;
842         }
843
844         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
845                                           SAMR_ACCESS_LOOKUP_DOMAIN |
846                                           SAMR_ACCESS_ENUM_DOMAINS,
847                                           SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 |
848                                           SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS |
849                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
850                                           &connect_handle,
851                                           &domain_handle,
852                                           &domain_sid);
853         if (!W_ERROR_IS_OK(werr)) {
854                 goto done;
855         }
856
857         status = dcerpc_samr_QueryDomainInfo(b, talloc_tos(),
858                                              &builtin_handle,
859                                              2,
860                                              &builtin_info,
861                                              &result);
862         if (!NT_STATUS_IS_OK(status)) {
863                 werr = ntstatus_to_werror(status);
864                 goto done;
865         }
866         if (!NT_STATUS_IS_OK(result)) {
867                 werr = ntstatus_to_werror(result);
868                 goto done;
869         }
870
871         if (r->out.total_entries) {
872                 *r->out.total_entries += builtin_info->general.num_aliases;
873         }
874
875         status = dcerpc_samr_QueryDomainInfo(b, talloc_tos(),
876                                              &domain_handle,
877                                              2,
878                                              &domain_info,
879                                              &result);
880         if (!NT_STATUS_IS_OK(status)) {
881                 werr = ntstatus_to_werror(status);
882                 goto done;
883         }
884         if (!NT_STATUS_IS_OK(result)) {
885                 werr = ntstatus_to_werror(result);
886                 goto done;
887         }
888
889         if (r->out.total_entries) {
890                 *r->out.total_entries += domain_info->general.num_aliases;
891         }
892
893         status = dcerpc_samr_EnumDomainAliases(b, talloc_tos(),
894                                                &builtin_handle,
895                                                r->in.resume_handle,
896                                                &builtin_sam_array,
897                                                r->in.prefmaxlen,
898                                                &entries_read,
899                                                &result);
900         if (!NT_STATUS_IS_OK(status)) {
901                 werr = ntstatus_to_werror(status);
902                 goto done;
903         }
904         if (!NT_STATUS_IS_OK(result)) {
905                 werr = ntstatus_to_werror(result);
906                 goto done;
907         }
908
909         for (i=0; i<builtin_sam_array->count; i++) {
910                 union samr_AliasInfo *alias_info = NULL;
911
912                 if (r->in.level == 1) {
913
914                         status = libnetapi_samr_open_alias_queryinfo(ctx, pipe_cli,
915                                                                      &builtin_handle,
916                                                                      builtin_sam_array->entries[i].idx,
917                                                                      SAMR_ALIAS_ACCESS_LOOKUP_INFO,
918                                                                      ALIASINFOALL,
919                                                                      &alias_info);
920                         if (!NT_STATUS_IS_OK(status)) {
921                                 werr = ntstatus_to_werror(status);
922                                 goto done;
923                         }
924                 }
925
926                 werr = map_alias_info_to_buffer(ctx,
927                                                 builtin_sam_array->entries[i].name.string,
928                                                 alias_info ? &alias_info->all : NULL,
929                                                 r->in.level,
930                                                 r->out.entries_read,
931                                                 r->out.buffer);
932         }
933
934         status = dcerpc_samr_EnumDomainAliases(b, talloc_tos(),
935                                                &domain_handle,
936                                                r->in.resume_handle,
937                                                &domain_sam_array,
938                                                r->in.prefmaxlen,
939                                                &entries_read,
940                                                &result);
941         if (!NT_STATUS_IS_OK(status)) {
942                 werr = ntstatus_to_werror(status);
943                 goto done;
944         }
945         if (!NT_STATUS_IS_OK(result)) {
946                 werr = ntstatus_to_werror(result);
947                 goto done;
948         }
949
950         for (i=0; i<domain_sam_array->count; i++) {
951
952                 union samr_AliasInfo *alias_info = NULL;
953
954                 if (r->in.level == 1) {
955                         status = libnetapi_samr_open_alias_queryinfo(ctx, pipe_cli,
956                                                                      &domain_handle,
957                                                                      domain_sam_array->entries[i].idx,
958                                                                      SAMR_ALIAS_ACCESS_LOOKUP_INFO,
959                                                                      ALIASINFOALL,
960                                                                      &alias_info);
961                         if (!NT_STATUS_IS_OK(status)) {
962                                 werr = ntstatus_to_werror(status);
963                                 goto done;
964                         }
965                 }
966
967                 werr = map_alias_info_to_buffer(ctx,
968                                                 domain_sam_array->entries[i].name.string,
969                                                 alias_info ? &alias_info->all : NULL,
970                                                 r->in.level,
971                                                 r->out.entries_read,
972                                                 r->out.buffer);
973         }
974
975  done:
976         if (ctx->disable_policy_handle_cache) {
977                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
978                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
979                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
980         }
981
982         return werr;
983 }
984
985 /****************************************************************
986 ****************************************************************/
987
988 WERROR NetLocalGroupEnum_l(struct libnetapi_ctx *ctx,
989                            struct NetLocalGroupEnum *r)
990 {
991         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupEnum);
992 }
993
994 /****************************************************************
995 ****************************************************************/
996
997 static NTSTATUS libnetapi_lsa_lookup_names3(TALLOC_CTX *mem_ctx,
998                                             struct rpc_pipe_client *lsa_pipe,
999                                             const char *name,
1000                                             struct dom_sid *sid)
1001 {
1002         NTSTATUS status, result;
1003         struct policy_handle lsa_handle;
1004         struct dcerpc_binding_handle *b = lsa_pipe->binding_handle;
1005
1006         struct lsa_RefDomainList *domains = NULL;
1007         struct lsa_TransSidArray3 sids;
1008         uint32_t count = 0;
1009
1010         struct lsa_String names;
1011         uint32_t num_names = 1;
1012
1013         if (!sid || !name) {
1014                 return NT_STATUS_INVALID_PARAMETER;
1015         }
1016
1017         ZERO_STRUCT(sids);
1018
1019         init_lsa_String(&names, name);
1020
1021         status = rpccli_lsa_open_policy2(lsa_pipe, mem_ctx,
1022                                          false,
1023                                          SEC_STD_READ_CONTROL |
1024                                          LSA_POLICY_VIEW_LOCAL_INFORMATION |
1025                                          LSA_POLICY_LOOKUP_NAMES,
1026                                          &lsa_handle);
1027         NT_STATUS_NOT_OK_RETURN(status);
1028
1029         status = dcerpc_lsa_LookupNames3(b, mem_ctx,
1030                                          &lsa_handle,
1031                                          num_names,
1032                                          &names,
1033                                          &domains,
1034                                          &sids,
1035                                          LSA_LOOKUP_NAMES_ALL, /* sure ? */
1036                                          &count,
1037                                          0, 0,
1038                                          &result);
1039         NT_STATUS_NOT_OK_RETURN(status);
1040         NT_STATUS_NOT_OK_RETURN(result);
1041
1042         if (count != 1 || sids.count != 1) {
1043                 return NT_STATUS_NONE_MAPPED;
1044         }
1045
1046         sid_copy(sid, sids.sids[0].sid);
1047
1048         return NT_STATUS_OK;
1049 }
1050
1051 /****************************************************************
1052 ****************************************************************/
1053
1054 static WERROR NetLocalGroupModifyMembers_r(struct libnetapi_ctx *ctx,
1055                                            struct NetLocalGroupAddMembers *add,
1056                                            struct NetLocalGroupDelMembers *del,
1057                                            struct NetLocalGroupSetMembers *set)
1058 {
1059         struct NetLocalGroupAddMembers *r = NULL;
1060
1061         struct rpc_pipe_client *pipe_cli = NULL;
1062         struct rpc_pipe_client *lsa_pipe = NULL;
1063         NTSTATUS status, result;
1064         WERROR werr;
1065         struct lsa_String lsa_account_name;
1066         struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
1067         struct dom_sid2 *domain_sid = NULL;
1068         struct dom_sid *member_sids = NULL;
1069         int i = 0, k = 0;
1070
1071         struct LOCALGROUP_MEMBERS_INFO_0 *info0 = NULL;
1072         struct LOCALGROUP_MEMBERS_INFO_3 *info3 = NULL;
1073
1074         struct dom_sid *add_sids = NULL;
1075         struct dom_sid *del_sids = NULL;
1076         uint32_t num_add_sids = 0;
1077         uint32_t num_del_sids = 0;
1078         struct dcerpc_binding_handle *b = NULL;
1079
1080         if ((!add && !del && !set) || (add && del && set)) {
1081                 return WERR_INVALID_PARAM;
1082         }
1083
1084         if (add) {
1085                 r = add;
1086         }
1087
1088         if (del) {
1089                 r = (struct NetLocalGroupAddMembers *)del;
1090         }
1091
1092         if (set) {
1093                 r = (struct NetLocalGroupAddMembers *)set;
1094         }
1095
1096         if (!r->in.group_name) {
1097                 return WERR_INVALID_PARAM;
1098         }
1099
1100         switch (r->in.level) {
1101                 case 0:
1102                 case 3:
1103                         break;
1104                 default:
1105                         return WERR_UNKNOWN_LEVEL;
1106         }
1107
1108         if (r->in.total_entries == 0 || !r->in.buffer) {
1109                 return WERR_INVALID_PARAM;
1110         }
1111
1112         ZERO_STRUCT(connect_handle);
1113         ZERO_STRUCT(builtin_handle);
1114         ZERO_STRUCT(domain_handle);
1115         ZERO_STRUCT(alias_handle);
1116
1117         member_sids = TALLOC_ZERO_ARRAY(ctx, struct dom_sid,
1118                                         r->in.total_entries);
1119         W_ERROR_HAVE_NO_MEMORY(member_sids);
1120
1121         switch (r->in.level) {
1122                 case 0:
1123                         info0 = (struct LOCALGROUP_MEMBERS_INFO_0 *)r->in.buffer;
1124                         for (i=0; i < r->in.total_entries; i++) {
1125                                 sid_copy(&member_sids[i], (struct dom_sid *)info0[i].lgrmi0_sid);
1126                         }
1127                         break;
1128                 case 3:
1129                         info3 = (struct LOCALGROUP_MEMBERS_INFO_3 *)r->in.buffer;
1130                         break;
1131                 default:
1132                         break;
1133         }
1134
1135         if (r->in.level == 3) {
1136                 werr = libnetapi_open_pipe(ctx, r->in.server_name,
1137                                            &ndr_table_lsarpc.syntax_id,
1138                                            &lsa_pipe);
1139                 if (!W_ERROR_IS_OK(werr)) {
1140                         goto done;
1141                 }
1142
1143                 for (i=0; i < r->in.total_entries; i++) {
1144                         status = libnetapi_lsa_lookup_names3(ctx, lsa_pipe,
1145                                                              info3[i].lgrmi3_domainandname,
1146                                                              &member_sids[i]);
1147                         if (!NT_STATUS_IS_OK(status)) {
1148                                 werr = ntstatus_to_werror(status);
1149                                 goto done;
1150                         }
1151                 }
1152                 TALLOC_FREE(lsa_pipe);
1153         }
1154
1155         werr = libnetapi_open_pipe(ctx, r->in.server_name,
1156                                    &ndr_table_samr.syntax_id,
1157                                    &pipe_cli);
1158         if (!W_ERROR_IS_OK(werr)) {
1159                 goto done;
1160         }
1161
1162         b = pipe_cli->binding_handle;
1163
1164         werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
1165                                                   SAMR_ACCESS_LOOKUP_DOMAIN |
1166                                                   SAMR_ACCESS_ENUM_DOMAINS,
1167                                                   SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1168                                                   &connect_handle,
1169                                                   &builtin_handle);
1170         if (!W_ERROR_IS_OK(werr)) {
1171                 goto done;
1172         }
1173
1174         init_lsa_String(&lsa_account_name, r->in.group_name);
1175
1176         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
1177                                                       &builtin_handle,
1178                                                       r->in.group_name,
1179                                                       SAMR_ALIAS_ACCESS_ADD_MEMBER |
1180                                                       SAMR_ALIAS_ACCESS_REMOVE_MEMBER |
1181                                                       SAMR_ALIAS_ACCESS_GET_MEMBERS |
1182                                                       SAMR_ALIAS_ACCESS_LOOKUP_INFO,
1183                                                       &alias_handle);
1184
1185         if (ctx->disable_policy_handle_cache) {
1186                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
1187         }
1188
1189         if (NT_STATUS_IS_OK(status)) {
1190                 goto modify_membership;
1191         }
1192
1193         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
1194                                           SAMR_ACCESS_ENUM_DOMAINS |
1195                                           SAMR_ACCESS_LOOKUP_DOMAIN,
1196                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1197                                           &connect_handle,
1198                                           &domain_handle,
1199                                           &domain_sid);
1200         if (!W_ERROR_IS_OK(werr)) {
1201                 goto done;
1202         }
1203
1204         status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
1205                                                       &domain_handle,
1206                                                       r->in.group_name,
1207                                                       SAMR_ALIAS_ACCESS_ADD_MEMBER |
1208                                                       SAMR_ALIAS_ACCESS_REMOVE_MEMBER |
1209                                                       SAMR_ALIAS_ACCESS_GET_MEMBERS |
1210                                                       SAMR_ALIAS_ACCESS_LOOKUP_INFO,
1211                                                       &alias_handle);
1212         if (!NT_STATUS_IS_OK(status)) {
1213                 werr = ntstatus_to_werror(status);
1214                 goto done;
1215         }
1216
1217         if (ctx->disable_policy_handle_cache) {
1218                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
1219         }
1220
1221  modify_membership:
1222
1223         if (add) {
1224                 for (i=0; i < r->in.total_entries; i++) {
1225                         status = add_sid_to_array_unique(ctx, &member_sids[i],
1226                                                          &add_sids,
1227                                                          &num_add_sids);
1228                         if (!NT_STATUS_IS_OK(status)) {
1229                                 werr = ntstatus_to_werror(status);
1230                                 goto done;
1231                         }
1232                 }
1233         }
1234
1235         if (del) {
1236                 for (i=0; i < r->in.total_entries; i++) {
1237                         status = add_sid_to_array_unique(ctx, &member_sids[i],
1238                                                          &del_sids,
1239                                                          &num_del_sids);
1240                         if (!NT_STATUS_IS_OK(status)) {
1241                                 werr = ntstatus_to_werror(status);
1242                                 goto done;
1243                         }
1244                 }
1245         }
1246
1247         if (set) {
1248
1249                 struct lsa_SidArray current_sids;
1250
1251                 status = dcerpc_samr_GetMembersInAlias(b, talloc_tos(),
1252                                                        &alias_handle,
1253                                                        &current_sids,
1254                                                        &result);
1255                 if (!NT_STATUS_IS_OK(status)) {
1256                         werr = ntstatus_to_werror(status);
1257                         goto done;
1258                 }
1259                 if (!NT_STATUS_IS_OK(result)) {
1260                         werr = ntstatus_to_werror(result);
1261                         goto done;
1262                 }
1263
1264                 /* add list */
1265
1266                 for (i=0; i < r->in.total_entries; i++) {
1267                         bool already_member = false;
1268                         for (k=0; k < current_sids.num_sids; k++) {
1269                                 if (dom_sid_equal(&member_sids[i],
1270                                               current_sids.sids[k].sid)) {
1271                                         already_member = true;
1272                                         break;
1273                                 }
1274                         }
1275                         if (!already_member) {
1276                                 status = add_sid_to_array_unique(ctx,
1277                                         &member_sids[i],
1278                                         &add_sids, &num_add_sids);
1279                                 if (!NT_STATUS_IS_OK(status)) {
1280                                         werr = ntstatus_to_werror(status);
1281                                         goto done;
1282                                 }
1283                         }
1284                 }
1285
1286                 /* del list */
1287
1288                 for (k=0; k < current_sids.num_sids; k++) {
1289                         bool keep_member = false;
1290                         for (i=0; i < r->in.total_entries; i++) {
1291                                 if (dom_sid_equal(&member_sids[i],
1292                                               current_sids.sids[k].sid)) {
1293                                         keep_member = true;
1294                                         break;
1295                                 }
1296                         }
1297                         if (!keep_member) {
1298                                 status = add_sid_to_array_unique(ctx,
1299                                                 current_sids.sids[k].sid,
1300                                                 &del_sids, &num_del_sids);
1301                                 if (!NT_STATUS_IS_OK(status)) {
1302                                         werr = ntstatus_to_werror(status);
1303                                         goto done;
1304                                 }
1305                         }
1306                 }
1307         }
1308
1309         /* add list */
1310
1311         for (i=0; i < num_add_sids; i++) {
1312                 status = dcerpc_samr_AddAliasMember(b, talloc_tos(),
1313                                                     &alias_handle,
1314                                                     &add_sids[i],
1315                                                     &result);
1316                 if (!NT_STATUS_IS_OK(status)) {
1317                         werr = ntstatus_to_werror(status);
1318                         goto done;
1319                 }
1320                 if (!NT_STATUS_IS_OK(result)) {
1321                         werr = ntstatus_to_werror(result);
1322                         goto done;
1323                 }
1324         }
1325
1326         /* del list */
1327
1328         for (i=0; i < num_del_sids; i++) {
1329                 status = dcerpc_samr_DeleteAliasMember(b, talloc_tos(),
1330                                                        &alias_handle,
1331                                                        &del_sids[i],
1332                                                        &result);
1333                 if (!NT_STATUS_IS_OK(status)) {
1334                         werr = ntstatus_to_werror(status);
1335                         goto done;
1336                 }
1337                 if (!NT_STATUS_IS_OK(result)) {
1338                         werr = ntstatus_to_werror(result);
1339                         goto done;
1340                 }
1341         }
1342
1343         werr = WERR_OK;
1344
1345  done:
1346         if (is_valid_policy_hnd(&alias_handle)) {
1347                 dcerpc_samr_Close(b, talloc_tos(), &alias_handle, &result);
1348         }
1349
1350         if (ctx->disable_policy_handle_cache) {
1351                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
1352                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
1353                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
1354         }
1355
1356         return werr;
1357 }
1358
1359 /****************************************************************
1360 ****************************************************************/
1361
1362 WERROR NetLocalGroupAddMembers_r(struct libnetapi_ctx *ctx,
1363                                  struct NetLocalGroupAddMembers *r)
1364 {
1365         return NetLocalGroupModifyMembers_r(ctx, r, NULL, NULL);
1366 }
1367
1368 /****************************************************************
1369 ****************************************************************/
1370
1371 WERROR NetLocalGroupAddMembers_l(struct libnetapi_ctx *ctx,
1372                                  struct NetLocalGroupAddMembers *r)
1373 {
1374         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupAddMembers);
1375 }
1376
1377 /****************************************************************
1378 ****************************************************************/
1379
1380 WERROR NetLocalGroupDelMembers_r(struct libnetapi_ctx *ctx,
1381                                  struct NetLocalGroupDelMembers *r)
1382 {
1383         return NetLocalGroupModifyMembers_r(ctx, NULL, r, NULL);
1384 }
1385
1386 /****************************************************************
1387 ****************************************************************/
1388
1389 WERROR NetLocalGroupDelMembers_l(struct libnetapi_ctx *ctx,
1390                                  struct NetLocalGroupDelMembers *r)
1391 {
1392         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupDelMembers);
1393 }
1394
1395 /****************************************************************
1396 ****************************************************************/
1397
1398 WERROR NetLocalGroupGetMembers_r(struct libnetapi_ctx *ctx,
1399                                  struct NetLocalGroupGetMembers *r)
1400 {
1401         return WERR_NOT_SUPPORTED;
1402 }
1403
1404 /****************************************************************
1405 ****************************************************************/
1406
1407 WERROR NetLocalGroupGetMembers_l(struct libnetapi_ctx *ctx,
1408                                  struct NetLocalGroupGetMembers *r)
1409 {
1410         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupGetMembers);
1411 }
1412
1413 /****************************************************************
1414 ****************************************************************/
1415
1416 WERROR NetLocalGroupSetMembers_r(struct libnetapi_ctx *ctx,
1417                                  struct NetLocalGroupSetMembers *r)
1418 {
1419         return NetLocalGroupModifyMembers_r(ctx, NULL, NULL, r);
1420 }
1421
1422 /****************************************************************
1423 ****************************************************************/
1424
1425 WERROR NetLocalGroupSetMembers_l(struct libnetapi_ctx *ctx,
1426                                  struct NetLocalGroupSetMembers *r)
1427 {
1428         LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetLocalGroupSetMembers);
1429 }