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