/* Unix SMB/CIFS implementation. Winbind rpc backend functions Copyright (C) Tim Potter 2000-2001,2003 Copyright (C) Simo Sorce 2003 Copyright (C) Volker Lendecke 2004 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "includes.h" #include "winbindd.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_WINBIND /* Query display info for a domain. This returns enough information plus a bit extra to give an overview of domain users for the User Manager application. */ static NTSTATUS query_user_list(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32 *num_entries, WINBIND_USERINFO **info) { /* We don't have users */ *num_entries = 0; *info = NULL; return NT_STATUS_OK; } /* list all domain groups */ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32 *num_entries, struct acct_info **info) { /* We don't have domain groups */ *num_entries = 0; *info = NULL; return NT_STATUS_OK; } /* List all domain groups */ static NTSTATUS enum_local_groups(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32 *num_entries, struct acct_info **info) { struct pdb_search *search; struct samr_displayentry *aliases; int i; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; search = pdb_search_aliases(&domain->sid); if (search == NULL) goto done; *num_entries = pdb_search_entries(search, 0, 0xffffffff, &aliases); if (*num_entries == 0) goto done; *info = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries); if (*info == NULL) { result = NT_STATUS_NO_MEMORY; goto done; } for (i=0; i<*num_entries; i++) { fstrcpy((*info)[i].acct_name, aliases[i].account_name); fstrcpy((*info)[i].acct_desc, aliases[i].description); (*info)[i].rid = aliases[i].rid; } result = NT_STATUS_OK; done: pdb_search_destroy(search); return result; } /* convert a single name to a sid in a domain */ static NTSTATUS name_to_sid(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, enum winbindd_cmd original_cmd, const char *domain_name, const char *name, DOM_SID *sid, enum lsa_SidType *type) { uint32 flags = LOOKUP_NAME_ALL; switch ( original_cmd ) { case WINBINDD_LOOKUPNAME: /* This call is ok */ break; default: /* Avoid any NSS calls in the lookup_name by default */ flags |= LOOKUP_NAME_EXPLICIT; DEBUG(10,("winbindd_passdb: limiting name_to_sid() to explicit mappings\n")); break; } DEBUG(10, ("Finding name %s\n", name)); if ( !lookup_name( mem_ctx, name, flags, NULL, NULL, sid, type ) ) { return NT_STATUS_NONE_MAPPED; } return NT_STATUS_OK; } /* convert a domain SID to a user or group name */ static NTSTATUS sid_to_name(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const DOM_SID *sid, char **domain_name, char **name, enum lsa_SidType *type) { const char *dom, *nam; DEBUG(10, ("Converting SID %s\n", sid_string_static(sid))); /* Paranoia check */ if (!sid_check_is_in_builtin(sid) && !sid_check_is_in_our_domain(sid) && !sid_check_is_in_unix_users(sid) && !sid_check_is_unix_users(sid) && !sid_check_is_in_unix_groups(sid) && !sid_check_is_unix_groups(sid) ) { DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with " "passdb backend\n", sid_string_static(sid))); return NT_STATUS_NONE_MAPPED; } if (!lookup_sid(mem_ctx, sid, &dom, &nam, type)) { return NT_STATUS_NONE_MAPPED; } *domain_name = talloc_strdup(mem_ctx, dom); *name = talloc_strdup(mem_ctx, nam); return NT_STATUS_OK; } static NTSTATUS rids_to_names(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const DOM_SID *sid, uint32 *rids, size_t num_rids, char **domain_name, char ***names, enum lsa_SidType **types) { return NT_STATUS_UNSUCCESSFUL; } /* Lookup user information from a rid or username. */ static NTSTATUS query_user(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const DOM_SID *user_sid, WINBIND_USERINFO *user_info) { return NT_STATUS_NO_SUCH_USER; } /* Lookup groups a user is a member of. I wish Unix had a call like this! */ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const DOM_SID *user_sid, uint32 *num_groups, DOM_SID **user_gids) { NTSTATUS result; DOM_SID *groups = NULL; gid_t *gids = NULL; size_t ngroups = 0; struct samu *user; if ( (user = samu_new(mem_ctx)) == NULL ) { return NT_STATUS_NO_MEMORY; } if ( !pdb_getsampwsid( user, user_sid ) ) { return NT_STATUS_NO_SUCH_USER; } result = pdb_enum_group_memberships( mem_ctx, user, &groups, &gids, &ngroups ); TALLOC_FREE( user ); *num_groups = (uint32)ngroups; *user_gids = groups; return result; } static NTSTATUS lookup_useraliases(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32 num_sids, const DOM_SID *sids, uint32 *p_num_aliases, uint32 **rids) { NTSTATUS result; size_t num_aliases = 0; result = pdb_enum_alias_memberships(mem_ctx, &domain->sid, sids, num_sids, rids, &num_aliases); *p_num_aliases = num_aliases; return result; } /* Lookup group membership given a rid. */ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const DOM_SID *group_sid, uint32 *num_names, DOM_SID **sid_mem, char ***names, uint32 **name_types) { size_t i, num_members, num_mapped; uint32 *rids; NTSTATUS result; const DOM_SID **sids; struct lsa_dom_info *lsa_domains; struct lsa_name_info *lsa_names; TALLOC_CTX *tmp_ctx; if (!sid_check_is_in_our_domain(group_sid)) { /* There's no groups, only aliases in BUILTIN */ return NT_STATUS_NO_SUCH_GROUP; } if (!(tmp_ctx = talloc_init("lookup_groupmem"))) { return NT_STATUS_NO_MEMORY; } result = pdb_enum_group_members(tmp_ctx, group_sid, &rids, &num_members); if (!NT_STATUS_IS_OK(result)) { TALLOC_FREE(tmp_ctx); return result; } if (num_members == 0) { *num_names = 0; *sid_mem = NULL; *names = NULL; *name_types = NULL; TALLOC_FREE(tmp_ctx); return NT_STATUS_OK; } *sid_mem = TALLOC_ARRAY(mem_ctx, DOM_SID, num_members); *names = TALLOC_ARRAY(mem_ctx, char *, num_members); *name_types = TALLOC_ARRAY(mem_ctx, uint32, num_members); sids = TALLOC_ARRAY(tmp_ctx, const DOM_SID *, num_members); if (((*sid_mem) == NULL) || ((*names) == NULL) || ((*name_types) == NULL) || (sids == NULL)) { TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } /* * Prepare an array of sid pointers for the lookup_sids calling * convention. */ for (i=0; isid, rids[i])) { TALLOC_FREE(tmp_ctx); return NT_STATUS_INTERNAL_ERROR; } sids[i] = sid; } result = lookup_sids(tmp_ctx, num_members, sids, 1, &lsa_domains, &lsa_names); if (!NT_STATUS_IS_OK(result)) { TALLOC_FREE(tmp_ctx); return result; } num_mapped = 0; for (i=0; iname))) { TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } sid_copy(&(*dom_sids)[i], &domains[i]->sid); } TALLOC_FREE(tmp_ctx); return NT_STATUS_OK; } /* the rpc backend methods are exposed via this structure */ struct winbindd_methods passdb_methods = { False, query_user_list, enum_dom_groups, enum_local_groups, name_to_sid, sid_to_name, rids_to_names, query_user, lookup_usergroups, lookup_useraliases, lookup_groupmem, sequence_number, lockout_policy, password_policy, trusted_domains, };