possibly fix the 15000 user problem
[sfrench/samba-autobuild/.git] / source3 / nsswitch / winbindd_rpc.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind rpc backend functions
5
6    Copyright (C) Tim Potter 2000-2001
7    Copyright (C) Andrew Tridgell 2001
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "winbindd.h"
25
26 /* Query display info for a domain.  This returns enough information plus a
27    bit extra to give an overview of domain users for the User Manager
28    application. */
29 static NTSTATUS query_user_list(struct winbindd_domain *domain,
30                                TALLOC_CTX *mem_ctx,
31                                uint32 *num_entries, 
32                                WINBIND_USERINFO **info)
33 {
34         CLI_POLICY_HND *hnd;
35         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
36         POLICY_HND dom_pol;
37         BOOL got_dom_pol = False;
38         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
39         int i;
40
41         *num_entries = 0;
42         *info = NULL;
43
44         /* Get sam handle */
45
46         if (!(hnd = cm_get_sam_handle(domain->name)))
47                 goto done;
48
49         /* Get domain handle */
50
51         result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
52                                         des_access, &domain->sid, &dom_pol);
53
54         if (!NT_STATUS_IS_OK(result))
55                 goto done;
56
57         got_dom_pol = True;
58
59         i = 0;
60         do {
61                 SAM_DISPINFO_CTR ctr;
62                 SAM_DISPINFO_1 info1;
63                 uint32 count = 0, start=i;
64                 int j;
65                 TALLOC_CTX *ctx2;
66
67                 ctr.sam.info1 = &info1;
68
69                 ctx2 = talloc_init_named("winbindd dispinfo");
70                 if (!ctx2) {
71                         result = NT_STATUS_NO_MEMORY;
72                         goto done;
73                 }
74                 
75                 /* Query display info level 1 */
76                 result = cli_samr_query_dispinfo(hnd->cli, ctx2,
77                                                  &dom_pol, &start, 1,
78                                                  &count, 0xFFFF, &ctr);
79
80                 if (!NT_STATUS_IS_OK(result) && 
81                     !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) break;
82
83                 (*num_entries) += count;
84
85                 /* now map the result into the WINBIND_USERINFO structure */
86                 (*info) = talloc_realloc(mem_ctx, *info,
87                                          (*num_entries)*sizeof(WINBIND_USERINFO));
88                 if (!(*info)) {
89                         result = NT_STATUS_NO_MEMORY;
90                         talloc_destroy(ctx2);
91                         goto done;
92                 }
93
94                 for (j=0;j<count;i++, j++) {
95                         (*info)[i].acct_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_acct_name);
96                         (*info)[i].full_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_full_name);
97                         (*info)[i].user_rid = info1.sam[j].rid_user;
98                         /* For the moment we set the primary group for
99                            every user to be the Domain Users group.
100                            There are serious problems with determining
101                            the actual primary group for large domains.
102                            This should really be made into a 'winbind
103                            force group' smb.conf parameter or
104                            something like that. */
105                         (*info)[i].group_rid = DOMAIN_GROUP_RID_USERS;
106                 }
107
108                 talloc_destroy(ctx2);
109         } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
110
111  done:
112
113         if (got_dom_pol)
114                 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
115
116         return result;
117 }
118
119 /* list all domain groups */
120 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
121                                 TALLOC_CTX *mem_ctx,
122                                 uint32 *num_entries, 
123                                 struct acct_info **info)
124 {
125         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
126         CLI_POLICY_HND *hnd;
127         POLICY_HND dom_pol;
128         NTSTATUS status;
129
130         *num_entries = 0;
131         *info = NULL;
132
133         if (!(hnd = cm_get_sam_handle(domain->name))) {
134                 return NT_STATUS_UNSUCCESSFUL;
135         }
136
137         status = cli_samr_open_domain(hnd->cli, mem_ctx,
138                                       &hnd->pol, des_access, &domain->sid, &dom_pol);
139         if (!NT_STATUS_IS_OK(status)) {
140                 return status;
141         }
142
143         do {
144                 struct acct_info *info2 = NULL;
145                 uint32 count = 0, start = *num_entries;
146                 TALLOC_CTX *mem_ctx2;
147
148                 mem_ctx2 = talloc_init_named("enum_dom_groups[rpc]");
149
150                 status = cli_samr_enum_dom_groups(hnd->cli, mem_ctx2, &dom_pol,
151                                                   &start,
152                                                   0xFFFF, /* buffer size? */
153                                                   &info2, &count);
154
155                 if (!NT_STATUS_IS_OK(status) && 
156                     !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
157                         talloc_destroy(mem_ctx2);
158                         break;
159                 }
160
161                 (*info) = talloc_realloc(mem_ctx, *info, 
162                                          sizeof(**info) * ((*num_entries) + count));
163                 if (! *info) {
164                         talloc_destroy(mem_ctx2);
165                         cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
166                         return NT_STATUS_NO_MEMORY;
167                 }
168
169                 memcpy(&(*info)[*num_entries], info2, count*sizeof(*info2));
170                 (*num_entries) += count;
171                 talloc_destroy(mem_ctx2);
172         } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
173
174         cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
175
176         return status;
177 }
178
179 /* convert a single name to a sid in a domain */
180 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
181                             const char *name,
182                             DOM_SID *sid,
183                             enum SID_NAME_USE *type)
184 {
185         TALLOC_CTX *mem_ctx;
186         CLI_POLICY_HND *hnd;
187         NTSTATUS status;
188         DOM_SID *sids = NULL;
189         uint32 *types = NULL;
190         int num_sids;
191         const char *full_name;
192
193         if (!(mem_ctx = talloc_init_named("name_to_sid[rpc] for [%s]\\[%s]", domain->name, name))) {
194                 DEBUG(0, ("talloc_init failed!\n"));
195                 return NT_STATUS_NO_MEMORY;
196         }
197         
198         if (!(hnd = cm_get_lsa_handle(domain->name))) {
199                 talloc_destroy(mem_ctx);
200                 return NT_STATUS_UNSUCCESSFUL;
201         }
202         
203         full_name = talloc_asprintf(mem_ctx, "%s\\%s", domain->name, name);
204         
205         if (!full_name) {
206                 DEBUG(0, ("talloc_asprintf failed!\n"));
207                 talloc_destroy(mem_ctx);
208                 return NT_STATUS_NO_MEMORY;
209         }
210
211         status = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, 1, 
212                                       &full_name, &sids, &types, &num_sids);
213         
214         /* Return rid and type if lookup successful */        
215         if (NT_STATUS_IS_OK(status)) {
216                 sid_copy(sid, &sids[0]);
217                 *type = types[0];
218         }
219
220         talloc_destroy(mem_ctx);
221         return status;
222 }
223
224 /*
225   convert a domain SID to a user or group name
226 */
227 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
228                             TALLOC_CTX *mem_ctx,
229                             DOM_SID *sid,
230                             char **name,
231                             enum SID_NAME_USE *type)
232 {
233         CLI_POLICY_HND *hnd;
234         char **domains;
235         char **names;
236         uint32 *types;
237         int num_names;
238         NTSTATUS status;
239
240         if (!(hnd = cm_get_lsa_handle(domain->name)))
241                 return NT_STATUS_UNSUCCESSFUL;
242         
243         status = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol,
244                                      1, sid, &domains, &names, &types, 
245                                      &num_names);
246
247         if (NT_STATUS_IS_OK(status)) {
248                 *type = types[0];
249                 *name = names[0];
250                 DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name));
251
252                 /* Paranoia */
253                 if (strcasecmp(domain->name, domains[0]) != 0) {
254                         DEBUG(1, ("domain name from domain param and PDC lookup return differ! (%s vs %s)\n", domain->name, domains[0]));
255                         return NT_STATUS_UNSUCCESSFUL;
256                 }
257         }
258         return status;
259 }
260
261 /* Lookup user information from a rid or username. */
262 static NTSTATUS query_user(struct winbindd_domain *domain, 
263                            TALLOC_CTX *mem_ctx, 
264                            uint32 user_rid, 
265                            WINBIND_USERINFO *user_info)
266 {
267         CLI_POLICY_HND *hnd;
268         NTSTATUS result;
269         POLICY_HND dom_pol, user_pol;
270         BOOL got_dom_pol = False, got_user_pol = False;
271         SAM_USERINFO_CTR *ctr;
272
273         /* Get sam handle */
274         if (!(hnd = cm_get_sam_handle(domain->name)))
275                 goto done;
276
277         /* Get domain handle */
278
279         result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
280                                       SEC_RIGHTS_MAXIMUM_ALLOWED, 
281                                       &domain->sid, &dom_pol);
282
283         if (!NT_STATUS_IS_OK(result))
284                 goto done;
285
286         got_dom_pol = True;
287
288         /* Get user handle */
289         result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
290                                     SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
291
292         if (!NT_STATUS_IS_OK(result))
293                 goto done;
294
295         got_user_pol = True;
296
297         /* Get user info */
298         result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol, 
299                                          0x15, &ctr);
300
301         cli_samr_close(hnd->cli, mem_ctx, &user_pol);
302         got_user_pol = False;
303
304         user_info->group_rid = ctr->info.id21->group_rid;
305         user_info->acct_name = unistr2_tdup(mem_ctx, 
306                                             &ctr->info.id21->uni_user_name);
307         user_info->full_name = unistr2_tdup(mem_ctx, 
308                                             &ctr->info.id21->uni_full_name);
309
310  done:
311         /* Clean up policy handles */
312         if (got_user_pol)
313                 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
314
315         if (got_dom_pol)
316                 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
317
318         return result;
319 }                                   
320
321 /* Lookup groups a user is a member of.  I wish Unix had a call like this! */
322 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
323                                   TALLOC_CTX *mem_ctx,
324                                   uint32 user_rid, 
325                                   uint32 *num_groups, uint32 **user_gids)
326 {
327         CLI_POLICY_HND *hnd;
328         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
329         POLICY_HND dom_pol, user_pol;
330         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
331         BOOL got_dom_pol = False, got_user_pol = False;
332         DOM_GID *user_groups;
333         int i;
334
335         *num_groups = 0;
336
337         /* First try cached universal groups from logon */
338         *user_gids = uni_group_cache_fetch(&domain->sid, user_rid, mem_ctx, num_groups);
339         if((*num_groups > 0) && *user_gids) {
340                 return NT_STATUS_OK;
341         } else {
342             *user_gids = NULL;
343             *num_groups = 0;
344         }
345
346         /* Get sam handle */
347         if (!(hnd = cm_get_sam_handle(domain->name)))
348                 goto done;
349
350         /* Get domain handle */
351         result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
352                                         des_access, &domain->sid, &dom_pol);
353
354         if (!NT_STATUS_IS_OK(result))
355                 goto done;
356
357         got_dom_pol = True;
358
359         /* Get user handle */
360         result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
361                                         des_access, user_rid, &user_pol);
362
363         if (!NT_STATUS_IS_OK(result))
364                 goto done;
365
366         got_user_pol = True;
367
368         /* Query user rids */
369         result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol, 
370                                            num_groups, &user_groups);
371
372         if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
373                 goto done;
374
375         (*user_gids) = talloc(mem_ctx, sizeof(uint32) * (*num_groups));
376         for (i=0;i<(*num_groups);i++) {
377                 (*user_gids)[i] = user_groups[i].g_rid;
378         }
379         
380  done:
381         /* Clean up policy handles */
382         if (got_user_pol)
383                 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
384
385         if (got_dom_pol)
386                 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
387
388         return result;
389 }
390
391
392 /* Lookup group membership given a rid.   */
393 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
394                                 TALLOC_CTX *mem_ctx,
395                                 uint32 group_rid, uint32 *num_names, 
396                                 uint32 **rid_mem, char ***names, 
397                                 uint32 **name_types)
398 {
399         CLI_POLICY_HND *hnd;
400         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
401         uint32 i, total_names = 0;
402         POLICY_HND dom_pol, group_pol;
403         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
404         BOOL got_dom_pol = False, got_group_pol = False;
405
406         *num_names = 0;
407
408         /* Get sam handle */
409
410         if (!(hnd = cm_get_sam_handle(domain->name)))
411                 goto done;
412
413         /* Get domain handle */
414
415         result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
416                                       des_access, &domain->sid, &dom_pol);
417
418         if (!NT_STATUS_IS_OK(result))
419                 goto done;
420
421         got_dom_pol = True;
422
423         /* Get group handle */
424
425         result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol,
426                                      des_access, group_rid, &group_pol);
427
428         if (!NT_STATUS_IS_OK(result))
429                 goto done;
430
431         got_group_pol = True;
432
433         /* Step #1: Get a list of user rids that are the members of the
434            group. */
435
436         result = cli_samr_query_groupmem(hnd->cli, mem_ctx,
437                                          &group_pol, num_names, rid_mem,
438                                          name_types);
439
440         if (!NT_STATUS_IS_OK(result))
441                 goto done;
442
443         /* Step #2: Convert list of rids into list of usernames.  Do this
444            in bunches of ~1000 to avoid crashing NT4.  It looks like there
445            is a buffer overflow or something like that lurking around
446            somewhere. */
447
448 #define MAX_LOOKUP_RIDS 900
449
450         *names = talloc_zero(mem_ctx, *num_names * sizeof(char *));
451         *name_types = talloc_zero(mem_ctx, *num_names * sizeof(uint32));
452
453         for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
454                 int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
455                 uint32 tmp_num_names = 0;
456                 char **tmp_names = NULL;
457                 uint32 *tmp_types = NULL;
458
459                 /* Lookup a chunk of rids */
460
461                 result = cli_samr_lookup_rids(hnd->cli, mem_ctx,
462                                               &dom_pol, 1000, /* flags */
463                                               num_lookup_rids,
464                                               &(*rid_mem)[i],
465                                               &tmp_num_names,
466                                               &tmp_names, &tmp_types);
467
468                 if (!NT_STATUS_IS_OK(result))
469                         goto done;
470
471                 /* Copy result into array.  The talloc system will take
472                    care of freeing the temporary arrays later on. */
473
474                 memcpy(&(*names)[i], tmp_names, sizeof(char *) * 
475                        tmp_num_names);
476
477                 memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
478                        tmp_num_names);
479
480                 total_names += tmp_num_names;
481         }
482
483         *num_names = total_names;
484
485  done:
486         if (got_group_pol)
487                 cli_samr_close(hnd->cli, mem_ctx, &group_pol);
488
489         if (got_dom_pol)
490                 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
491
492         return result;
493 }
494
495 /* find the sequence number for a domain */
496 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
497 {
498         TALLOC_CTX *mem_ctx;
499         CLI_POLICY_HND *hnd;
500         SAM_UNK_CTR ctr;
501         uint16 switch_value = 2;
502         NTSTATUS result;
503         uint32 seqnum = DOM_SEQUENCE_NONE;
504         POLICY_HND dom_pol;
505         BOOL got_dom_pol = False;
506         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
507
508         *seq = DOM_SEQUENCE_NONE;
509
510         if (!(mem_ctx = talloc_init_named("sequence_number[rpc]")))
511                 return NT_STATUS_NO_MEMORY;
512
513         /* Get sam handle */
514
515         if (!(hnd = cm_get_sam_handle(domain->name)))
516                 goto done;
517
518         /* Get domain handle */
519
520         result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, 
521                                       des_access, &domain->sid, &dom_pol);
522
523         if (!NT_STATUS_IS_OK(result))
524                 goto done;
525
526         got_dom_pol = True;
527
528         /* Query domain info */
529
530         result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
531                                          switch_value, &ctr);
532
533         if (NT_STATUS_IS_OK(result)) {
534                 seqnum = ctr.info.inf2.seq_num;
535                 DEBUG(10,("domain_sequence_number: for domain %s is %u\n", domain->name, (unsigned)seqnum ));
536         } else {
537                 DEBUG(10,("domain_sequence_number: failed to get sequence number (%u) for domain %s\n",
538                         (unsigned)seqnum, domain->name ));
539         }
540
541   done:
542
543         if (got_dom_pol)
544                 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
545
546         talloc_destroy(mem_ctx);
547
548         *seq = seqnum;
549
550         return result;
551 }
552
553 /* get a list of trusted domains */
554 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
555                                 TALLOC_CTX *mem_ctx,
556                                 uint32 *num_domains,
557                                 char ***names,
558                                 DOM_SID **dom_sids)
559 {
560         CLI_POLICY_HND *hnd;
561         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
562         uint32 enum_ctx = 0;
563
564         *num_domains = 0;
565
566         if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
567                 goto done;
568
569         result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
570                                         &hnd->pol, &enum_ctx, num_domains, 
571                                         names, dom_sids);
572 done:
573         return result;
574 }
575
576 /* find the domain sid for a domain */
577 static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
578 {
579         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
580         TALLOC_CTX *mem_ctx;
581         CLI_POLICY_HND *hnd;
582         fstring level5_dom;
583
584         if (!(mem_ctx = talloc_init_named("domain_sid[rpc]")))
585                 return NT_STATUS_NO_MEMORY;
586
587         /* Get sam handle */
588         if (!(hnd = cm_get_lsa_handle(domain->name)))
589                 goto done;
590
591         status = cli_lsa_query_info_policy(hnd->cli, mem_ctx,
592                                            &hnd->pol, 0x05, level5_dom, sid);
593
594 done:
595         talloc_destroy(mem_ctx);
596         return status;
597 }
598
599 /* the rpc backend methods are exposed via this structure */
600 struct winbindd_methods msrpc_methods = {
601         False,
602         query_user_list,
603         enum_dom_groups,
604         name_to_sid,
605         sid_to_name,
606         query_user,
607         lookup_usergroups,
608         lookup_groupmem,
609         sequence_number,
610         trusted_domains,
611         domain_sid
612 };