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