A few more trusted domains updates from mimir.
[samba.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         const char *full_name;
191
192         if (!(mem_ctx = talloc_init_named("name_to_sid[rpc] for [%s]\\[%s]", domain->name, name))) {
193                 DEBUG(0, ("talloc_init failed!\n"));
194                 return NT_STATUS_NO_MEMORY;
195         }
196         
197         if (!(hnd = cm_get_lsa_handle(domain->name))) {
198                 talloc_destroy(mem_ctx);
199                 return NT_STATUS_UNSUCCESSFUL;
200         }
201         
202         full_name = talloc_asprintf(mem_ctx, "%s\\%s", domain->name, name);
203         
204         if (!full_name) {
205                 DEBUG(0, ("talloc_asprintf failed!\n"));
206                 talloc_destroy(mem_ctx);
207                 return NT_STATUS_NO_MEMORY;
208         }
209
210         status = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, 1, 
211                                       &full_name, &sids, &types);
212         
213         /* Return rid and type if lookup successful */
214
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         NTSTATUS status;
238
239         if (!(hnd = cm_get_lsa_handle(domain->name)))
240                 return NT_STATUS_UNSUCCESSFUL;
241         
242         status = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol,
243                                      1, sid, &domains, &names, &types);
244
245         if (NT_STATUS_IS_OK(status)) {
246                 *type = types[0];
247                 *name = names[0];
248                 DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name));
249
250                 /* Paranoia */
251                 if (strcasecmp(domain->name, domains[0]) != 0) {
252                         DEBUG(1, ("domain name from domain param and PDC lookup return differ! (%s vs %s)\n", domain->name, domains[0]));
253                         return NT_STATUS_UNSUCCESSFUL;
254                 }
255         }
256         return status;
257 }
258
259 /* Lookup user information from a rid or username. */
260 static NTSTATUS query_user(struct winbindd_domain *domain, 
261                            TALLOC_CTX *mem_ctx, 
262                            uint32 user_rid, 
263                            WINBIND_USERINFO *user_info)
264 {
265         CLI_POLICY_HND *hnd;
266         NTSTATUS result;
267         POLICY_HND dom_pol, user_pol;
268         BOOL got_dom_pol = False, got_user_pol = False;
269         SAM_USERINFO_CTR *ctr;
270
271         /* Get sam handle */
272         if (!(hnd = cm_get_sam_handle(domain->name)))
273                 goto done;
274
275         /* Get domain handle */
276
277         result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
278                                       SEC_RIGHTS_MAXIMUM_ALLOWED, 
279                                       &domain->sid, &dom_pol);
280
281         if (!NT_STATUS_IS_OK(result))
282                 goto done;
283
284         got_dom_pol = True;
285
286         /* Get user handle */
287         result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
288                                     SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
289
290         if (!NT_STATUS_IS_OK(result))
291                 goto done;
292
293         got_user_pol = True;
294
295         /* Get user info */
296         result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol, 
297                                          0x15, &ctr);
298
299         cli_samr_close(hnd->cli, mem_ctx, &user_pol);
300         got_user_pol = False;
301
302         user_info->group_rid = ctr->info.id21->group_rid;
303         user_info->acct_name = unistr2_tdup(mem_ctx, 
304                                             &ctr->info.id21->uni_user_name);
305         user_info->full_name = unistr2_tdup(mem_ctx, 
306                                             &ctr->info.id21->uni_full_name);
307
308  done:
309         /* Clean up policy handles */
310         if (got_user_pol)
311                 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
312
313         if (got_dom_pol)
314                 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
315
316         return result;
317 }                                   
318
319 /* Lookup groups a user is a member of.  I wish Unix had a call like this! */
320 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
321                                   TALLOC_CTX *mem_ctx,
322                                   uint32 user_rid, 
323                                   uint32 *num_groups, uint32 **user_gids)
324 {
325         CLI_POLICY_HND *hnd;
326         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
327         POLICY_HND dom_pol, user_pol;
328         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
329         BOOL got_dom_pol = False, got_user_pol = False;
330         DOM_GID *user_groups;
331         int i;
332
333         *num_groups = 0;
334
335         /* First try cached universal groups from logon */
336         *user_gids = uni_group_cache_fetch(&domain->sid, user_rid, mem_ctx, num_groups);
337         if((*num_groups > 0) && *user_gids) {
338                 return NT_STATUS_OK;
339         } else {
340             *user_gids = NULL;
341             *num_groups = 0;
342         }
343
344         /* Get sam handle */
345         if (!(hnd = cm_get_sam_handle(domain->name)))
346                 goto done;
347
348         /* Get domain handle */
349         result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
350                                         des_access, &domain->sid, &dom_pol);
351
352         if (!NT_STATUS_IS_OK(result))
353                 goto done;
354
355         got_dom_pol = True;
356
357         /* Get user handle */
358         result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
359                                         des_access, user_rid, &user_pol);
360
361         if (!NT_STATUS_IS_OK(result))
362                 goto done;
363
364         got_user_pol = True;
365
366         /* Query user rids */
367         result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol, 
368                                            num_groups, &user_groups);
369
370         if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
371                 goto done;
372
373         (*user_gids) = talloc(mem_ctx, sizeof(uint32) * (*num_groups));
374         for (i=0;i<(*num_groups);i++) {
375                 (*user_gids)[i] = user_groups[i].g_rid;
376         }
377         
378  done:
379         /* Clean up policy handles */
380         if (got_user_pol)
381                 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
382
383         if (got_dom_pol)
384                 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
385
386         return result;
387 }
388
389
390 /* Lookup group membership given a rid.   */
391 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
392                                 TALLOC_CTX *mem_ctx,
393                                 uint32 group_rid, uint32 *num_names, 
394                                 uint32 **rid_mem, char ***names, 
395                                 uint32 **name_types)
396 {
397         CLI_POLICY_HND *hnd;
398         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
399         uint32 i, total_names = 0;
400         POLICY_HND dom_pol, group_pol;
401         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
402         BOOL got_dom_pol = False, got_group_pol = False;
403
404         *num_names = 0;
405
406         /* Get sam handle */
407
408         if (!(hnd = cm_get_sam_handle(domain->name)))
409                 goto done;
410
411         /* Get domain handle */
412
413         result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
414                                       des_access, &domain->sid, &dom_pol);
415
416         if (!NT_STATUS_IS_OK(result))
417                 goto done;
418
419         got_dom_pol = True;
420
421         /* Get group handle */
422
423         result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol,
424                                      des_access, group_rid, &group_pol);
425
426         if (!NT_STATUS_IS_OK(result))
427                 goto done;
428
429         got_group_pol = True;
430
431         /* Step #1: Get a list of user rids that are the members of the
432            group. */
433
434         result = cli_samr_query_groupmem(hnd->cli, mem_ctx,
435                                          &group_pol, num_names, rid_mem,
436                                          name_types);
437
438         if (!NT_STATUS_IS_OK(result))
439                 goto done;
440
441         /* Step #2: Convert list of rids into list of usernames.  Do this
442            in bunches of ~1000 to avoid crashing NT4.  It looks like there
443            is a buffer overflow or something like that lurking around
444            somewhere. */
445
446 #define MAX_LOOKUP_RIDS 900
447
448         *names = talloc_zero(mem_ctx, *num_names * sizeof(char *));
449         *name_types = talloc_zero(mem_ctx, *num_names * sizeof(uint32));
450
451         for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
452                 int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
453                 uint32 tmp_num_names = 0;
454                 char **tmp_names = NULL;
455                 uint32 *tmp_types = NULL;
456
457                 /* Lookup a chunk of rids */
458
459                 result = cli_samr_lookup_rids(hnd->cli, mem_ctx,
460                                               &dom_pol, 1000, /* flags */
461                                               num_lookup_rids,
462                                               &(*rid_mem)[i],
463                                               &tmp_num_names,
464                                               &tmp_names, &tmp_types);
465
466                 if (!NT_STATUS_IS_OK(result))
467                         goto done;
468
469                 /* Copy result into array.  The talloc system will take
470                    care of freeing the temporary arrays later on. */
471
472                 memcpy(&(*names)[i], tmp_names, sizeof(char *) * 
473                        tmp_num_names);
474
475                 memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
476                        tmp_num_names);
477
478                 total_names += tmp_num_names;
479         }
480
481         *num_names = total_names;
482
483  done:
484         if (got_group_pol)
485                 cli_samr_close(hnd->cli, mem_ctx, &group_pol);
486
487         if (got_dom_pol)
488                 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
489
490         return result;
491 }
492
493 /* find the sequence number for a domain */
494 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
495 {
496         TALLOC_CTX *mem_ctx;
497         CLI_POLICY_HND *hnd;
498         SAM_UNK_CTR ctr;
499         uint16 switch_value = 2;
500         NTSTATUS result;
501         uint32 seqnum = DOM_SEQUENCE_NONE;
502         POLICY_HND dom_pol;
503         BOOL got_dom_pol = False;
504         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
505
506         *seq = DOM_SEQUENCE_NONE;
507
508         if (!(mem_ctx = talloc_init_named("sequence_number[rpc]")))
509                 return NT_STATUS_NO_MEMORY;
510
511         /* Get sam handle */
512
513         if (!(hnd = cm_get_sam_handle(domain->name)))
514                 goto done;
515
516         /* Get domain handle */
517
518         result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, 
519                                       des_access, &domain->sid, &dom_pol);
520
521         if (!NT_STATUS_IS_OK(result))
522                 goto done;
523
524         got_dom_pol = True;
525
526         /* Query domain info */
527
528         result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
529                                          switch_value, &ctr);
530
531         if (NT_STATUS_IS_OK(result)) {
532                 seqnum = ctr.info.inf2.seq_num;
533                 DEBUG(10,("domain_sequence_number: for domain %s is %u\n", domain->name, (unsigned)seqnum ));
534         } else {
535                 DEBUG(10,("domain_sequence_number: failed to get sequence number (%u) for domain %s\n",
536                         (unsigned)seqnum, domain->name ));
537         }
538
539   done:
540
541         if (got_dom_pol)
542                 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
543
544         talloc_destroy(mem_ctx);
545
546         *seq = seqnum;
547
548         return result;
549 }
550
551 /* get a list of trusted domains */
552 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
553                                 TALLOC_CTX *mem_ctx,
554                                 uint32 *num_domains,
555                                 char ***names,
556                                 DOM_SID **dom_sids)
557 {
558         CLI_POLICY_HND *hnd;
559         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
560         uint32 enum_ctx = 0;
561         uint32 pref_num_domains = 5;
562
563         *num_domains = 0;
564
565         if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
566                 goto done;
567
568         result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
569                                         &hnd->pol, &enum_ctx, &pref_num_domains,
570                                         num_domains, names, dom_sids);
571 done:
572         return result;
573 }
574
575 /* find the domain sid for a domain */
576 static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
577 {
578         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
579         TALLOC_CTX *mem_ctx;
580         CLI_POLICY_HND *hnd;
581         fstring level5_dom;
582
583         if (!(mem_ctx = talloc_init_named("domain_sid[rpc]")))
584                 return NT_STATUS_NO_MEMORY;
585
586         /* Get sam handle */
587         if (!(hnd = cm_get_lsa_handle(domain->name)))
588                 goto done;
589
590         status = cli_lsa_query_info_policy(hnd->cli, mem_ctx,
591                                            &hnd->pol, 0x05, level5_dom, sid);
592
593 done:
594         talloc_destroy(mem_ctx);
595         return status;
596 }
597
598 /* the rpc backend methods are exposed via this structure */
599 struct winbindd_methods msrpc_methods = {
600         False,
601         query_user_list,
602         enum_dom_groups,
603         name_to_sid,
604         sid_to_name,
605         query_user,
606         lookup_usergroups,
607         lookup_groupmem,
608         sequence_number,
609         trusted_domains,
610         domain_sid
611 };