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