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