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