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