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/>.
29 #define DBGC_CLASS DBGC_WINBIND
31 static NTSTATUS enum_groups_internal(struct winbindd_domain *domain,
34 struct acct_info **info,
35 enum lsa_SidType sidtype)
37 struct pdb_search *search;
38 struct samr_displayentry *entries;
40 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
42 if (sidtype == SID_NAME_ALIAS) {
43 search = pdb_search_aliases(&domain->sid);
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;
57 *info = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
59 result = NT_STATUS_NO_MEMORY;
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;
71 pdb_search_destroy(search);
75 /* List all local groups (aliases) */
76 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
79 struct acct_info **info)
81 return enum_groups_internal(domain,
88 /* convert a single name to a sid in a domain */
89 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
91 enum winbindd_cmd original_cmd,
92 const char *domain_name,
95 enum lsa_SidType *type)
98 uint32 flags = LOOKUP_NAME_ALL;
100 switch ( original_cmd ) {
101 case WINBINDD_LOOKUPNAME:
102 /* This call is ok */
105 /* Avoid any NSS calls in the lookup_name by default */
106 flags |= LOOKUP_NAME_EXPLICIT;
107 DEBUG(10,("winbindd_passdb: limiting name_to_sid() to explicit mappings\n"));
111 if (domain_name && domain_name[0] && strchr_m(name, '\\') == NULL) {
112 fullname = talloc_asprintf(mem_ctx, "%s\\%s",
114 if (fullname == NULL) {
115 return NT_STATUS_NO_MEMORY;
121 DEBUG(10, ("Finding fullname %s\n", fullname));
123 if ( !lookup_name( mem_ctx, fullname, flags, NULL, NULL, sid, type ) ) {
124 return NT_STATUS_NONE_MAPPED;
127 DEBUG(10, ("name_to_sid for %s returned %s (%s)\n",
130 sid_type_lookup((uint32)*type)));
136 convert a domain SID to a user or group name
138 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
143 enum lsa_SidType *type)
145 const char *dom, *nam;
147 DEBUG(10, ("Converting SID %s\n", sid_string_dbg(sid)));
150 if (!sid_check_is_in_builtin(sid) &&
151 !sid_check_is_in_our_domain(sid) &&
152 !sid_check_is_in_unix_users(sid) &&
153 !sid_check_is_unix_users(sid) &&
154 !sid_check_is_in_unix_groups(sid) &&
155 !sid_check_is_unix_groups(sid) &&
156 !sid_check_is_in_wellknown_domain(sid))
158 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
159 "passdb backend\n", sid_string_dbg(sid)));
160 return NT_STATUS_NONE_MAPPED;
163 if (!lookup_sid(mem_ctx, sid, &dom, &nam, type)) {
164 return NT_STATUS_NONE_MAPPED;
167 *domain_name = talloc_strdup(mem_ctx, dom);
168 *name = talloc_strdup(mem_ctx, nam);
173 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
180 enum lsa_SidType **types)
195 if (!sid_check_is_in_builtin(sid) &&
196 !sid_check_is_in_our_domain(sid) &&
197 !sid_check_is_in_unix_users(sid) &&
198 !sid_check_is_unix_users(sid) &&
199 !sid_check_is_in_unix_groups(sid) &&
200 !sid_check_is_unix_groups(sid) &&
201 !sid_check_is_in_wellknown_domain(sid))
203 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
204 "passdb backend\n", sid_string_dbg(sid)));
205 return NT_STATUS_NONE_MAPPED;
208 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
209 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
211 if ((*names == NULL) || (*types == NULL)) {
212 return NT_STATUS_NO_MEMORY;
215 have_mapped = have_unmapped = false;
217 for (i=0; i<num_rids; i++) {
219 const char *dom = NULL, *nam = NULL;
220 enum lsa_SidType type = SID_NAME_UNKNOWN;
222 if (!sid_compose(&lsid, sid, rids[i])) {
223 return NT_STATUS_INTERNAL_ERROR;
226 if (!lookup_sid(mem_ctx, &lsid, &dom, &nam, &type)) {
227 have_unmapped = true;
228 (*types)[i] = SID_NAME_UNKNOWN;
229 (*names)[i] = talloc_strdup(mem_ctx, "");
233 (*names)[i] = CONST_DISCARD(char *, nam);
236 if (*domain_name == NULL) {
237 *domain_name = CONST_DISCARD(char *, dom);
239 char *dname = CONST_DISCARD(char *, dom);
245 return NT_STATUS_NONE_MAPPED;
247 if (!have_unmapped) {
250 return STATUS_SOME_UNMAPPED;
253 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
254 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
256 const DOM_SID *user_sid,
257 uint32 *num_groups, DOM_SID **user_gids)
260 DOM_SID *groups = NULL;
265 if ( (user = samu_new(mem_ctx)) == NULL ) {
266 return NT_STATUS_NO_MEMORY;
269 if ( !pdb_getsampwsid( user, user_sid ) ) {
271 return NT_STATUS_NO_SUCH_USER;
274 result = pdb_enum_group_memberships( mem_ctx, user, &groups, &gids, &ngroups );
278 *num_groups = (uint32)ngroups;
284 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
286 uint32 num_sids, const DOM_SID *sids,
287 uint32 *p_num_aliases, uint32 **rids)
290 size_t num_aliases = 0;
292 result = pdb_enum_alias_memberships(mem_ctx, &domain->sid,
293 sids, num_sids, rids, &num_aliases);
295 *p_num_aliases = num_aliases;
299 /* find the sequence number for a domain */
300 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
305 result = pdb_get_seq_num(&seq_num);
310 *seq = (int) seq_num;
315 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
317 struct samr_DomInfo12 *policy)
319 /* actually we have that */
320 return NT_STATUS_NOT_IMPLEMENTED;
323 static NTSTATUS password_policy(struct winbindd_domain *domain,
325 struct samr_DomInfo1 *policy)
327 uint32 min_pass_len,pass_hist,password_properties;
328 time_t u_expire, u_min_age;
329 NTTIME nt_expire, nt_min_age;
330 uint32 account_policy_temp;
332 if ((policy = TALLOC_ZERO_P(mem_ctx, struct samr_DomInfo1)) == NULL) {
333 return NT_STATUS_NO_MEMORY;
336 if (!pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &account_policy_temp)) {
337 return NT_STATUS_ACCESS_DENIED;
339 min_pass_len = account_policy_temp;
341 if (!pdb_get_account_policy(AP_PASSWORD_HISTORY, &account_policy_temp)) {
342 return NT_STATUS_ACCESS_DENIED;
344 pass_hist = account_policy_temp;
346 if (!pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp)) {
347 return NT_STATUS_ACCESS_DENIED;
349 password_properties = account_policy_temp;
351 if (!pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp)) {
352 return NT_STATUS_ACCESS_DENIED;
354 u_expire = account_policy_temp;
356 if (!pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &account_policy_temp)) {
357 return NT_STATUS_ACCESS_DENIED;
359 u_min_age = account_policy_temp;
361 unix_to_nt_time_abs(&nt_expire, u_expire);
362 unix_to_nt_time_abs(&nt_min_age, u_min_age);
364 init_samr_DomInfo1(policy,
365 (uint16)min_pass_len,
374 /*********************************************************************
375 BUILTIN specific functions.
376 *********************************************************************/
378 /* list all domain groups */
379 static NTSTATUS builtin_enum_dom_groups(struct winbindd_domain *domain,
382 struct acct_info **info)
384 /* BUILTIN doesn't have domain groups */
390 /* Query display info for a domain. This returns enough information plus a
391 bit extra to give an overview of domain users for the User Manager
393 static NTSTATUS builtin_query_user_list(struct winbindd_domain *domain,
396 WINBIND_USERINFO **info)
398 /* We don't have users */
404 /* Lookup user information from a rid or username. */
405 static NTSTATUS builtin_query_user(struct winbindd_domain *domain,
407 const DOM_SID *user_sid,
408 WINBIND_USERINFO *user_info)
410 return NT_STATUS_NO_SUCH_USER;
413 static NTSTATUS builtin_lookup_groupmem(struct winbindd_domain *domain,
415 const DOM_SID *group_sid, uint32 *num_names,
416 DOM_SID **sid_mem, char ***names,
423 return NT_STATUS_NO_SUCH_GROUP;
426 /* get a list of trusted domains - builtin domain */
427 static NTSTATUS builtin_trusted_domains(struct winbindd_domain *domain,
441 /*********************************************************************
442 SAM specific functions.
443 *********************************************************************/
445 /* list all domain groups */
446 static NTSTATUS sam_enum_dom_groups(struct winbindd_domain *domain,
449 struct acct_info **info)
451 return enum_groups_internal(domain,
458 static NTSTATUS sam_query_user_list(struct winbindd_domain *domain,
461 WINBIND_USERINFO **info)
463 struct pdb_search *ps = pdb_search_users(ACB_NORMAL);
464 struct samr_displayentry *entries = NULL;
471 return NT_STATUS_NO_MEMORY;
474 *num_entries = pdb_search_entries(ps,
478 *info = TALLOC_ZERO_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
480 pdb_search_destroy(ps);
481 return NT_STATUS_NO_MEMORY;
484 for (i = 0; i < *num_entries; i++) {
485 struct samr_displayentry *e = &entries[i];
487 (*info)[i].acct_name = talloc_strdup(mem_ctx, e->account_name );
488 (*info)[i].full_name = talloc_strdup(mem_ctx, e->fullname );
489 (*info)[i].homedir = NULL;
490 (*info)[i].shell = NULL;
491 sid_compose(&(*info)[i].user_sid, &domain->sid, e->rid);
493 /* For the moment we set the primary group for
494 every user to be the Domain Users group.
495 There are serious problems with determining
496 the actual primary group for large domains.
497 This should really be made into a 'winbind
498 force group' smb.conf parameter or
499 something like that. */
501 sid_compose(&(*info)[i].group_sid, &domain->sid,
502 DOMAIN_GROUP_RID_USERS);
505 pdb_search_destroy(ps);
509 /* Lookup user information from a rid or username. */
510 static NTSTATUS sam_query_user(struct winbindd_domain *domain,
512 const DOM_SID *user_sid,
513 WINBIND_USERINFO *user_info)
515 struct samu *sampass = NULL;
517 ZERO_STRUCTP(user_info);
519 if (!sid_check_is_in_our_domain(user_sid)) {
520 return NT_STATUS_NO_SUCH_USER;
523 DEBUG(10,("sam_query_user: getting samu info for sid %s\n",
524 sid_string_dbg(user_sid) ));
526 if (!(sampass = samu_new(mem_ctx))) {
527 return NT_STATUS_NO_MEMORY;
530 if (!pdb_getsampwsid(sampass, user_sid)) {
531 TALLOC_FREE(sampass);
532 return NT_STATUS_NO_SUCH_USER;
535 if (pdb_get_group_sid(sampass) == NULL) {
536 TALLOC_FREE(sampass);
537 return NT_STATUS_NO_SUCH_GROUP;
540 DEBUG(10,("sam_query_user: group sid %s\n",
541 sid_string_dbg(sampass->group_sid) ));
543 sid_copy(&user_info->user_sid, user_sid);
544 sid_copy(&user_info->group_sid, sampass->group_sid);
546 user_info->acct_name = talloc_strdup(mem_ctx, sampass->username ?
547 sampass->username : "");
548 user_info->full_name = talloc_strdup(mem_ctx, sampass->full_name ?
549 sampass->full_name : "");
550 user_info->homedir = talloc_strdup(mem_ctx, sampass->home_dir ?
551 sampass->home_dir : "");
552 if (sampass->unix_pw && sampass->unix_pw->pw_shell) {
553 user_info->shell = talloc_strdup(mem_ctx, sampass->unix_pw->pw_shell);
555 user_info->shell = talloc_strdup(mem_ctx, "");
557 user_info->primary_gid = sampass->unix_pw ? sampass->unix_pw->pw_gid : (gid_t)-1;
559 TALLOC_FREE(sampass);
563 /* Lookup group membership given a rid. */
564 static NTSTATUS sam_lookup_groupmem(struct winbindd_domain *domain,
566 const DOM_SID *group_sid, uint32 *num_names,
567 DOM_SID **sid_mem, char ***names,
570 size_t i, num_members, num_mapped;
573 const DOM_SID **sids;
574 struct lsa_dom_info *lsa_domains;
575 struct lsa_name_info *lsa_names;
578 if (!sid_check_is_in_our_domain(group_sid)) {
579 /* There's no groups, only aliases in BUILTIN */
580 return NT_STATUS_NO_SUCH_GROUP;
583 if (!(tmp_ctx = talloc_init("lookup_groupmem"))) {
584 return NT_STATUS_NO_MEMORY;
587 result = pdb_enum_group_members(tmp_ctx, group_sid, &rids,
589 if (!NT_STATUS_IS_OK(result)) {
590 TALLOC_FREE(tmp_ctx);
594 if (num_members == 0) {
599 TALLOC_FREE(tmp_ctx);
603 *sid_mem = TALLOC_ARRAY(mem_ctx, DOM_SID, num_members);
604 *names = TALLOC_ARRAY(mem_ctx, char *, num_members);
605 *name_types = TALLOC_ARRAY(mem_ctx, uint32, num_members);
606 sids = TALLOC_ARRAY(tmp_ctx, const DOM_SID *, num_members);
608 if (((*sid_mem) == NULL) || ((*names) == NULL) ||
609 ((*name_types) == NULL) || (sids == NULL)) {
610 TALLOC_FREE(tmp_ctx);
611 return NT_STATUS_NO_MEMORY;
615 * Prepare an array of sid pointers for the lookup_sids calling
619 for (i=0; i<num_members; i++) {
620 DOM_SID *sid = &((*sid_mem)[i]);
621 if (!sid_compose(sid, &domain->sid, rids[i])) {
622 TALLOC_FREE(tmp_ctx);
623 return NT_STATUS_INTERNAL_ERROR;
628 result = lookup_sids(tmp_ctx, num_members, sids, 1,
629 &lsa_domains, &lsa_names);
630 if (!NT_STATUS_IS_OK(result)) {
631 TALLOC_FREE(tmp_ctx);
636 for (i=0; i<num_members; i++) {
637 if (lsa_names[i].type != SID_NAME_USER) {
638 DEBUG(2, ("Got %s as group member -- ignoring\n",
639 sid_type_lookup(lsa_names[i].type)));
642 if (!((*names)[num_mapped] = talloc_strdup((*names),
643 lsa_names[i].name))) {
644 TALLOC_FREE(tmp_ctx);
645 return NT_STATUS_NO_MEMORY;
648 (*name_types)[num_mapped] = lsa_names[i].type;
653 *num_names = num_mapped;
655 TALLOC_FREE(tmp_ctx);
659 /* get a list of trusted domains */
660 static NTSTATUS sam_trusted_domains(struct winbindd_domain *domain,
668 struct trustdom_info **domains;
677 if (!(tmp_ctx = talloc_init("trusted_domains"))) {
678 return NT_STATUS_NO_MEMORY;
681 nt_status = pdb_enum_trusteddoms(tmp_ctx, num_domains, &domains);
682 if (!NT_STATUS_IS_OK(nt_status)) {
683 TALLOC_FREE(tmp_ctx);
688 *names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
689 *alt_names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
690 *dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
692 if ((*alt_names == NULL) || (*names == NULL) || (*dom_sids == NULL)) {
693 TALLOC_FREE(tmp_ctx);
694 return NT_STATUS_NO_MEMORY;
702 for (i=0; i<*num_domains; i++) {
703 (*alt_names)[i] = NULL;
704 if (!((*names)[i] = talloc_strdup((*names),
705 domains[i]->name))) {
706 TALLOC_FREE(tmp_ctx);
707 return NT_STATUS_NO_MEMORY;
709 sid_copy(&(*dom_sids)[i], &domains[i]->sid);
712 TALLOC_FREE(tmp_ctx);
716 /* the rpc backend methods are exposed via this structure */
717 struct winbindd_methods builtin_passdb_methods = {
719 builtin_query_user_list,
720 builtin_enum_dom_groups,
728 builtin_lookup_groupmem,
732 builtin_trusted_domains,
735 /* the rpc backend methods are exposed via this structure */
736 struct winbindd_methods sam_passdb_methods = {