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