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