Final (hopefully :-) part of fix for bug #5551. Allow passdb backend to enumerate...
[Samba.git] / source / winbindd / winbindd_passdb.c
blobffcf0719be76b1582a1980573ab500d4a86e12ac
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind rpc backend functions
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
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 3 of the License, or
14 (at your option) any later version.
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.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "winbindd.h"
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_WINBIND
31 static NTSTATUS enum_groups_internal(struct winbindd_domain *domain,
32 TALLOC_CTX *mem_ctx,
33 uint32 *num_entries,
34 struct acct_info **info,
35 enum lsa_SidType sidtype)
37 struct pdb_search *search;
38 struct samr_displayentry *entries;
39 int i;
40 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
42 if (sidtype == SID_NAME_ALIAS) {
43 search = pdb_search_aliases(&domain->sid);
44 } else {
45 search = pdb_search_groups();
48 if (search == NULL) goto done;
50 *num_entries = pdb_search_entries(search, 0, 0xffffffff, &entries);
51 if (*num_entries == 0) {
52 /* Zero entries isn't an error */
53 result = NT_STATUS_OK;
54 goto done;
57 *info = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
58 if (*info == NULL) {
59 result = NT_STATUS_NO_MEMORY;
60 goto done;
63 for (i=0; i<*num_entries; i++) {
64 fstrcpy((*info)[i].acct_name, entries[i].account_name);
65 fstrcpy((*info)[i].acct_desc, entries[i].description);
66 (*info)[i].rid = entries[i].rid;
69 result = NT_STATUS_OK;
70 done:
71 pdb_search_destroy(search);
72 return result;
75 /* list all domain groups */
76 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
77 TALLOC_CTX *mem_ctx,
78 uint32 *num_entries,
79 struct acct_info **info)
81 return enum_groups_internal(domain,
82 mem_ctx,
83 num_entries,
84 info,
85 SID_NAME_DOM_GRP);
88 /* List all local groups (aliases) */
89 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
90 TALLOC_CTX *mem_ctx,
91 uint32 *num_entries,
92 struct acct_info **info)
94 return enum_groups_internal(domain,
95 mem_ctx,
96 num_entries,
97 info,
98 SID_NAME_ALIAS);
101 /* convert a single name to a sid in a domain */
102 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
103 TALLOC_CTX *mem_ctx,
104 enum winbindd_cmd original_cmd,
105 const char *domain_name,
106 const char *name,
107 DOM_SID *sid,
108 enum lsa_SidType *type)
110 uint32 flags = LOOKUP_NAME_ALL;
112 switch ( original_cmd ) {
113 case WINBINDD_LOOKUPNAME:
114 /* This call is ok */
115 break;
116 default:
117 /* Avoid any NSS calls in the lookup_name by default */
118 flags |= LOOKUP_NAME_EXPLICIT;
119 DEBUG(10,("winbindd_passdb: limiting name_to_sid() to explicit mappings\n"));
120 break;
123 DEBUG(10, ("Finding name %s\n", name));
125 if ( !lookup_name( mem_ctx, name, flags, NULL, NULL, sid, type ) ) {
126 return NT_STATUS_NONE_MAPPED;
129 return NT_STATUS_OK;
133 convert a domain SID to a user or group name
135 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
136 TALLOC_CTX *mem_ctx,
137 const DOM_SID *sid,
138 char **domain_name,
139 char **name,
140 enum lsa_SidType *type)
142 const char *dom, *nam;
144 DEBUG(10, ("Converting SID %s\n", sid_string_dbg(sid)));
146 /* Paranoia check */
147 if (!sid_check_is_in_builtin(sid) &&
148 !sid_check_is_in_our_domain(sid) &&
149 !sid_check_is_in_unix_users(sid) &&
150 !sid_check_is_unix_users(sid) &&
151 !sid_check_is_in_unix_groups(sid) &&
152 !sid_check_is_unix_groups(sid) &&
153 !sid_check_is_in_wellknown_domain(sid))
155 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
156 "passdb backend\n", sid_string_dbg(sid)));
157 return NT_STATUS_NONE_MAPPED;
160 if (!lookup_sid(mem_ctx, sid, &dom, &nam, type)) {
161 return NT_STATUS_NONE_MAPPED;
164 *domain_name = talloc_strdup(mem_ctx, dom);
165 *name = talloc_strdup(mem_ctx, nam);
167 return NT_STATUS_OK;
170 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
171 TALLOC_CTX *mem_ctx,
172 const DOM_SID *sid,
173 uint32 *rids,
174 size_t num_rids,
175 char **domain_name,
176 char ***names,
177 enum lsa_SidType **types)
179 size_t i;
180 bool have_mapped;
181 bool have_unmapped;
183 *domain_name = NULL;
184 *names = NULL;
185 *types = NULL;
187 if (!num_rids) {
188 return NT_STATUS_OK;
191 /* Paranoia check */
192 if (!sid_check_is_in_builtin(sid) &&
193 !sid_check_is_in_our_domain(sid) &&
194 !sid_check_is_in_unix_users(sid) &&
195 !sid_check_is_unix_users(sid) &&
196 !sid_check_is_in_unix_groups(sid) &&
197 !sid_check_is_unix_groups(sid) &&
198 !sid_check_is_in_wellknown_domain(sid))
200 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
201 "passdb backend\n", sid_string_dbg(sid)));
202 return NT_STATUS_NONE_MAPPED;
205 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
206 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
208 if ((*names == NULL) || (*types == NULL)) {
209 return NT_STATUS_NO_MEMORY;
212 have_mapped = have_unmapped = false;
214 for (i=0; i<num_rids; i++) {
215 DOM_SID lsid;
216 const char *dom = NULL, *nam = NULL;
217 enum lsa_SidType type = SID_NAME_UNKNOWN;
219 if (!sid_compose(&lsid, sid, rids[i])) {
220 return NT_STATUS_INTERNAL_ERROR;
223 if (!lookup_sid(mem_ctx, &lsid, &dom, &nam, &type)) {
224 have_unmapped = true;
225 (*types)[i] = SID_NAME_UNKNOWN;
226 (*names)[i] = talloc_strdup(mem_ctx, "");
227 } else {
228 have_mapped = true;
229 (*types)[i] = type;
230 (*names)[i] = CONST_DISCARD(char *, nam);
233 if (domain_name == NULL) {
234 *domain_name = CONST_DISCARD(char *, dom);
235 } else {
236 char *dname = CONST_DISCARD(char *, dom);
237 TALLOC_FREE(dname);
241 if (!have_mapped) {
242 return NT_STATUS_NONE_MAPPED;
244 if (!have_unmapped) {
245 return NT_STATUS_OK;
247 return STATUS_SOME_UNMAPPED;
250 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
251 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
252 TALLOC_CTX *mem_ctx,
253 const DOM_SID *user_sid,
254 uint32 *num_groups, DOM_SID **user_gids)
256 NTSTATUS result;
257 DOM_SID *groups = NULL;
258 gid_t *gids = NULL;
259 size_t ngroups = 0;
260 struct samu *user;
262 if ( (user = samu_new(mem_ctx)) == NULL ) {
263 return NT_STATUS_NO_MEMORY;
266 if ( !pdb_getsampwsid( user, user_sid ) ) {
267 return NT_STATUS_NO_SUCH_USER;
270 result = pdb_enum_group_memberships( mem_ctx, user, &groups, &gids, &ngroups );
272 TALLOC_FREE( user );
274 *num_groups = (uint32)ngroups;
275 *user_gids = groups;
277 return result;
280 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
281 TALLOC_CTX *mem_ctx,
282 uint32 num_sids, const DOM_SID *sids,
283 uint32 *p_num_aliases, uint32 **rids)
285 NTSTATUS result;
286 size_t num_aliases = 0;
288 result = pdb_enum_alias_memberships(mem_ctx, &domain->sid,
289 sids, num_sids, rids, &num_aliases);
291 *p_num_aliases = num_aliases;
292 return result;
295 /* find the sequence number for a domain */
296 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
298 bool result;
299 time_t seq_num;
301 result = pdb_get_seq_num(&seq_num);
302 if (!result) {
303 *seq = 1;
306 *seq = (int) seq_num;
307 /* *seq = 1; */
308 return NT_STATUS_OK;
311 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
312 TALLOC_CTX *mem_ctx,
313 struct samr_DomInfo12 *policy)
315 /* actually we have that */
316 return NT_STATUS_NOT_IMPLEMENTED;
319 static NTSTATUS password_policy(struct winbindd_domain *domain,
320 TALLOC_CTX *mem_ctx,
321 struct samr_DomInfo1 *policy)
323 uint32 min_pass_len,pass_hist,password_properties;
324 time_t u_expire, u_min_age;
325 NTTIME nt_expire, nt_min_age;
326 uint32 account_policy_temp;
328 if ((policy = TALLOC_ZERO_P(mem_ctx, struct samr_DomInfo1)) == NULL) {
329 return NT_STATUS_NO_MEMORY;
332 if (!pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &account_policy_temp)) {
333 return NT_STATUS_ACCESS_DENIED;
335 min_pass_len = account_policy_temp;
337 if (!pdb_get_account_policy(AP_PASSWORD_HISTORY, &account_policy_temp)) {
338 return NT_STATUS_ACCESS_DENIED;
340 pass_hist = account_policy_temp;
342 if (!pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp)) {
343 return NT_STATUS_ACCESS_DENIED;
345 password_properties = account_policy_temp;
347 if (!pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp)) {
348 return NT_STATUS_ACCESS_DENIED;
350 u_expire = account_policy_temp;
352 if (!pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &account_policy_temp)) {
353 return NT_STATUS_ACCESS_DENIED;
355 u_min_age = account_policy_temp;
357 unix_to_nt_time_abs(&nt_expire, u_expire);
358 unix_to_nt_time_abs(&nt_min_age, u_min_age);
360 init_samr_DomInfo1(policy,
361 (uint16)min_pass_len,
362 (uint16)pass_hist,
363 password_properties,
364 nt_expire,
365 nt_min_age);
367 return NT_STATUS_OK;
370 /*********************************************************************
371 BUILTIN specific functions.
372 *********************************************************************/
374 /* Query display info for a domain. This returns enough information plus a
375 bit extra to give an overview of domain users for the User Manager
376 application. */
377 static NTSTATUS builtin_query_user_list(struct winbindd_domain *domain,
378 TALLOC_CTX *mem_ctx,
379 uint32 *num_entries,
380 WINBIND_USERINFO **info)
382 /* We don't have users */
383 *num_entries = 0;
384 *info = NULL;
385 return NT_STATUS_OK;
388 /* Lookup user information from a rid or username. */
389 static NTSTATUS builtin_query_user(struct winbindd_domain *domain,
390 TALLOC_CTX *mem_ctx,
391 const DOM_SID *user_sid,
392 WINBIND_USERINFO *user_info)
394 return NT_STATUS_NO_SUCH_USER;
397 static NTSTATUS builtin_lookup_groupmem(struct winbindd_domain *domain,
398 TALLOC_CTX *mem_ctx,
399 const DOM_SID *group_sid, uint32 *num_names,
400 DOM_SID **sid_mem, char ***names,
401 uint32 **name_types)
403 *num_names = 0;
404 *sid_mem = NULL;
405 *names = NULL;
406 *name_types = 0;
407 return NT_STATUS_NO_SUCH_GROUP;
410 /* get a list of trusted domains - builtin domain */
411 static NTSTATUS builtin_trusted_domains(struct winbindd_domain *domain,
412 TALLOC_CTX *mem_ctx,
413 uint32 *num_domains,
414 char ***names,
415 char ***alt_names,
416 DOM_SID **dom_sids)
418 *num_domains = 0;
419 *names = NULL;
420 *alt_names = NULL;
421 *dom_sids = NULL;
422 return NT_STATUS_OK;
425 /*********************************************************************
426 SAM specific functions.
427 *********************************************************************/
429 static NTSTATUS sam_query_user_list(struct winbindd_domain *domain,
430 TALLOC_CTX *mem_ctx,
431 uint32 *num_entries,
432 WINBIND_USERINFO **info)
434 struct pdb_search *ps = pdb_search_users(ACB_NORMAL);
435 struct samr_displayentry *entries = NULL;
436 uint32 i;
438 *num_entries = 0;
439 *info = NULL;
441 if (!ps) {
442 return NT_STATUS_NO_MEMORY;
445 *num_entries = pdb_search_entries(ps,
446 1, 0xffffffff,
447 &entries);
449 *info = TALLOC_ZERO_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
450 if (!(*info)) {
451 pdb_search_destroy(ps);
452 return NT_STATUS_NO_MEMORY;
455 for (i = 0; i < *num_entries; i++) {
456 struct samr_displayentry *e = &entries[i];
458 (*info)[i].acct_name = talloc_strdup(mem_ctx, e->account_name );
459 (*info)[i].full_name = talloc_strdup(mem_ctx, e->fullname );
460 (*info)[i].homedir = NULL;
461 (*info)[i].shell = NULL;
462 sid_compose(&(*info)[i].user_sid, &domain->sid, e->rid);
464 /* For the moment we set the primary group for
465 every user to be the Domain Users group.
466 There are serious problems with determining
467 the actual primary group for large domains.
468 This should really be made into a 'winbind
469 force group' smb.conf parameter or
470 something like that. */
472 sid_compose(&(*info)[i].group_sid, &domain->sid,
473 DOMAIN_GROUP_RID_USERS);
476 pdb_search_destroy(ps);
477 return NT_STATUS_OK;
480 /* Lookup user information from a rid or username. */
481 static NTSTATUS sam_query_user(struct winbindd_domain *domain,
482 TALLOC_CTX *mem_ctx,
483 const DOM_SID *user_sid,
484 WINBIND_USERINFO *user_info)
486 struct samu *sampass = NULL;
488 ZERO_STRUCTP(user_info);
490 if (!sid_check_is_in_our_domain(user_sid)) {
491 return NT_STATUS_NO_SUCH_USER;
494 DEBUG(10,("sam_query_user: getting samu info for sid %s\n",
495 sid_string_dbg(user_sid) ));
497 if (!(sampass = samu_new(mem_ctx))) {
498 return NT_STATUS_NO_MEMORY;
501 if (!pdb_getsampwsid(sampass, user_sid)) {
502 TALLOC_FREE(sampass);
503 return NT_STATUS_NO_SUCH_USER;
506 if (pdb_get_group_sid(sampass) == NULL) {
507 TALLOC_FREE(sampass);
508 return NT_STATUS_NO_SUCH_GROUP;
511 DEBUG(10,("sam_query_user: group sid %s\n",
512 sid_string_dbg(sampass->group_sid) ));
514 sid_copy(&user_info->user_sid, user_sid);
515 sid_copy(&user_info->group_sid, sampass->group_sid);
517 user_info->acct_name = talloc_strdup(mem_ctx, sampass->username ?
518 sampass->username : "");
519 user_info->full_name = talloc_strdup(mem_ctx, sampass->full_name ?
520 sampass->full_name : "");
521 user_info->homedir = talloc_strdup(mem_ctx, sampass->home_dir ?
522 sampass->home_dir : "");
523 if (sampass->unix_pw && sampass->unix_pw->pw_shell) {
524 user_info->shell = talloc_strdup(mem_ctx, sampass->unix_pw->pw_shell);
525 } else {
526 user_info->shell = talloc_strdup(mem_ctx, "");
528 user_info->primary_gid = sampass->unix_pw ? sampass->unix_pw->pw_gid : (gid_t)-1;
530 TALLOC_FREE(sampass);
531 return NT_STATUS_OK;
534 /* Lookup group membership given a rid. */
535 static NTSTATUS sam_lookup_groupmem(struct winbindd_domain *domain,
536 TALLOC_CTX *mem_ctx,
537 const DOM_SID *group_sid, uint32 *num_names,
538 DOM_SID **sid_mem, char ***names,
539 uint32 **name_types)
541 size_t i, num_members, num_mapped;
542 uint32 *rids;
543 NTSTATUS result;
544 const DOM_SID **sids;
545 struct lsa_dom_info *lsa_domains;
546 struct lsa_name_info *lsa_names;
547 TALLOC_CTX *tmp_ctx;
549 if (!sid_check_is_in_our_domain(group_sid)) {
550 /* There's no groups, only aliases in BUILTIN */
551 return NT_STATUS_NO_SUCH_GROUP;
554 if (!(tmp_ctx = talloc_init("lookup_groupmem"))) {
555 return NT_STATUS_NO_MEMORY;
558 result = pdb_enum_group_members(tmp_ctx, group_sid, &rids,
559 &num_members);
560 if (!NT_STATUS_IS_OK(result)) {
561 TALLOC_FREE(tmp_ctx);
562 return result;
565 if (num_members == 0) {
566 *num_names = 0;
567 *sid_mem = NULL;
568 *names = NULL;
569 *name_types = NULL;
570 TALLOC_FREE(tmp_ctx);
571 return NT_STATUS_OK;
574 *sid_mem = TALLOC_ARRAY(mem_ctx, DOM_SID, num_members);
575 *names = TALLOC_ARRAY(mem_ctx, char *, num_members);
576 *name_types = TALLOC_ARRAY(mem_ctx, uint32, num_members);
577 sids = TALLOC_ARRAY(tmp_ctx, const DOM_SID *, num_members);
579 if (((*sid_mem) == NULL) || ((*names) == NULL) ||
580 ((*name_types) == NULL) || (sids == NULL)) {
581 TALLOC_FREE(tmp_ctx);
582 return NT_STATUS_NO_MEMORY;
586 * Prepare an array of sid pointers for the lookup_sids calling
587 * convention.
590 for (i=0; i<num_members; i++) {
591 DOM_SID *sid = &((*sid_mem)[i]);
592 if (!sid_compose(sid, &domain->sid, rids[i])) {
593 TALLOC_FREE(tmp_ctx);
594 return NT_STATUS_INTERNAL_ERROR;
596 sids[i] = sid;
599 result = lookup_sids(tmp_ctx, num_members, sids, 1,
600 &lsa_domains, &lsa_names);
601 if (!NT_STATUS_IS_OK(result)) {
602 TALLOC_FREE(tmp_ctx);
603 return result;
606 num_mapped = 0;
607 for (i=0; i<num_members; i++) {
608 if (lsa_names[i].type != SID_NAME_USER) {
609 DEBUG(2, ("Got %s as group member -- ignoring\n",
610 sid_type_lookup(lsa_names[i].type)));
611 continue;
613 if (!((*names)[i] = talloc_strdup((*names),
614 lsa_names[i].name))) {
615 TALLOC_FREE(tmp_ctx);
616 return NT_STATUS_NO_MEMORY;
619 (*name_types)[i] = lsa_names[i].type;
621 num_mapped += 1;
624 *num_names = num_mapped;
626 TALLOC_FREE(tmp_ctx);
627 return NT_STATUS_OK;
630 /* get a list of trusted domains */
631 static NTSTATUS sam_trusted_domains(struct winbindd_domain *domain,
632 TALLOC_CTX *mem_ctx,
633 uint32 *num_domains,
634 char ***names,
635 char ***alt_names,
636 DOM_SID **dom_sids)
638 NTSTATUS nt_status;
639 struct trustdom_info **domains;
640 int i;
641 TALLOC_CTX *tmp_ctx;
643 *num_domains = 0;
644 *names = NULL;
645 *alt_names = NULL;
646 *dom_sids = NULL;
648 if (!(tmp_ctx = talloc_init("trusted_domains"))) {
649 return NT_STATUS_NO_MEMORY;
652 nt_status = pdb_enum_trusteddoms(tmp_ctx, num_domains, &domains);
653 if (!NT_STATUS_IS_OK(nt_status)) {
654 TALLOC_FREE(tmp_ctx);
655 return nt_status;
658 if (*num_domains) {
659 *names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
660 *alt_names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
661 *dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
663 if ((*alt_names == NULL) || (*names == NULL) || (*dom_sids == NULL)) {
664 TALLOC_FREE(tmp_ctx);
665 return NT_STATUS_NO_MEMORY;
667 } else {
668 *names = NULL;
669 *alt_names = NULL;
670 *dom_sids = NULL;
673 for (i=0; i<*num_domains; i++) {
674 (*alt_names)[i] = NULL;
675 if (!((*names)[i] = talloc_strdup((*names),
676 domains[i]->name))) {
677 TALLOC_FREE(tmp_ctx);
678 return NT_STATUS_NO_MEMORY;
680 sid_copy(&(*dom_sids)[i], &domains[i]->sid);
683 TALLOC_FREE(tmp_ctx);
684 return NT_STATUS_OK;
687 /* the rpc backend methods are exposed via this structure */
688 struct winbindd_methods builtin_passdb_methods = {
689 false,
690 builtin_query_user_list,
691 enum_dom_groups,
692 enum_local_groups,
693 name_to_sid,
694 sid_to_name,
695 rids_to_names,
696 builtin_query_user,
697 lookup_usergroups,
698 lookup_useraliases,
699 builtin_lookup_groupmem,
700 sequence_number,
701 lockout_policy,
702 password_policy,
703 builtin_trusted_domains,
706 /* the rpc backend methods are exposed via this structure */
707 struct winbindd_methods sam_passdb_methods = {
708 false,
709 sam_query_user_list,
710 enum_dom_groups,
711 enum_local_groups,
712 name_to_sid,
713 sid_to_name,
714 rids_to_names,
715 sam_query_user,
716 lookup_usergroups,
717 lookup_useraliases,
718 sam_lookup_groupmem,
719 sequence_number,
720 lockout_policy,
721 password_policy,
722 sam_trusted_domains,