1/*
2   Unix SMB/CIFS implementation.
3
4   Winbind rpc backend functions
5
6   Copyright (C) Tim Potter 2000-2001,2003
7   Copyright (C) Andrew Tridgell 2001
8   Copyright (C) Volker Lendecke 2005
9
10   This program is free software; you can redistribute it and/or modify
11   it under the terms of the GNU General Public License as published by
12   the Free Software Foundation; either version 2 of the License, or
13   (at your option) any later version.
14
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License for more details.
19
20   You should have received a copy of the GNU General Public License
21   along with this program; if not, write to the Free Software
22   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23*/
24
25#include "includes.h"
26#include "winbindd.h"
27
28#undef DBGC_CLASS
29#define DBGC_CLASS DBGC_WINBIND
30
31
32/* Query display info for a domain.  This returns enough information plus a
33   bit extra to give an overview of domain users for the User Manager
34   application. */
35static NTSTATUS query_user_list(struct winbindd_domain *domain,
36			       TALLOC_CTX *mem_ctx,
37			       uint32 *num_entries,
38			       WINBIND_USERINFO **info)
39{
40	CLI_POLICY_HND *hnd;
41	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
42	POLICY_HND dom_pol;
43	BOOL got_dom_pol = False;
44	uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
45	unsigned int i, start_idx, retry;
46	uint32 loop_count;
47
48	DEBUG(3,("rpc: query_user_list\n"));
49
50	*num_entries = 0;
51	*info = NULL;
52
53	retry = 0;
54	do {
55		/* Get sam handle */
56
57		if ( !NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)) )
58			return result;
59
60		/* Get domain handle */
61
62		result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
63						des_access, &domain->sid, &dom_pol);
64
65	} while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
66
67	if (!NT_STATUS_IS_OK(result))
68		goto done;
69
70	got_dom_pol = True;
71
72	i = start_idx = 0;
73	loop_count = 0;
74
75	do {
76		TALLOC_CTX *ctx2;
77		uint32 num_dom_users, j;
78		uint32 max_entries, max_size;
79		SAM_DISPINFO_CTR ctr;
80		SAM_DISPINFO_1 info1;
81
82		ZERO_STRUCT( ctr );
83		ZERO_STRUCT( info1 );
84		ctr.sam.info1 = &info1;
85
86		if (!(ctx2 = talloc_init("winbindd enum_users"))) {
87			result = NT_STATUS_NO_MEMORY;
88			goto done;
89		}
90
91		/* this next bit is copied from net_user_list_internal() */
92
93		get_query_dispinfo_params( loop_count, &max_entries, &max_size );
94
95		result = cli_samr_query_dispinfo(hnd->cli, mem_ctx, &dom_pol,
96			&start_idx, 1, &num_dom_users, max_entries, max_size, &ctr);
97
98		loop_count++;
99
100		*num_entries += num_dom_users;
101
102		*info = TALLOC_REALLOC_ARRAY( mem_ctx, *info, WINBIND_USERINFO, *num_entries);
103
104		if (!(*info)) {
105			result = NT_STATUS_NO_MEMORY;
106			talloc_destroy(ctx2);
107			goto done;
108		}
109
110		for (j = 0; j < num_dom_users; i++, j++) {
111			fstring username, fullname;
112			uint32 rid = ctr.sam.info1->sam[j].rid_user;
113
114			unistr2_to_ascii( username, &(&ctr.sam.info1->str[j])->uni_acct_name, sizeof(username)-1);
115			unistr2_to_ascii( fullname, &(&ctr.sam.info1->str[j])->uni_full_name, sizeof(fullname)-1);
116
117			(*info)[i].acct_name = talloc_strdup(mem_ctx, username );
118			(*info)[i].full_name = talloc_strdup(mem_ctx, fullname );
119			(*info)[i].user_sid = rid_to_talloced_sid(domain, mem_ctx, rid );
120
121			/* For the moment we set the primary group for
122			   every user to be the Domain Users group.
123			   There are serious problems with determining
124			   the actual primary group for large domains.
125			   This should really be made into a 'winbind
126			   force group' smb.conf parameter or
127			   something like that. */
128
129			(*info)[i].group_sid = rid_to_talloced_sid(domain,
130				mem_ctx, DOMAIN_GROUP_RID_USERS);
131		}
132
133		talloc_destroy(ctx2);
134
135	} while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
136
137 done:
138
139	if (got_dom_pol)
140		cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
141
142	return result;
143}
144
145/* list all domain groups */
146static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
147				TALLOC_CTX *mem_ctx,
148				uint32 *num_entries,
149				struct acct_info **info)
150{
151	uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
152	CLI_POLICY_HND *hnd;
153	POLICY_HND dom_pol;
154	NTSTATUS status;
155	uint32 start = 0;
156	int retry;
157	NTSTATUS result;
158
159	*num_entries = 0;
160	*info = NULL;
161
162	DEBUG(3,("rpc: enum_dom_groups\n"));
163
164	retry = 0;
165	do {
166		if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)))
167			return result;
168
169		status = cli_samr_open_domain(hnd->cli, mem_ctx,
170					      &hnd->pol, des_access, &domain->sid, &dom_pol);
171	} while (!NT_STATUS_IS_OK(status) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
172
173	if (!NT_STATUS_IS_OK(status))
174		return status;
175
176	do {
177		struct acct_info *info2 = NULL;
178		uint32 count = 0;
179		TALLOC_CTX *mem_ctx2;
180
181		mem_ctx2 = talloc_init("enum_dom_groups[rpc]");
182
183		/* start is updated by this call. */
184		status = cli_samr_enum_dom_groups(hnd->cli, mem_ctx2, &dom_pol,
185						  &start,
186						  0xFFFF, /* buffer size? */
187						  &info2, &count);
188
189		if (!NT_STATUS_IS_OK(status) &&
190		    !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
191			talloc_destroy(mem_ctx2);
192			break;
193		}
194
195		(*info) = TALLOC_REALLOC_ARRAY(mem_ctx, *info, struct acct_info, (*num_entries) + count);
196		if (! *info) {
197			talloc_destroy(mem_ctx2);
198			cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
199			return NT_STATUS_NO_MEMORY;
200		}
201
202		memcpy(&(*info)[*num_entries], info2, count*sizeof(*info2));
203		(*num_entries) += count;
204		talloc_destroy(mem_ctx2);
205	} while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
206
207	cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
208
209	return status;
210}
211
212/* List all domain groups */
213
214static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
215				TALLOC_CTX *mem_ctx,
216				uint32 *num_entries,
217				struct acct_info **info)
218{
219	uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
220	CLI_POLICY_HND *hnd;
221	POLICY_HND dom_pol;
222	NTSTATUS result;
223	int retry;
224
225	*num_entries = 0;
226	*info = NULL;
227
228	retry = 0;
229	do {
230		if ( !NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)) )
231			return result;
232
233		result = cli_samr_open_domain( hnd->cli, mem_ctx, &hnd->pol,
234						des_access, &domain->sid, &dom_pol);
235	} while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
236
237	if ( !NT_STATUS_IS_OK(result))
238		return result;
239
240	do {
241		struct acct_info *info2 = NULL;
242		uint32 count = 0, start = *num_entries;
243		TALLOC_CTX *mem_ctx2;
244
245		mem_ctx2 = talloc_init("enum_dom_local_groups[rpc]");
246
247		result = cli_samr_enum_als_groups( hnd->cli, mem_ctx2, &dom_pol,
248					  &start, 0xFFFF, &info2, &count);
249
250		if ( !NT_STATUS_IS_OK(result)
251			&& !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES) )
252		{
253			talloc_destroy(mem_ctx2);
254			break;
255		}
256
257		(*info) = TALLOC_REALLOC_ARRAY(mem_ctx, *info, struct acct_info, (*num_entries) + count);
258		if (! *info) {
259			talloc_destroy(mem_ctx2);
260			cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
261			return NT_STATUS_NO_MEMORY;
262		}
263
264		memcpy(&(*info)[*num_entries], info2, count*sizeof(*info2));
265		(*num_entries) += count;
266		talloc_destroy(mem_ctx2);
267	} while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
268
269	cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
270
271	return result;
272}
273
274/* convert a single name to a sid in a domain */
275NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain,
276			    TALLOC_CTX *mem_ctx,
277			    const char *domain_name,
278			    const char *name,
279			    DOM_SID *sid,
280			    enum SID_NAME_USE *type)
281{
282	CLI_POLICY_HND *hnd;
283	NTSTATUS result;
284	DOM_SID *sids = NULL;
285	uint32 *types = NULL;
286	const char *full_name;
287	int retry;
288
289	DEBUG(3,("rpc: name_to_sid name=%s\n", name));
290
291	full_name = talloc_asprintf(mem_ctx, "%s\\%s", domain_name, name);
292
293	if (!full_name) {
294		DEBUG(0, ("talloc_asprintf failed!\n"));
295		return NT_STATUS_NO_MEMORY;
296	}
297
298	DEBUG(3,("name_to_sid [rpc] %s for domain %s\n", name, domain_name ));
299
300	retry = 0;
301	do {
302		if (!NT_STATUS_IS_OK(result = cm_get_lsa_handle(domain, &hnd))) {
303			return result;
304		}
305
306		result = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, 1,
307					      &full_name, &sids, &types);
308	} while (!NT_STATUS_IS_OK(result) && (retry++ < 1) &&
309			hnd && hnd->cli && hnd->cli->fd == -1);
310
311	/* Return rid and type if lookup successful */
312
313	if (NT_STATUS_IS_OK(result)) {
314		sid_copy(sid, &sids[0]);
315		*type = (enum SID_NAME_USE)types[0];
316	}
317
318	return result;
319}
320
321/*
322  convert a domain SID to a user or group name
323*/
324NTSTATUS msrpc_sid_to_name(struct winbindd_domain *domain,
325			    TALLOC_CTX *mem_ctx,
326			    const DOM_SID *sid,
327			    char **domain_name,
328			    char **name,
329			    enum SID_NAME_USE *type)
330{
331	CLI_POLICY_HND *hnd;
332	char **domains;
333	char **names;
334	uint32 *types;
335	NTSTATUS result;
336	int retry;
337
338	DEBUG(3,("sid_to_name [rpc] %s for domain %s\n", sid_string_static(sid),
339			domain->name ));
340
341	retry = 0;
342	do {
343		if (!NT_STATUS_IS_OK(result = cm_get_lsa_handle(domain, &hnd)))
344			return result;
345
346		result = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol,
347					     1, sid, &domains, &names, &types);
348	} while (!NT_STATUS_IS_OK(result) && (retry++ < 1) &&
349			hnd && hnd->cli && hnd->cli->fd == -1);
350
351	if (NT_STATUS_IS_OK(result)) {
352		*type = (enum SID_NAME_USE)types[0];
353		*domain_name = domains[0];
354		*name = names[0];
355		DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name));
356	}
357
358	return result;
359}
360
361/* Lookup user information from a rid or username. */
362static NTSTATUS query_user(struct winbindd_domain *domain,
363			   TALLOC_CTX *mem_ctx,
364			   const DOM_SID *user_sid,
365			   WINBIND_USERINFO *user_info)
366{
367	CLI_POLICY_HND *hnd = NULL;
368	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
369	POLICY_HND dom_pol, user_pol;
370	BOOL got_dom_pol = False, got_user_pol = False;
371	SAM_USERINFO_CTR *ctr;
372	int retry;
373	fstring sid_string;
374	uint32 user_rid;
375	NET_USER_INFO_3 *user;
376
377	DEBUG(3,("rpc: query_user rid=%s\n", sid_to_string(sid_string, user_sid)));
378	if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid)) {
379		goto done;
380	}
381
382	/* try netsamlogon cache first */
383
384	if ( (user = netsamlogon_cache_get( mem_ctx, user_sid )) != NULL )
385	{
386
387		DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
388			sid_string_static(user_sid)));
389
390		user_info->user_sid  = rid_to_talloced_sid( domain, mem_ctx, user_rid );
391		user_info->group_sid = rid_to_talloced_sid( domain, mem_ctx, user->group_rid );
392
393		user_info->acct_name = unistr2_tdup(mem_ctx, &user->uni_user_name);
394		user_info->full_name = unistr2_tdup(mem_ctx, &user->uni_full_name);
395
396		SAFE_FREE(user);
397
398		return NT_STATUS_OK;
399	}
400
401	/* no cache; hit the wire */
402
403	retry = 0;
404	do {
405		/* Get sam handle; if we fail here there is no hope */
406
407		if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)))
408			goto done;
409
410		/* Get domain handle */
411
412		result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
413					      SEC_RIGHTS_MAXIMUM_ALLOWED,
414					      &domain->sid, &dom_pol);
415	} while (!NT_STATUS_IS_OK(result) && (retry++ < 1) &&
416			hnd && hnd->cli && hnd->cli->fd == -1);
417
418	if (!NT_STATUS_IS_OK(result))
419		goto done;
420
421	got_dom_pol = True;
422
423	/* Get user handle */
424	result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
425				    SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
426
427	if (!NT_STATUS_IS_OK(result))
428		goto done;
429
430	got_user_pol = True;
431
432	/* Get user info */
433	result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol,
434					 0x15, &ctr);
435
436	if (!NT_STATUS_IS_OK(result))
437		goto done;
438
439	cli_samr_close(hnd->cli, mem_ctx, &user_pol);
440	got_user_pol = False;
441
442	user_info->user_sid = rid_to_talloced_sid(domain, mem_ctx, user_rid);
443	user_info->group_sid = rid_to_talloced_sid(domain, mem_ctx, ctr->info.id21->group_rid);
444	user_info->acct_name = unistr2_tdup(mem_ctx,
445					    &ctr->info.id21->uni_user_name);
446	user_info->full_name = unistr2_tdup(mem_ctx,
447					    &ctr->info.id21->uni_full_name);
448
449 done:
450	/* Clean up policy handles */
451	if (got_user_pol)
452		cli_samr_close(hnd->cli, mem_ctx, &user_pol);
453
454	if (got_dom_pol)
455		cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
456
457	return result;
458}
459
460/* Lookup groups a user is a member of.  I wish Unix had a call like this! */
461static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
462				  TALLOC_CTX *mem_ctx,
463				  const DOM_SID *user_sid,
464				  uint32 *num_groups, DOM_SID ***user_grpsids)
465{
466	CLI_POLICY_HND *hnd;
467	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
468	POLICY_HND dom_pol, user_pol;
469	uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
470	BOOL got_dom_pol = False, got_user_pol = False;
471	DOM_GID *user_groups;
472	unsigned int i;
473	unsigned int retry;
474	fstring sid_string;
475	uint32 user_rid;
476	NET_USER_INFO_3 *user;
477
478	DEBUG(3,("rpc: lookup_usergroups sid=%s\n", sid_to_string(sid_string, user_sid)));
479
480	*num_groups = 0;
481	*user_grpsids = NULL;
482
483	/* so lets see if we have a cached user_info_3 */
484
485	if ( (user = netsamlogon_cache_get( mem_ctx, user_sid )) != NULL )
486	{
487		DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
488			sid_string_static(user_sid)));
489
490		*num_groups = user->num_groups;
491
492		(*user_grpsids) = TALLOC_ARRAY(mem_ctx, DOM_SID*, *num_groups);
493		for (i=0;i<(*num_groups);i++) {
494			(*user_grpsids)[i] = rid_to_talloced_sid(domain, mem_ctx, user->gids[i].g_rid);
495		}
496
497		SAFE_FREE(user);
498
499		return NT_STATUS_OK;
500	}
501
502	/* no cache; hit the wire */
503
504	retry = 0;
505	do {
506		/* Get sam handle; if we fail here there is no hope */
507
508		if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)))
509			goto done;
510
511		/* Get domain handle */
512
513		result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
514					      des_access, &domain->sid, &dom_pol);
515	} while (!NT_STATUS_IS_OK(result) && (retry++ < 1) &&
516			hnd && hnd->cli && hnd->cli->fd == -1);
517
518	if (!NT_STATUS_IS_OK(result))
519		goto done;
520
521	got_dom_pol = True;
522
523
524	if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid)) {
525		goto done;
526	}
527
528	/* Get user handle */
529	result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
530					des_access, user_rid, &user_pol);
531
532	if (!NT_STATUS_IS_OK(result))
533		goto done;
534
535	got_user_pol = True;
536
537	/* Query user rids */
538	result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol,
539					   num_groups, &user_groups);
540
541	if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
542		goto done;
543
544	(*user_grpsids) = TALLOC_ARRAY(mem_ctx, DOM_SID *, *num_groups);
545	if (!(*user_grpsids)) {
546		result = NT_STATUS_NO_MEMORY;
547		goto done;
548	}
549
550	for (i=0;i<(*num_groups);i++) {
551		(*user_grpsids)[i] = rid_to_talloced_sid(domain, mem_ctx, user_groups[i].g_rid);
552	}
553
554 done:
555	/* Clean up policy handles */
556	if (got_user_pol)
557		cli_samr_close(hnd->cli, mem_ctx, &user_pol);
558
559	if (got_dom_pol)
560		cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
561
562	return result;
563}
564
565NTSTATUS msrpc_lookup_useraliases(struct winbindd_domain *domain,
566				  TALLOC_CTX *mem_ctx,
567				  uint32 num_sids, DOM_SID **sids,
568				  uint32 *num_aliases, uint32 **alias_rids)
569{
570	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
571	CLI_POLICY_HND *hnd;
572	BOOL got_dom_pol = False;
573	POLICY_HND dom_pol;
574	DOM_SID2 *sid2;
575	int i, retry;
576
577	*num_aliases = 0;
578	*alias_rids = NULL;
579
580	retry = 0;
581	do {
582		/* Get sam handle; if we fail here there is no hope */
583
584		if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain,
585								&hnd)))
586			goto done;
587
588		/* Get domain handle */
589
590		result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
591					      SEC_RIGHTS_MAXIMUM_ALLOWED,
592					      &domain->sid, &dom_pol);
593	} while (!NT_STATUS_IS_OK(result) && (retry++ < 1) &&
594			hnd && hnd->cli && hnd->cli->fd == -1);
595
596	if (!NT_STATUS_IS_OK(result))
597		goto done;
598
599	got_dom_pol = True;
600
601	sid2 = TALLOC_ARRAY(mem_ctx, DOM_SID2, num_sids);
602
603	if (sid2 == NULL) {
604		result = NT_STATUS_NO_MEMORY;
605		goto done;
606	}
607
608	for (i=0; i<num_sids; i++) {
609		sid_copy(&sid2[i].sid, sids[i]);
610		sid2[i].num_auths = sid2[i].sid.num_auths;
611	}
612
613	result = cli_samr_query_useraliases(hnd->cli, mem_ctx, &dom_pol,
614					    num_sids, sid2,
615					    num_aliases, alias_rids);
616
617 done:
618
619	if (got_dom_pol)
620		cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
621
622	return result;
623}
624
625
626/* Lookup group membership given a rid.   */
627static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
628				TALLOC_CTX *mem_ctx,
629				const DOM_SID *group_sid, uint32 *num_names,
630				DOM_SID ***sid_mem, char ***names,
631				uint32 **name_types)
632{
633        CLI_POLICY_HND *hnd = NULL;
634        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
635        uint32 i, total_names = 0;
636        POLICY_HND dom_pol, group_pol;
637        uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
638        BOOL got_dom_pol = False, got_group_pol = False;
639	uint32 *rid_mem = NULL;
640	uint32 group_rid;
641	int retry;
642	unsigned int j;
643	fstring sid_string;
644
645	DEBUG(10,("rpc: lookup_groupmem %s sid=%s\n", domain->name, sid_to_string(sid_string, group_sid)));
646
647	if (!sid_peek_check_rid(&domain->sid, group_sid, &group_rid)) {
648		goto done;
649	}
650
651	*num_names = 0;
652
653	retry = 0;
654	do {
655	        /* Get sam handle */
656		if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)))
657			goto done;
658
659		/* Get domain handle */
660
661		result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
662				des_access, &domain->sid, &dom_pol);
663	} while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
664
665        if (!NT_STATUS_IS_OK(result))
666                goto done;
667
668        got_dom_pol = True;
669
670        /* Get group handle */
671
672        result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol,
673                                     des_access, group_rid, &group_pol);
674
675        if (!NT_STATUS_IS_OK(result))
676                goto done;
677
678        got_group_pol = True;
679
680        /* Step #1: Get a list of user rids that are the members of the
681           group. */
682
683        result = cli_samr_query_groupmem(hnd->cli, mem_ctx,
684                                         &group_pol, num_names, &rid_mem,
685                                         name_types);
686
687        if (!NT_STATUS_IS_OK(result))
688                goto done;
689
690	if (!*num_names) {
691		names = NULL;
692		name_types = NULL;
693		sid_mem = NULL;
694		goto done;
695	}
696
697        /* Step #2: Convert list of rids into list of usernames.  Do this
698           in bunches of ~1000 to avoid crashing NT4.  It looks like there
699           is a buffer overflow or something like that lurking around
700           somewhere. */
701
702#define MAX_LOOKUP_RIDS 900
703
704        *names = TALLOC_ZERO_ARRAY(mem_ctx, char *, *num_names);
705        *name_types = TALLOC_ZERO_ARRAY(mem_ctx, uint32, *num_names);
706        *sid_mem = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID *, *num_names);
707
708	for (j=0;j<(*num_names);j++) {
709		(*sid_mem)[j] = rid_to_talloced_sid(domain, mem_ctx, (rid_mem)[j]);
710	}
711
712	if (*num_names>0 && (!*names || !*name_types)) {
713		result = NT_STATUS_NO_MEMORY;
714		goto done;
715	}
716
717        for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
718                int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
719                uint32 tmp_num_names = 0;
720                char **tmp_names = NULL;
721                uint32 *tmp_types = NULL;
722
723                /* Lookup a chunk of rids */
724
725                result = cli_samr_lookup_rids(hnd->cli, mem_ctx,
726                                              &dom_pol,
727                                              num_lookup_rids,
728                                              &rid_mem[i],
729                                              &tmp_num_names,
730                                              &tmp_names, &tmp_types);
731
732		/* see if we have a real error (and yes the STATUS_SOME_UNMAPPED is
733		   the one returned from 2k) */
734
735                if (!NT_STATUS_IS_OK(result) && NT_STATUS_V(result) != NT_STATUS_V(STATUS_SOME_UNMAPPED))
736                        goto done;
737
738                /* Copy result into array.  The talloc system will take
739                   care of freeing the temporary arrays later on. */
740
741                memcpy(&(*names)[i], tmp_names, sizeof(char *) *
742                       tmp_num_names);
743
744                memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
745                       tmp_num_names);
746
747                total_names += tmp_num_names;
748        }
749
750        *num_names = total_names;
751
752 	result = NT_STATUS_OK;
753
754done:
755        if (got_group_pol)
756                cli_samr_close(hnd->cli, mem_ctx, &group_pol);
757
758        if (got_dom_pol)
759                cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
760
761        return result;
762}
763
764#ifdef HAVE_LDAP
765
766#include <ldap.h>
767
768static int get_ldap_seq(const char *server, int port, uint32 *seq)
769{
770	int ret = -1;
771	struct timeval to;
772	const char *attrs[] = {"highestCommittedUSN", NULL};
773	LDAPMessage *res = NULL;
774	char **values = NULL;
775	LDAP *ldp = NULL;
776
777	*seq = DOM_SEQUENCE_NONE;
778
779	/*
780	 * Parameterised (5) second timeout on open. This is needed as the search timeout
781	 * doesn't seem to apply to doing an open as well. JRA.
782	 */
783
784	if ((ldp = ldap_open_with_timeout(server, port, lp_ldap_timeout())) == NULL)
785		return -1;
786
787	/* Timeout if no response within 20 seconds. */
788	to.tv_sec = 10;
789	to.tv_usec = 0;
790
791	if (ldap_search_st(ldp, "", LDAP_SCOPE_BASE, "(objectclass=*)", &attrs[0], 0, &to, &res))
792		goto done;
793
794	if (ldap_count_entries(ldp, res) != 1)
795		goto done;
796
797	values = ldap_get_values(ldp, res, "highestCommittedUSN");
798	if (!values || !values[0])
799		goto done;
800
801	*seq = atoi(values[0]);
802	ret = 0;
803
804  done:
805
806	if (values)
807		ldap_value_free(values);
808	if (res)
809		ldap_msgfree(res);
810	if (ldp)
811		ldap_unbind(ldp);
812	return ret;
813}
814
815/**********************************************************************
816 Get the sequence number for a Windows AD native mode domain using
817 LDAP queries
818**********************************************************************/
819
820static int get_ldap_sequence_number( const char* domain, uint32 *seq)
821{
822	int ret = -1;
823	int i, port = LDAP_PORT;
824	struct ip_service *ip_list = NULL;
825	int count;
826
827	if ( !get_sorted_dc_list(domain, &ip_list, &count, False) ) {
828		DEBUG(3, ("Could not look up dc's for domain %s\n", domain));
829		return False;
830	}
831
832	/* Finally return first DC that we can contact */
833
834	for (i = 0; i < count; i++) {
835		fstring ipstr;
836
837		/* since the is an LDAP lookup, default to the LDAP_PORT is not set */
838		port = (ip_list[i].port!= PORT_NONE) ? ip_list[i].port : LDAP_PORT;
839
840		fstrcpy( ipstr, inet_ntoa(ip_list[i].ip) );
841
842		if (is_zero_ip(ip_list[i].ip))
843			continue;
844
845		if ( (ret = get_ldap_seq( ipstr, port,  seq)) == 0 )
846			goto done;
847
848		/* add to failed connection cache */
849		add_failed_connection_entry( domain, ipstr, NT_STATUS_UNSUCCESSFUL );
850	}
851
852done:
853	if ( ret == 0 ) {
854		DEBUG(3, ("get_ldap_sequence_number: Retrieved sequence number for Domain (%s) from DC (%s:%d)\n",
855			domain, inet_ntoa(ip_list[i].ip), port));
856	}
857
858	SAFE_FREE(ip_list);
859
860	return ret;
861}
862
863#endif /* HAVE_LDAP */
864
865/* find the sequence number for a domain */
866static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
867{
868	TALLOC_CTX *mem_ctx;
869	CLI_POLICY_HND *hnd;
870	SAM_UNK_CTR ctr;
871	NTSTATUS result;
872	POLICY_HND dom_pol;
873	BOOL got_dom_pol = False;
874	BOOL got_seq_num = False;
875	uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
876	int retry;
877
878	DEBUG(10,("rpc: fetch sequence_number for %s\n", domain->name));
879
880	*seq = DOM_SEQUENCE_NONE;
881
882	if (!(mem_ctx = talloc_init("sequence_number[rpc]")))
883		return NT_STATUS_NO_MEMORY;
884
885	retry = 0;
886	do {
887#ifdef HAVE_LDAP
888		if ( domain->native_mode )
889		{
890			DEBUG(8,("using get_ldap_seq() to retrieve the sequence number\n"));
891
892			if ( get_ldap_sequence_number( domain->name, seq ) == 0 ) {
893				result = NT_STATUS_OK;
894				DEBUG(10,("domain_sequence_number: LDAP for domain %s is %u\n",
895					domain->name, *seq));
896				goto done;
897			}
898
899			DEBUG(10,("domain_sequence_number: failed to get LDAP sequence number for domain %s\n",
900			domain->name ));
901		}
902#endif /* HAVE_LDAP */
903	        /* Get sam handle */
904		if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain, &hnd)))
905			goto done;
906
907		/* Get domain handle */
908		result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
909				      des_access, &domain->sid, &dom_pol);
910	} while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
911
912	if (!NT_STATUS_IS_OK(result))
913		goto done;
914
915	got_dom_pol = True;
916
917	/* Query domain info */
918
919	result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
920					 8, &ctr);
921
922	if (NT_STATUS_IS_OK(result)) {
923		*seq = ctr.info.inf8.seq_num.low;
924		got_seq_num = True;
925		goto seq_num;
926	}
927
928	/* retry with info-level 2 in case the dc does not support info-level 8
929	 * (like all older samba2 and samba3 dc's - Guenther */
930
931	result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
932					 2, &ctr);
933
934	if (NT_STATUS_IS_OK(result)) {
935		*seq = ctr.info.inf2.seq_num.low;
936		got_seq_num = True;
937	}
938
939 seq_num:
940	if (got_seq_num) {
941		DEBUG(10,("domain_sequence_number: for domain %s is %u\n", domain->name, (unsigned)*seq));
942	} else {
943		DEBUG(10,("domain_sequence_number: failed to get sequence number (%u) for domain %s\n",
944			(unsigned)*seq, domain->name ));
945	}
946
947  done:
948
949	if (got_dom_pol)
950		cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
951
952	talloc_destroy(mem_ctx);
953
954	return result;
955}
956
957/* get a list of trusted domains */
958static NTSTATUS trusted_domains(struct winbindd_domain *domain,
959				TALLOC_CTX *mem_ctx,
960				uint32 *num_domains,
961				char ***names,
962				char ***alt_names,
963				DOM_SID **dom_sids)
964{
965	CLI_POLICY_HND *hnd;
966	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
967	uint32 enum_ctx = 0;
968	int retry;
969
970	DEBUG(3,("rpc: trusted_domains\n"));
971
972	*num_domains = 0;
973	*names = NULL;
974	*alt_names = NULL;
975	*dom_sids = NULL;
976
977	retry = 0;
978	do {
979		if (!NT_STATUS_IS_OK(result = cm_get_lsa_handle(find_our_domain(), &hnd)))
980			goto done;
981
982		result = STATUS_MORE_ENTRIES;
983
984		while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) {
985			uint32 start_idx, num;
986			char **tmp_names;
987			DOM_SID *tmp_sids;
988			int i;
989
990			result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
991							&hnd->pol, &enum_ctx,
992							&num, &tmp_names,
993							&tmp_sids);
994
995			if (!NT_STATUS_IS_OK(result) &&
996			    !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
997				break;
998
999			start_idx = *num_domains;
1000			*num_domains += num;
1001			*names = TALLOC_REALLOC_ARRAY(mem_ctx, *names,
1002						      char *, *num_domains);
1003			*dom_sids = TALLOC_REALLOC_ARRAY(mem_ctx, *dom_sids,
1004							 DOM_SID,
1005							 *num_domains);
1006			if ((*names == NULL) || (*dom_sids == NULL))
1007				return NT_STATUS_NO_MEMORY;
1008
1009			for (i=0; i<num; i++) {
1010				(*names)[start_idx+i] = tmp_names[i];
1011				(*dom_sids)[start_idx+i] = tmp_sids[i];
1012			}
1013		}
1014	} while (!NT_STATUS_IS_OK(result) && (retry++ < 1) &&  hnd && hnd->cli && hnd->cli->fd == -1);
1015
1016done:
1017	return result;
1018}
1019
1020/* find the domain sid for a domain */
1021static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
1022{
1023	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1024	TALLOC_CTX *mem_ctx;
1025	CLI_POLICY_HND *hnd;
1026	char *level5_dom;
1027	DOM_SID *alloc_sid;
1028	int retry;
1029
1030	DEBUG(3,("rpc: domain_sid\n"));
1031
1032	if (!(mem_ctx = talloc_init("domain_sid[rpc]")))
1033		return NT_STATUS_NO_MEMORY;
1034
1035	retry = 0;
1036	do {
1037		/* Get lsa handle */
1038		if (!NT_STATUS_IS_OK(result = cm_get_lsa_handle(domain, &hnd)))
1039			goto done;
1040
1041		result = cli_lsa_query_info_policy(hnd->cli, mem_ctx,
1042					   &hnd->pol, 0x05, &level5_dom, &alloc_sid);
1043	} while (!NT_STATUS_IS_OK(result) && (retry++ < 1) &&  hnd && hnd->cli && hnd->cli->fd == -1);
1044
1045	if (NT_STATUS_IS_OK(result)) {
1046		if (alloc_sid) {
1047			sid_copy(sid, alloc_sid);
1048		} else {
1049			result = NT_STATUS_NO_MEMORY;
1050		}
1051	}
1052
1053done:
1054	talloc_destroy(mem_ctx);
1055	return result;
1056}
1057
1058/* find alternate names list for the domain - none for rpc */
1059static NTSTATUS alternate_name(struct winbindd_domain *domain)
1060{
1061	return NT_STATUS_OK;
1062}
1063
1064
1065/* the rpc backend methods are exposed via this structure */
1066struct winbindd_methods msrpc_methods = {
1067	False,
1068	query_user_list,
1069	enum_dom_groups,
1070	enum_local_groups,
1071	msrpc_name_to_sid,
1072	msrpc_sid_to_name,
1073	query_user,
1074	lookup_usergroups,
1075	msrpc_lookup_useraliases,
1076	lookup_groupmem,
1077	sequence_number,
1078	trusted_domains,
1079	domain_sid,
1080	alternate_name
1081};
1082