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