source: branches/samba-3.0/source/nsswitch/winbindd_passdb.c

Last change on this file was 312, checked in by Herwig Bauernfeind, 16 years ago

Update 3.0 to final 3.0.36 (source)

File size: 17.9 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Winbind rpc backend functions
5
6 Copyright (C) Tim Potter 2000-2001,2003
7 Copyright (C) Simo Sorce 2003
8 Copyright (C) Volker Lendecke 2004
9 Copyright (C) Jeremy Allison 2008
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24*/
25
26#include "includes.h"
27#include "winbindd.h"
28
29#undef DBGC_CLASS
30#define DBGC_CLASS DBGC_WINBIND
31
32static NTSTATUS enum_groups_internal(struct winbindd_domain *domain,
33 TALLOC_CTX *mem_ctx,
34 uint32 *num_entries,
35 struct acct_info **info,
36 enum lsa_SidType sidtype)
37{
38 struct pdb_search *search;
39 struct samr_displayentry *entries;
40 int i;
41 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
42
43 if (sidtype == SID_NAME_ALIAS) {
44 search = pdb_search_aliases(&domain->sid);
45 } else {
46 search = pdb_search_groups();
47 }
48
49 if (search == NULL) goto done;
50
51 *num_entries = pdb_search_entries(search, 0, 0xffffffff, &entries);
52 if (*num_entries == 0) {
53 /* Zero entries isn't an error */
54 result = NT_STATUS_OK;
55 goto done;
56 }
57
58 *info = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
59 if (*info == NULL) {
60 result = NT_STATUS_NO_MEMORY;
61 goto done;
62 }
63
64 for (i=0; i<*num_entries; i++) {
65 fstrcpy((*info)[i].acct_name, entries[i].account_name);
66 fstrcpy((*info)[i].acct_desc, entries[i].description);
67 (*info)[i].rid = entries[i].rid;
68 }
69
70 result = NT_STATUS_OK;
71 done:
72 pdb_search_destroy(search);
73 return result;
74}
75
76/* List all local groups (aliases) */
77static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
78 TALLOC_CTX *mem_ctx,
79 uint32 *num_entries,
80 struct acct_info **info)
81{
82 return enum_groups_internal(domain,
83 mem_ctx,
84 num_entries,
85 info,
86 SID_NAME_ALIAS);
87}
88
89/* convert a single name to a sid in a domain */
90static NTSTATUS name_to_sid(struct winbindd_domain *domain,
91 TALLOC_CTX *mem_ctx,
92 const char *domain_name,
93 const char *name,
94 DOM_SID *sid,
95 enum lsa_SidType *type)
96{
97 DEBUG(10, ("Finding name %s\n", name));
98
99 if ( !lookup_name( mem_ctx, name, LOOKUP_NAME_ALL,
100 NULL, NULL, sid, type ) )
101 {
102 return NT_STATUS_NONE_MAPPED;
103 }
104
105 return NT_STATUS_OK;
106}
107
108/*
109 convert a domain SID to a user or group name
110*/
111static NTSTATUS sid_to_name(struct winbindd_domain *domain,
112 TALLOC_CTX *mem_ctx,
113 const DOM_SID *sid,
114 char **domain_name,
115 char **name,
116 enum lsa_SidType *type)
117{
118 const char *dom, *nam;
119
120 DEBUG(10, ("Converting SID %s\n", sid_string_static(sid)));
121
122 /* Paranoia check */
123 if (!sid_check_is_in_builtin(sid) &&
124 !sid_check_is_in_our_domain(sid)) {
125 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
126 "passdb backend\n", sid_string_static(sid)));
127 return NT_STATUS_NONE_MAPPED;
128 }
129
130 if (!lookup_sid(mem_ctx, sid, &dom, &nam, type)) {
131 return NT_STATUS_NONE_MAPPED;
132 }
133
134 *domain_name = talloc_strdup(mem_ctx, dom);
135 *name = talloc_strdup(mem_ctx, nam);
136
137 return NT_STATUS_OK;
138}
139
140static NTSTATUS rids_to_names(struct winbindd_domain *domain,
141 TALLOC_CTX *mem_ctx,
142 const DOM_SID *domain_sid,
143 uint32 *rids,
144 size_t num_rids,
145 char **domain_name,
146 char ***names,
147 enum lsa_SidType **types)
148{
149 size_t i;
150 bool have_mapped;
151 bool have_unmapped;
152
153 *domain_name = NULL;
154 *names = NULL;
155 *types = NULL;
156
157 if (!num_rids) {
158 return NT_STATUS_OK;
159 }
160
161 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
162 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
163
164 if ((*names == NULL) || (*types == NULL)) {
165 return NT_STATUS_NO_MEMORY;
166 }
167
168 have_mapped = have_unmapped = false;
169
170 for (i=0; i<num_rids; i++) {
171 DOM_SID sid;
172 const char *dom = NULL, *nam = NULL;
173 enum lsa_SidType type = SID_NAME_UNKNOWN;
174
175 if (!sid_compose(&sid, domain_sid, rids[i])) {
176 return NT_STATUS_INTERNAL_ERROR;
177 }
178
179 if (!lookup_sid(mem_ctx, &sid, &dom, &nam, &type)) {
180 have_unmapped = true;
181 (*types)[i] = SID_NAME_UNKNOWN;
182 (*names)[i] = talloc_strdup(mem_ctx, "");
183 } else {
184 have_mapped = true;
185 (*types)[i] = type;
186 (*names)[i] = CONST_DISCARD(char *, nam);
187 }
188
189 if (domain_name == NULL) {
190 *domain_name = CONST_DISCARD(char *, dom);
191 } else {
192 char *dname = CONST_DISCARD(char *, dom);
193 TALLOC_FREE(dname);
194 }
195 }
196
197 if (!have_mapped) {
198 return NT_STATUS_NONE_MAPPED;
199 }
200 if (!have_unmapped) {
201 return NT_STATUS_OK;
202 }
203 return STATUS_SOME_UNMAPPED;
204}
205
206/* Lookup groups a user is a member of. I wish Unix had a call like this! */
207static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
208 TALLOC_CTX *mem_ctx,
209 const DOM_SID *user_sid,
210 uint32 *num_groups, DOM_SID **user_gids)
211{
212 NTSTATUS result;
213 DOM_SID *groups = NULL;
214 gid_t *gids = NULL;
215 size_t ngroups = 0;
216 struct samu *user;
217
218 if ( (user = samu_new(mem_ctx)) == NULL ) {
219 return NT_STATUS_NO_MEMORY;
220 }
221
222 if (!pdb_getsampwsid(user, user_sid ) ) {
223 TALLOC_FREE( user );
224 return NT_STATUS_NO_SUCH_USER;
225 }
226
227 result = pdb_enum_group_memberships( mem_ctx, user, &groups, &gids, &ngroups );
228
229 TALLOC_FREE( user );
230
231 *num_groups = (uint32)ngroups;
232 *user_gids = groups;
233
234 return result;
235}
236
237static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
238 TALLOC_CTX *mem_ctx,
239 uint32 num_sids, const DOM_SID *sids,
240 uint32 *p_num_aliases, uint32 **rids)
241{
242 NTSTATUS result;
243 size_t num_aliases = 0;
244
245 result = pdb_enum_alias_memberships(mem_ctx, &domain->sid,
246 sids, num_sids, rids, &num_aliases);
247
248 *p_num_aliases = num_aliases;
249 return result;
250}
251
252/* find the sequence number for a domain */
253static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
254{
255 BOOL result;
256 time_t seq_num;
257
258 result = pdb_get_seq_num(&seq_num);
259 if (!result) {
260 *seq = 1;
261 }
262
263 *seq = (int) seq_num;
264 /* *seq = 1; */
265 return NT_STATUS_OK;
266}
267
268static NTSTATUS lockout_policy(struct winbindd_domain *domain,
269 TALLOC_CTX *mem_ctx,
270 SAM_UNK_INFO_12 *policy)
271{
272 /* actually we have that */
273 return NT_STATUS_NOT_IMPLEMENTED;
274}
275
276static NTSTATUS password_policy(struct winbindd_domain *domain,
277 TALLOC_CTX *mem_ctx,
278 SAM_UNK_INFO_1 *policy)
279{
280 uint32 min_pass_len,pass_hist,password_properties;
281 time_t u_expire, u_min_age;
282 NTTIME nt_expire, nt_min_age;
283 uint32 account_policy_temp;
284
285 if ((policy = TALLOC_ZERO_P(mem_ctx, SAM_UNK_INFO_1)) == NULL) {
286 return NT_STATUS_NO_MEMORY;
287 }
288
289 if (!pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &account_policy_temp)) {
290 return NT_STATUS_ACCESS_DENIED;
291 }
292 min_pass_len = account_policy_temp;
293
294 if (!pdb_get_account_policy(AP_PASSWORD_HISTORY, &account_policy_temp)) {
295 return NT_STATUS_ACCESS_DENIED;
296 }
297 pass_hist = account_policy_temp;
298
299 if (!pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp)) {
300 return NT_STATUS_ACCESS_DENIED;
301 }
302 password_properties = account_policy_temp;
303
304 if (!pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp)) {
305 return NT_STATUS_ACCESS_DENIED;
306 }
307 u_expire = account_policy_temp;
308
309 if (!pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &account_policy_temp)) {
310 return NT_STATUS_ACCESS_DENIED;
311 }
312 u_min_age = account_policy_temp;
313
314 unix_to_nt_time_abs(&nt_expire, u_expire);
315 unix_to_nt_time_abs(&nt_min_age, u_min_age);
316
317 init_unk_info1(policy, (uint16)min_pass_len, (uint16)pass_hist,
318 password_properties, nt_expire, nt_min_age);
319
320 return NT_STATUS_OK;
321}
322
323/*********************************************************************
324 BUILTIN specific functions.
325*********************************************************************/
326
327/* list all domain groups */
328static NTSTATUS builtin_enum_dom_groups(struct winbindd_domain *domain,
329 TALLOC_CTX *mem_ctx,
330 uint32 *num_entries,
331 struct acct_info **info)
332{
333 /* BUILTIN doesn't have domain groups */
334 *num_entries = 0;
335 *info = NULL;
336 return NT_STATUS_OK;
337}
338
339/* Query display info for a domain. This returns enough information plus a
340 bit extra to give an overview of domain users for the User Manager
341 application. */
342static NTSTATUS builtin_query_user_list(struct winbindd_domain *domain,
343 TALLOC_CTX *mem_ctx,
344 uint32 *num_entries,
345 WINBIND_USERINFO **info)
346{
347 /* We don't have users */
348 *num_entries = 0;
349 *info = NULL;
350 return NT_STATUS_OK;
351}
352
353/* Lookup user information from a rid or username. */
354static NTSTATUS builtin_query_user(struct winbindd_domain *domain,
355 TALLOC_CTX *mem_ctx,
356 const DOM_SID *user_sid,
357 WINBIND_USERINFO *user_info)
358{
359 return NT_STATUS_NO_SUCH_USER;
360}
361
362static NTSTATUS builtin_lookup_groupmem(struct winbindd_domain *domain,
363 TALLOC_CTX *mem_ctx,
364 const DOM_SID *group_sid, uint32 *num_names,
365 DOM_SID **sid_mem, char ***names,
366 uint32 **name_types)
367{
368 *num_names = 0;
369 *sid_mem = NULL;
370 *names = NULL;
371 *name_types = 0;
372 return NT_STATUS_NO_SUCH_GROUP;
373}
374
375/* get a list of trusted domains - builtin domain */
376static NTSTATUS builtin_trusted_domains(struct winbindd_domain *domain,
377 TALLOC_CTX *mem_ctx,
378 uint32 *num_domains,
379 char ***names,
380 char ***alt_names,
381 DOM_SID **dom_sids)
382{
383 *num_domains = 0;
384 *names = NULL;
385 *alt_names = NULL;
386 *dom_sids = NULL;
387 return NT_STATUS_OK;
388}
389
390/*********************************************************************
391 SAM specific functions.
392*********************************************************************/
393
394/* list all domain groups */
395static NTSTATUS sam_enum_dom_groups(struct winbindd_domain *domain,
396 TALLOC_CTX *mem_ctx,
397 uint32 *num_entries,
398 struct acct_info **info)
399{
400 return enum_groups_internal(domain,
401 mem_ctx,
402 num_entries,
403 info,
404 SID_NAME_DOM_GRP);
405}
406
407static NTSTATUS sam_query_user_list(struct winbindd_domain *domain,
408 TALLOC_CTX *mem_ctx,
409 uint32 *num_entries,
410 WINBIND_USERINFO **info)
411{
412 struct pdb_search *ps = pdb_search_users(ACB_NORMAL);
413 struct samr_displayentry *entries = NULL;
414 uint32 i;
415
416 *num_entries = 0;
417 *info = NULL;
418
419 if (!ps) {
420 return NT_STATUS_NO_MEMORY;
421 }
422
423 *num_entries = pdb_search_entries(ps,
424 1, 0xffffffff,
425 &entries);
426
427 *info = TALLOC_ZERO_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
428 if (!(*info)) {
429 pdb_search_destroy(ps);
430 return NT_STATUS_NO_MEMORY;
431 }
432
433 for (i = 0; i < *num_entries; i++) {
434 struct samr_displayentry *e = &entries[i];
435
436 (*info)[i].acct_name = talloc_strdup(mem_ctx, e->account_name );
437 (*info)[i].full_name = talloc_strdup(mem_ctx, e->fullname );
438 (*info)[i].homedir = NULL;
439 (*info)[i].shell = NULL;
440 sid_compose(&(*info)[i].user_sid, &domain->sid, e->rid);
441
442 /* For the moment we set the primary group for
443 every user to be the Domain Users group.
444 There are serious problems with determining
445 the actual primary group for large domains.
446 This should really be made into a 'winbind
447 force group' smb.conf parameter or
448 something like that. */
449
450 sid_compose(&(*info)[i].group_sid, &domain->sid,
451 DOMAIN_GROUP_RID_USERS);
452 }
453
454 pdb_search_destroy(ps);
455 return NT_STATUS_OK;
456}
457
458/* Lookup user information from a rid or username. */
459static NTSTATUS sam_query_user(struct winbindd_domain *domain,
460 TALLOC_CTX *mem_ctx,
461 const DOM_SID *user_sid,
462 WINBIND_USERINFO *user_info)
463{
464 struct samu *sampass = NULL;
465 fstring sidstr;
466
467 ZERO_STRUCTP(user_info);
468
469 if (!sid_check_is_in_our_domain(user_sid)) {
470 return NT_STATUS_NO_SUCH_USER;
471 }
472
473 sid_to_string(sidstr, user_sid);
474 DEBUG(10,("sam_query_user: getting samu info for sid %s\n",
475 sidstr ));
476
477 if (!(sampass = samu_new(mem_ctx))) {
478 return NT_STATUS_NO_MEMORY;
479 }
480
481 if (!pdb_getsampwsid(sampass, user_sid)) {
482 TALLOC_FREE(sampass);
483 return NT_STATUS_NO_SUCH_USER;
484 }
485
486 if (pdb_get_group_sid(sampass) == NULL) {
487 TALLOC_FREE(sampass);
488 return NT_STATUS_NO_SUCH_GROUP;
489 }
490
491 sid_to_string(sidstr, sampass->group_sid);
492 DEBUG(10,("sam_query_user: group sid %s\n", sidstr ));
493
494 sid_copy(&user_info->user_sid, user_sid);
495 sid_copy(&user_info->group_sid, sampass->group_sid);
496
497 user_info->acct_name = talloc_strdup(mem_ctx, sampass->username ?
498 sampass->username : "");
499 user_info->full_name = talloc_strdup(mem_ctx, sampass->full_name ?
500 sampass->full_name : "");
501 user_info->homedir = talloc_strdup(mem_ctx, sampass->home_dir ?
502 sampass->home_dir : "");
503 if (sampass->unix_pw && sampass->unix_pw->pw_shell) {
504 user_info->shell = talloc_strdup(mem_ctx, sampass->unix_pw->pw_shell);
505 } else {
506 user_info->shell = talloc_strdup(mem_ctx, "");
507 }
508 user_info->primary_gid = sampass->unix_pw ? sampass->unix_pw->pw_gid : (gid_t)-1;
509
510 TALLOC_FREE(sampass);
511 return NT_STATUS_OK;
512}
513
514/* Lookup group membership given a rid. */
515static NTSTATUS sam_lookup_groupmem(struct winbindd_domain *domain,
516 TALLOC_CTX *mem_ctx,
517 const DOM_SID *group_sid, uint32 *num_names,
518 DOM_SID **sid_mem, char ***names,
519 uint32 **name_types)
520{
521 size_t i, num_members, num_mapped;
522 uint32 *rids;
523 NTSTATUS result;
524 const DOM_SID **sids;
525 struct lsa_dom_info *lsa_domains;
526 struct lsa_name_info *lsa_names;
527 TALLOC_CTX *tmp_ctx;
528
529 if (!sid_check_is_in_our_domain(group_sid)) {
530 /* There's no groups, only aliases in BUILTIN */
531 return NT_STATUS_NO_SUCH_GROUP;
532 }
533
534 if (!(tmp_ctx = talloc_init("lookup_groupmem"))) {
535 return NT_STATUS_NO_MEMORY;
536 }
537
538 result = pdb_enum_group_members(tmp_ctx, group_sid, &rids,
539 &num_members);
540 if (!NT_STATUS_IS_OK(result)) {
541 TALLOC_FREE(tmp_ctx);
542 return result;
543 }
544
545 if (num_members == 0) {
546 *num_names = 0;
547 *sid_mem = NULL;
548 *names = NULL;
549 *name_types = NULL;
550 TALLOC_FREE(tmp_ctx);
551 return NT_STATUS_OK;
552 }
553
554 *sid_mem = TALLOC_ARRAY(mem_ctx, DOM_SID, num_members);
555 *names = TALLOC_ARRAY(mem_ctx, char *, num_members);
556 *name_types = TALLOC_ARRAY(mem_ctx, uint32, num_members);
557 sids = TALLOC_ARRAY(tmp_ctx, const DOM_SID *, num_members);
558
559 if (((*sid_mem) == NULL) || ((*names) == NULL) ||
560 ((*name_types) == NULL) || (sids == NULL)) {
561 TALLOC_FREE(tmp_ctx);
562 return NT_STATUS_NO_MEMORY;
563 }
564
565 /*
566 * Prepare an array of sid pointers for the lookup_sids calling
567 * convention.
568 */
569
570 for (i=0; i<num_members; i++) {
571 DOM_SID *sid = &((*sid_mem)[i]);
572 if (!sid_compose(sid, &domain->sid, rids[i])) {
573 TALLOC_FREE(tmp_ctx);
574 return NT_STATUS_INTERNAL_ERROR;
575 }
576 sids[i] = sid;
577 }
578
579 result = lookup_sids(tmp_ctx, num_members, sids, 1,
580 &lsa_domains, &lsa_names);
581 if (!NT_STATUS_IS_OK(result)) {
582 TALLOC_FREE(tmp_ctx);
583 return result;
584 }
585
586 num_mapped = 0;
587 for (i=0; i<num_members; i++) {
588 if (lsa_names[i].type != SID_NAME_USER) {
589 DEBUG(2, ("Got %s as group member -- ignoring\n",
590 sid_type_lookup(lsa_names[i].type)));
591 continue;
592 }
593 if (!((*names)[num_mapped] = talloc_strdup((*names),
594 lsa_names[i].name))) {
595 TALLOC_FREE(tmp_ctx);
596 return NT_STATUS_NO_MEMORY;
597 }
598
599 (*name_types)[num_mapped] = lsa_names[i].type;
600
601 num_mapped += 1;
602 }
603
604 *num_names = num_mapped;
605
606 TALLOC_FREE(tmp_ctx);
607 return NT_STATUS_OK;
608}
609
610/* get a list of trusted domains - sam */
611static NTSTATUS sam_trusted_domains(struct winbindd_domain *domain,
612 TALLOC_CTX *mem_ctx,
613 uint32 *num_domains,
614 char ***names,
615 char ***alt_names,
616 DOM_SID **dom_sids)
617{
618 NTSTATUS nt_status;
619 struct trustdom_info **domains;
620 int i;
621 TALLOC_CTX *tmp_ctx;
622
623 *num_domains = 0;
624 *names = NULL;
625 *alt_names = NULL;
626 *dom_sids = NULL;
627
628 if (!(tmp_ctx = talloc_init("trusted_domains"))) {
629 return NT_STATUS_NO_MEMORY;
630 }
631
632 nt_status = secrets_trusted_domains(tmp_ctx, num_domains,
633 &domains);
634 if (!NT_STATUS_IS_OK(nt_status)) {
635 TALLOC_FREE(tmp_ctx);
636 return nt_status;
637 }
638
639 if (*num_domains) {
640 *names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
641 *alt_names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
642 *dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
643
644 if ((*alt_names == NULL) || (*names == NULL) || (*dom_sids == NULL)) {
645 TALLOC_FREE(tmp_ctx);
646 return NT_STATUS_NO_MEMORY;
647 }
648 } else {
649 *names = NULL;
650 *alt_names = NULL;
651 *dom_sids = NULL;
652 }
653
654 for (i=0; i<*num_domains; i++) {
655 (*alt_names)[i] = NULL;
656 if (!((*names)[i] = talloc_strdup((*names),
657 domains[i]->name))) {
658 TALLOC_FREE(tmp_ctx);
659 return NT_STATUS_NO_MEMORY;
660 }
661 sid_copy(&(*dom_sids)[i], &domains[i]->sid);
662 }
663
664 TALLOC_FREE(tmp_ctx);
665 return NT_STATUS_OK;
666}
667
668/* the rpc backend methods are exposed via this structure */
669struct winbindd_methods builtin_passdb_methods = {
670 false,
671 builtin_query_user_list,
672 builtin_enum_dom_groups,
673 enum_local_groups,
674 name_to_sid,
675 sid_to_name,
676 rids_to_names,
677 builtin_query_user,
678 lookup_usergroups,
679 lookup_useraliases,
680 builtin_lookup_groupmem,
681 sequence_number,
682 lockout_policy,
683 password_policy,
684 builtin_trusted_domains,
685};
686
687/* the rpc backend methods are exposed via this structure */
688struct winbindd_methods sam_passdb_methods = {
689 false,
690 sam_query_user_list,
691 sam_enum_dom_groups,
692 enum_local_groups,
693 name_to_sid,
694 sid_to_name,
695 rids_to_names,
696 sam_query_user,
697 lookup_usergroups,
698 lookup_useraliases,
699 sam_lookup_groupmem,
700 sequence_number,
701 lockout_policy,
702 password_policy,
703 sam_trusted_domains,
704};
Note: See TracBrowser for help on using the repository browser.