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