Fix the build of winbindd, sorry.
[samba.git] / source3 / winbindd / 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                 uint32_t total_size, returned_size;
67
68                 union samr_DispInfo disp_info;
69
70                 /* this next bit is copied from net_user_list_internal() */
71
72                 get_query_dispinfo_params(loop_count, &max_entries,
73                                           &max_size);
74
75                 result = rpccli_samr_QueryDisplayInfo(cli, mem_ctx,
76                                                       &dom_pol,
77                                                       1,
78                                                       start_idx,
79                                                       max_entries,
80                                                       max_size,
81                                                       &total_size,
82                                                       &returned_size,
83                                                       &disp_info);
84                 num_dom_users = disp_info.info1.count;
85                 start_idx += disp_info.info1.count;
86                 loop_count++;
87
88                 *num_entries += num_dom_users;
89
90                 *info = TALLOC_REALLOC_ARRAY(mem_ctx, *info, WINBIND_USERINFO,
91                                              *num_entries);
92
93                 if (!(*info)) {
94                         return NT_STATUS_NO_MEMORY;
95                 }
96
97                 for (j = 0; j < num_dom_users; i++, j++) {
98
99                         uint32_t rid = disp_info.info1.entries[j].rid;
100
101                         (*info)[i].acct_name = talloc_strdup(mem_ctx,
102                                 disp_info.info1.entries[j].account_name.string);
103                         (*info)[i].full_name = talloc_strdup(mem_ctx,
104                                 disp_info.info1.entries[j].full_name.string);
105                         (*info)[i].homedir = NULL;
106                         (*info)[i].shell = NULL;
107                         sid_compose(&(*info)[i].user_sid, &domain->sid, rid);
108                         
109                         /* For the moment we set the primary group for
110                            every user to be the Domain Users group.
111                            There are serious problems with determining
112                            the actual primary group for large domains.
113                            This should really be made into a 'winbind
114                            force group' smb.conf parameter or
115                            something like that. */
116                            
117                         sid_compose(&(*info)[i].group_sid, &domain->sid, 
118                                     DOMAIN_GROUP_RID_USERS);
119                 }
120
121         } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
122
123         return result;
124 }
125
126 /* list all domain groups */
127 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
128                                 TALLOC_CTX *mem_ctx,
129                                 uint32 *num_entries, 
130                                 struct acct_info **info)
131 {
132         POLICY_HND dom_pol;
133         NTSTATUS status;
134         uint32 start = 0;
135         struct rpc_pipe_client *cli;
136
137         *num_entries = 0;
138         *info = NULL;
139
140         DEBUG(3,("rpc: enum_dom_groups\n"));
141
142         if ( !winbindd_can_contact_domain( domain ) ) {
143                 DEBUG(10,("enum_domain_groups: No incoming trust for domain %s\n",
144                           domain->name));
145                 return NT_STATUS_OK;
146         }
147
148         status = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
149         if (!NT_STATUS_IS_OK(status))
150                 return status;
151
152         do {
153                 struct acct_info *info2 = NULL;
154                 uint32 count = 0;
155                 TALLOC_CTX *mem_ctx2;
156
157                 mem_ctx2 = talloc_init("enum_dom_groups[rpc]");
158
159                 /* start is updated by this call. */
160                 status = rpccli_samr_enum_dom_groups(cli, mem_ctx2, &dom_pol,
161                                                      &start,
162                                                      0xFFFF, /* buffer size? */
163                                                      &info2, &count);
164
165                 if (!NT_STATUS_IS_OK(status) && 
166                     !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
167                         talloc_destroy(mem_ctx2);
168                         break;
169                 }
170
171                 (*info) = TALLOC_REALLOC_ARRAY(mem_ctx, *info,
172                                                struct acct_info,
173                                                (*num_entries) + count);
174                 if (! *info) {
175                         talloc_destroy(mem_ctx2);
176                         return NT_STATUS_NO_MEMORY;
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 = NULL;
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_dbg(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         union samr_UserInfo *info = NULL;
413         uint32 user_rid;
414         NET_USER_INFO_3 *user;
415         struct rpc_pipe_client *cli;
416
417         DEBUG(3,("rpc: query_user sid=%s\n", sid_string_dbg(user_sid)));
418
419         if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid))
420                 return NT_STATUS_UNSUCCESSFUL;
421         
422         user_info->homedir = NULL;
423         user_info->shell = NULL;
424         user_info->primary_gid = (gid_t)-1;
425                                                 
426         /* try netsamlogon cache first */
427                         
428         if ( (user = netsamlogon_cache_get( mem_ctx, user_sid )) != NULL ) 
429         {
430                                 
431                 DEBUG(5,("query_user: Cache lookup succeeded for %s\n", 
432                         sid_string_dbg(user_sid)));
433
434                 sid_compose(&user_info->user_sid, &domain->sid, user->user_rid);
435                 sid_compose(&user_info->group_sid, &domain->sid,
436                             user->group_rid);
437                                 
438                 user_info->acct_name = unistr2_to_ascii_talloc(mem_ctx,
439                                                     &user->uni_user_name);
440                 user_info->full_name = unistr2_to_ascii_talloc(mem_ctx,
441                                                     &user->uni_full_name);
442                 
443                 TALLOC_FREE(user);
444                                                 
445                 return NT_STATUS_OK;
446         }
447                                 
448         if ( !winbindd_can_contact_domain( domain ) ) {
449                 DEBUG(10,("query_user: No incoming trust for domain %s\n",
450                           domain->name));
451                 return NT_STATUS_OK;
452         }
453         
454         if ( !winbindd_can_contact_domain( domain ) ) {
455                 DEBUG(10,("query_user: No incoming trust for domain %s\n",
456                           domain->name));
457                 return NT_STATUS_OK;
458         }
459         
460         if ( !winbindd_can_contact_domain( domain ) ) {
461                 DEBUG(10,("query_user: No incoming trust for domain %s\n",
462                           domain->name));
463                 return NT_STATUS_OK;
464         }
465         
466         /* no cache; hit the wire */
467                 
468         result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
469         if (!NT_STATUS_IS_OK(result))
470                 return result;
471
472         /* Get user handle */
473         result = rpccli_samr_OpenUser(cli, mem_ctx,
474                                       &dom_pol,
475                                       SEC_RIGHTS_MAXIMUM_ALLOWED,
476                                       user_rid,
477                                       &user_pol);
478
479         if (!NT_STATUS_IS_OK(result))
480                 return result;
481
482         /* Get user info */
483         result = rpccli_samr_QueryUserInfo(cli, mem_ctx,
484                                            &user_pol,
485                                            0x15,
486                                            &info);
487
488         rpccli_samr_Close(cli, mem_ctx, &user_pol);
489
490         if (!NT_STATUS_IS_OK(result))
491                 return result;
492
493         sid_compose(&user_info->user_sid, &domain->sid, user_rid);
494         sid_compose(&user_info->group_sid, &domain->sid,
495                     info->info21.primary_gid);
496         user_info->acct_name = talloc_strdup(mem_ctx,
497                                              info->info21.account_name.string);
498         user_info->full_name = talloc_strdup(mem_ctx,
499                                              info->info21.full_name.string);
500         user_info->homedir = NULL;
501         user_info->shell = NULL;
502         user_info->primary_gid = (gid_t)-1;
503
504         return NT_STATUS_OK;
505 }                                   
506
507 /* Lookup groups a user is a member of.  I wish Unix had a call like this! */
508 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
509                                   TALLOC_CTX *mem_ctx,
510                                   const DOM_SID *user_sid,
511                                   uint32 *num_groups, DOM_SID **user_grpsids)
512 {
513         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
514         POLICY_HND dom_pol, user_pol;
515         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
516         struct samr_RidWithAttributeArray *rid_array = NULL;
517         unsigned int i;
518         uint32 user_rid;
519         struct rpc_pipe_client *cli;
520
521         DEBUG(3,("rpc: lookup_usergroups sid=%s\n", sid_string_dbg(user_sid)));
522
523         if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid))
524                 return NT_STATUS_UNSUCCESSFUL;
525
526         *num_groups = 0;
527         *user_grpsids = NULL;
528
529         /* so lets see if we have a cached user_info_3 */
530         result = lookup_usergroups_cached(domain, mem_ctx, user_sid, 
531                                           num_groups, user_grpsids);
532
533         if (NT_STATUS_IS_OK(result)) {
534                 return NT_STATUS_OK;
535         }
536
537         if ( !winbindd_can_contact_domain( domain ) ) {
538                 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
539                           domain->name));
540
541                 /* Tell the cache manager not to remember this one */
542
543                 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
544         }
545
546         /* no cache; hit the wire */
547         
548         result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
549         if (!NT_STATUS_IS_OK(result))
550                 return result;
551
552         /* Get user handle */
553         result = rpccli_samr_OpenUser(cli, mem_ctx,
554                                       &dom_pol,
555                                       des_access,
556                                       user_rid,
557                                       &user_pol);
558
559         if (!NT_STATUS_IS_OK(result))
560                 return result;
561
562         /* Query user rids */
563         result = rpccli_samr_GetGroupsForUser(cli, mem_ctx,
564                                               &user_pol,
565                                               &rid_array);
566         *num_groups = rid_array->count;
567
568         rpccli_samr_Close(cli, mem_ctx, &user_pol);
569
570         if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
571                 return result;
572
573         (*user_grpsids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
574         if (!(*user_grpsids))
575                 return NT_STATUS_NO_MEMORY;
576
577         for (i=0;i<(*num_groups);i++) {
578                 sid_copy(&((*user_grpsids)[i]), &domain->sid);
579                 sid_append_rid(&((*user_grpsids)[i]),
580                                 rid_array->rids[i].rid);
581         }
582
583         return NT_STATUS_OK;
584 }
585
586 NTSTATUS msrpc_lookup_useraliases(struct winbindd_domain *domain,
587                                   TALLOC_CTX *mem_ctx,
588                                   uint32 num_sids, const DOM_SID *sids,
589                                   uint32 *num_aliases, uint32 **alias_rids)
590 {
591         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
592         POLICY_HND dom_pol;
593         uint32 num_query_sids = 0;
594         int i;
595         struct rpc_pipe_client *cli;
596         struct samr_Ids alias_rids_query;
597         int rangesize = MAX_SAM_ENTRIES_W2K;
598         uint32 total_sids = 0;
599         int num_queries = 1;
600
601         *num_aliases = 0;
602         *alias_rids = NULL;
603
604         DEBUG(3,("rpc: lookup_useraliases\n"));
605
606         if ( !winbindd_can_contact_domain( domain ) ) {
607                 DEBUG(10,("msrpc_lookup_useraliases: No incoming trust for domain %s\n",
608                           domain->name));
609                 return NT_STATUS_OK;
610         }
611
612         result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
613         if (!NT_STATUS_IS_OK(result))
614                 return result;
615
616         do {
617                 /* prepare query */
618                 struct lsa_SidArray sid_array;
619
620                 ZERO_STRUCT(sid_array);
621
622                 num_query_sids = MIN(num_sids - total_sids, rangesize);
623
624                 DEBUG(10,("rpc: lookup_useraliases: entering query %d for %d sids\n", 
625                         num_queries, num_query_sids));  
626
627                 if (num_query_sids) {
628                         sid_array.sids = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_SidPtr, num_query_sids);
629                         if (sid_array.sids == NULL) {
630                                 return NT_STATUS_NO_MEMORY;
631                         }
632                 } else {
633                         sid_array.sids = NULL;
634                 }
635
636                 for (i=0; i<num_query_sids; i++) {
637                         sid_array.sids[i].sid = sid_dup_talloc(mem_ctx, &sids[total_sids++]);
638                         if (!sid_array.sids[i].sid) {
639                                 TALLOC_FREE(sid_array.sids);
640                                 return NT_STATUS_NO_MEMORY;
641                         }
642                 }
643                 sid_array.num_sids = num_query_sids;
644
645                 /* do request */
646                 result = rpccli_samr_GetAliasMembership(cli, mem_ctx,
647                                                         &dom_pol,
648                                                         &sid_array,
649                                                         &alias_rids_query);
650
651                 if (!NT_STATUS_IS_OK(result)) {
652                         *num_aliases = 0;
653                         *alias_rids = NULL;
654                         TALLOC_FREE(sid_array.sids);
655                         goto done;
656                 }
657
658                 /* process output */
659
660                 for (i=0; i<alias_rids_query.count; i++) {
661                         size_t na = *num_aliases;
662                         if (!add_rid_to_array_unique(mem_ctx, alias_rids_query.ids[i],
663                                                 alias_rids, &na)) {
664                                 return NT_STATUS_NO_MEMORY;
665                         }
666                         *num_aliases = na;
667                 }
668
669                 TALLOC_FREE(sid_array.sids);
670
671                 num_queries++;
672
673         } while (total_sids < num_sids);
674
675  done:
676         DEBUG(10,("rpc: lookup_useraliases: got %d aliases in %d queries "
677                 "(rangesize: %d)\n", *num_aliases, num_queries, rangesize));
678
679         return result;
680 }
681
682
683 /* Lookup group membership given a rid.   */
684 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
685                                 TALLOC_CTX *mem_ctx,
686                                 const DOM_SID *group_sid, uint32 *num_names, 
687                                 DOM_SID **sid_mem, char ***names, 
688                                 uint32 **name_types)
689 {
690         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
691         uint32 i, total_names = 0;
692         POLICY_HND dom_pol, group_pol;
693         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
694         uint32 *rid_mem = NULL;
695         uint32 group_rid;
696         unsigned int j;
697         struct rpc_pipe_client *cli;
698         unsigned int orig_timeout;
699         struct samr_RidTypeArray *rids = NULL;
700
701         DEBUG(10,("rpc: lookup_groupmem %s sid=%s\n", domain->name,
702                   sid_string_dbg(group_sid)));
703
704         if ( !winbindd_can_contact_domain( domain ) ) {
705                 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
706                           domain->name));
707                 return NT_STATUS_OK;
708         }
709
710         if (!sid_peek_check_rid(&domain->sid, group_sid, &group_rid))
711                 return NT_STATUS_UNSUCCESSFUL;
712
713         *num_names = 0;
714
715         result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
716         if (!NT_STATUS_IS_OK(result))
717                 return result;
718
719         result = rpccli_samr_OpenGroup(cli, mem_ctx,
720                                        &dom_pol,
721                                        des_access,
722                                        group_rid,
723                                        &group_pol);
724
725         if (!NT_STATUS_IS_OK(result))
726                 return result;
727
728         /* Step #1: Get a list of user rids that are the members of the
729            group. */
730
731         /* This call can take a long time - allow the server to time out.
732            35 seconds should do it. */
733
734         orig_timeout = cli_set_timeout(cli->cli, 35000);
735
736         result = rpccli_samr_QueryGroupMember(cli, mem_ctx,
737                                               &group_pol,
738                                               &rids);
739
740         /* And restore our original timeout. */
741         cli_set_timeout(cli->cli, orig_timeout);
742
743         rpccli_samr_Close(cli, mem_ctx, &group_pol);
744
745         if (!NT_STATUS_IS_OK(result))
746                 return result;
747
748         *num_names = rids->count;
749         rid_mem = rids->rids;
750
751         if (!*num_names) {
752                 names = NULL;
753                 name_types = NULL;
754                 sid_mem = NULL;
755                 return NT_STATUS_OK;
756         }
757
758         /* Step #2: Convert list of rids into list of usernames.  Do this
759            in bunches of ~1000 to avoid crashing NT4.  It looks like there
760            is a buffer overflow or something like that lurking around
761            somewhere. */
762
763 #define MAX_LOOKUP_RIDS 900
764
765         *names = TALLOC_ZERO_ARRAY(mem_ctx, char *, *num_names);
766         *name_types = TALLOC_ZERO_ARRAY(mem_ctx, uint32, *num_names);
767         *sid_mem = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, *num_names);
768
769         for (j=0;j<(*num_names);j++)
770                 sid_compose(&(*sid_mem)[j], &domain->sid, rid_mem[j]);
771         
772         if (*num_names>0 && (!*names || !*name_types))
773                 return NT_STATUS_NO_MEMORY;
774
775         for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
776                 int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
777                 uint32 tmp_num_names = 0;
778                 char **tmp_names = NULL;
779                 uint32 *tmp_types = NULL;
780
781                 /* Lookup a chunk of rids */
782
783                 result = rpccli_samr_lookup_rids(cli, mem_ctx,
784                                                  &dom_pol,
785                                                  num_lookup_rids,
786                                                  &rid_mem[i],
787                                                  &tmp_num_names,
788                                                  &tmp_names, &tmp_types);
789
790                 /* see if we have a real error (and yes the
791                    STATUS_SOME_UNMAPPED is the one returned from 2k) */
792                 
793                 if (!NT_STATUS_IS_OK(result) &&
794                     !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED))
795                         return result;
796                         
797                 /* Copy result into array.  The talloc system will take
798                    care of freeing the temporary arrays later on. */
799
800                 memcpy(&(*names)[i], tmp_names, sizeof(char *) * 
801                        tmp_num_names);
802
803                 memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
804                        tmp_num_names);
805                 
806                 total_names += tmp_num_names;
807         }
808
809         *num_names = total_names;
810
811         return NT_STATUS_OK;
812 }
813
814 #ifdef HAVE_LDAP
815
816 #include <ldap.h>
817
818 static int get_ldap_seq(const char *server, int port, uint32 *seq)
819 {
820         int ret = -1;
821         struct timeval to;
822         const char *attrs[] = {"highestCommittedUSN", NULL};
823         LDAPMessage *res = NULL;
824         char **values = NULL;
825         LDAP *ldp = NULL;
826
827         *seq = DOM_SEQUENCE_NONE;
828
829         /*
830          * Parameterised (5) second timeout on open. This is needed as the
831          * search timeout doesn't seem to apply to doing an open as well. JRA.
832          */
833
834         ldp = ldap_open_with_timeout(server, port, lp_ldap_timeout());
835         if (ldp == NULL)
836                 return -1;
837
838         /* Timeout if no response within 20 seconds. */
839         to.tv_sec = 10;
840         to.tv_usec = 0;
841
842         if (ldap_search_st(ldp, "", LDAP_SCOPE_BASE, "(objectclass=*)",
843                            CONST_DISCARD(char **, attrs), 0, &to, &res))
844                 goto done;
845
846         if (ldap_count_entries(ldp, res) != 1)
847                 goto done;
848
849         values = ldap_get_values(ldp, res, "highestCommittedUSN");
850         if (!values || !values[0])
851                 goto done;
852
853         *seq = atoi(values[0]);
854         ret = 0;
855
856   done:
857
858         if (values)
859                 ldap_value_free(values);
860         if (res)
861                 ldap_msgfree(res);
862         if (ldp)
863                 ldap_unbind(ldp);
864         return ret;
865 }
866
867 /**********************************************************************
868  Get the sequence number for a Windows AD native mode domain using
869  LDAP queries.
870 **********************************************************************/
871
872 static int get_ldap_sequence_number(struct winbindd_domain *domain, uint32 *seq)
873 {
874         int ret = -1;
875         char addr[INET6_ADDRSTRLEN];
876
877         print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
878         if ((ret = get_ldap_seq(addr, LDAP_PORT, seq)) == 0) {
879                 DEBUG(3, ("get_ldap_sequence_number: Retrieved sequence "
880                           "number for Domain (%s) from DC (%s)\n",
881                         domain->name, addr));
882         }
883         return ret;
884 }
885
886 #endif /* HAVE_LDAP */
887
888 /* find the sequence number for a domain */
889 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
890 {
891         TALLOC_CTX *mem_ctx;
892         union samr_DomainInfo *info = NULL;
893         NTSTATUS result;
894         POLICY_HND dom_pol;
895         bool got_seq_num = False;
896         struct rpc_pipe_client *cli;
897
898         DEBUG(10,("rpc: fetch sequence_number for %s\n", domain->name));
899
900         if ( !winbindd_can_contact_domain( domain ) ) {
901                 DEBUG(10,("sequence_number: No incoming trust for domain %s\n",
902                           domain->name));
903                 *seq = time(NULL);
904                 return NT_STATUS_OK;
905         }
906
907         *seq = DOM_SEQUENCE_NONE;
908
909         if (!(mem_ctx = talloc_init("sequence_number[rpc]")))
910                 return NT_STATUS_NO_MEMORY;
911
912 #ifdef HAVE_LDAP
913         if ( domain->active_directory ) 
914         {
915                 int res;
916
917                 DEBUG(8,("using get_ldap_seq() to retrieve the "
918                          "sequence number\n"));
919
920                 res =  get_ldap_sequence_number( domain, seq );
921                 if (res == 0)
922                 {                       
923                         result = NT_STATUS_OK;
924                         DEBUG(10,("domain_sequence_number: LDAP for "
925                                   "domain %s is %u\n",
926                                   domain->name, *seq));
927                         goto done;
928                 }
929
930                 DEBUG(10,("domain_sequence_number: failed to get LDAP "
931                           "sequence number for domain %s\n",
932                           domain->name ));
933         }
934 #endif /* HAVE_LDAP */
935
936         result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
937         if (!NT_STATUS_IS_OK(result)) {
938                 goto done;
939         }
940
941         /* Query domain info */
942
943         result = rpccli_samr_QueryDomainInfo(cli, mem_ctx,
944                                              &dom_pol,
945                                              8,
946                                              &info);
947
948         if (NT_STATUS_IS_OK(result)) {
949                 *seq = info->info8.sequence_num;
950                 got_seq_num = True;
951                 goto seq_num;
952         }
953
954         /* retry with info-level 2 in case the dc does not support info-level 8
955          * (like all older samba2 and samba3 dc's) - Guenther */
956
957         result = rpccli_samr_QueryDomainInfo(cli, mem_ctx,
958                                              &dom_pol,
959                                              2,
960                                              &info);
961
962         if (NT_STATUS_IS_OK(result)) {
963                 *seq = info->info2.sequence_num;
964                 got_seq_num = True;
965         }
966
967  seq_num:
968         if (got_seq_num) {
969                 DEBUG(10,("domain_sequence_number: for domain %s is %u\n",
970                           domain->name, (unsigned)*seq));
971         } else {
972                 DEBUG(10,("domain_sequence_number: failed to get sequence "
973                           "number (%u) for domain %s\n",
974                           (unsigned)*seq, domain->name ));
975         }
976
977   done:
978
979         talloc_destroy(mem_ctx);
980
981         return result;
982 }
983
984 /* get a list of trusted domains */
985 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
986                                 TALLOC_CTX *mem_ctx,
987                                 uint32 *num_domains,
988                                 char ***names,
989                                 char ***alt_names,
990                                 DOM_SID **dom_sids)
991 {
992         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
993         uint32 enum_ctx = 0;
994         struct rpc_pipe_client *cli;
995         POLICY_HND lsa_policy;
996
997         DEBUG(3,("rpc: trusted_domains\n"));
998
999         *num_domains = 0;
1000         *names = NULL;
1001         *alt_names = NULL;
1002         *dom_sids = NULL;
1003
1004         result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
1005         if (!NT_STATUS_IS_OK(result))
1006                 return result;
1007
1008         result = STATUS_MORE_ENTRIES;
1009
1010         while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) {
1011                 uint32 start_idx;
1012                 int i;
1013                 struct lsa_DomainList dom_list;
1014
1015                 result = rpccli_lsa_EnumTrustDom(cli, mem_ctx,
1016                                                  &lsa_policy,
1017                                                  &enum_ctx,
1018                                                  &dom_list,
1019                                                  (uint32_t)-1);
1020
1021                 if (!NT_STATUS_IS_OK(result) &&
1022                     !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
1023                         break;
1024
1025                 start_idx = *num_domains;
1026                 *num_domains += dom_list.count;
1027                 *names = TALLOC_REALLOC_ARRAY(mem_ctx, *names,
1028                                               char *, *num_domains);
1029                 *dom_sids = TALLOC_REALLOC_ARRAY(mem_ctx, *dom_sids,
1030                                                  DOM_SID, *num_domains);
1031                 *alt_names = TALLOC_REALLOC_ARRAY(mem_ctx, *alt_names,
1032                                                  char *, *num_domains);
1033                 if ((*names == NULL) || (*dom_sids == NULL) ||
1034                     (*alt_names == NULL))
1035                         return NT_STATUS_NO_MEMORY;
1036
1037                 for (i=0; i<dom_list.count; i++) {
1038                         (*names)[start_idx+i] = CONST_DISCARD(char *, dom_list.domains[i].name.string);
1039                         (*dom_sids)[start_idx+i] = *dom_list.domains[i].sid;
1040                         (*alt_names)[start_idx+i] = talloc_strdup(mem_ctx, "");
1041                 }
1042         }
1043         return result;
1044 }
1045
1046 /* find the lockout policy for a domain */
1047 NTSTATUS msrpc_lockout_policy(struct winbindd_domain *domain,
1048                               TALLOC_CTX *mem_ctx,
1049                               struct samr_DomInfo12 *lockout_policy)
1050 {
1051         NTSTATUS result;
1052         struct rpc_pipe_client *cli;
1053         POLICY_HND dom_pol;
1054         union samr_DomainInfo *info = NULL;
1055
1056         DEBUG(10,("rpc: fetch lockout policy for %s\n", domain->name));
1057
1058         if ( !winbindd_can_contact_domain( domain ) ) {
1059                 DEBUG(10,("msrpc_lockout_policy: No incoming trust for domain %s\n",
1060                           domain->name));
1061                 return NT_STATUS_NOT_SUPPORTED;
1062         }
1063
1064         result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
1065         if (!NT_STATUS_IS_OK(result)) {
1066                 goto done;
1067         }
1068
1069         result = rpccli_samr_QueryDomainInfo(cli, mem_ctx,
1070                                              &dom_pol,
1071                                              12,
1072                                              &info);
1073         if (!NT_STATUS_IS_OK(result)) {
1074                 goto done;
1075         }
1076
1077         *lockout_policy = info->info12;
1078
1079         DEBUG(10,("msrpc_lockout_policy: lockout_threshold %d\n",
1080                 info->info12.lockout_threshold));
1081
1082   done:
1083
1084         return result;
1085 }
1086
1087 /* find the password policy for a domain */
1088 NTSTATUS msrpc_password_policy(struct winbindd_domain *domain,
1089                                TALLOC_CTX *mem_ctx,
1090                                struct samr_DomInfo1 *password_policy)
1091 {
1092         NTSTATUS result;
1093         struct rpc_pipe_client *cli;
1094         POLICY_HND dom_pol;
1095         union samr_DomainInfo *info = NULL;
1096
1097         DEBUG(10,("rpc: fetch password policy for %s\n", domain->name));
1098
1099         if ( !winbindd_can_contact_domain( domain ) ) {
1100                 DEBUG(10,("msrpc_password_policy: No incoming trust for domain %s\n",
1101                           domain->name));
1102                 return NT_STATUS_NOT_SUPPORTED;
1103         }
1104
1105         result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
1106         if (!NT_STATUS_IS_OK(result)) {
1107                 goto done;
1108         }
1109
1110         result = rpccli_samr_QueryDomainInfo(cli, mem_ctx,
1111                                              &dom_pol,
1112                                              1,
1113                                              &info);
1114         if (!NT_STATUS_IS_OK(result)) {
1115                 goto done;
1116         }
1117
1118         *password_policy = info->info1;
1119
1120         DEBUG(10,("msrpc_password_policy: min_length_password %d\n",
1121                 info->info1.min_password_length));
1122
1123   done:
1124
1125         return result;
1126 }
1127
1128
1129 /* the rpc backend methods are exposed via this structure */
1130 struct winbindd_methods msrpc_methods = {
1131         False,
1132         query_user_list,
1133         enum_dom_groups,
1134         enum_local_groups,
1135         msrpc_name_to_sid,
1136         msrpc_sid_to_name,
1137         msrpc_rids_to_names,
1138         query_user,
1139         lookup_usergroups,
1140         msrpc_lookup_useraliases,
1141         lookup_groupmem,
1142         sequence_number,
1143         msrpc_lockout_policy,
1144         msrpc_password_policy,
1145         trusted_domains,
1146 };