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