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