X-Git-Url: http://git.samba.org/samba.git/?p=bbaumbach%2Fsamba-autobuild%2F.git;a=blobdiff_plain;f=source3%2Fpassdb%2Flookup_sid.c;h=82c47b3145bc9e8a71720212f3d0cdaf56ebbba2;hp=f544a3f678a909c34c74ac39015c42c6a23092fc;hb=HEAD;hpb=c89affbd8da230cae6df25558fe621510690392c diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c index f544a3f678a..426ea3f81bd 100644 --- a/source3/passdb/lookup_sid.c +++ b/source3/passdb/lookup_sid.c @@ -1,4 +1,4 @@ -/* +/* Unix SMB/CIFS implementation. uid/user handling Copyright (C) Andrew Tridgell 1992-1998 @@ -21,12 +21,50 @@ #include "includes.h" #include "passdb.h" +#include "lib/util_unixsids.h" #include "../librpc/gen_ndr/ndr_security.h" #include "secrets.h" -#include "memcache.h" +#include "../lib/util/memcache.h" #include "idmap_cache.h" #include "../libcli/security/security.h" #include "lib/winbind_util.h" +#include "../librpc/gen_ndr/idmap.h" +#include "lib/util/bitmap.h" + +static bool lookup_unix_user_name(const char *name, struct dom_sid *sid) +{ + struct passwd *pwd; + bool ret; + + pwd = Get_Pwnam_alloc(talloc_tos(), name); + if (pwd == NULL) { + return False; + } + + /* + * For 64-bit uid's we have enough space in the whole SID, + * should they become necessary + */ + ret = sid_compose(sid, &global_sid_Unix_Users, pwd->pw_uid); + TALLOC_FREE(pwd); + return ret; +} + +static bool lookup_unix_group_name(const char *name, struct dom_sid *sid) +{ + struct group *grp; + + grp = getgrnam(name); + if (grp == NULL) { + return False; + } + + /* + * For 64-bit gid's we have enough space in the whole SID, + * should they become necessary + */ + return sid_compose(sid, &global_sid_Unix_Groups, grp->gr_gid); +} /***************************************************************** Dissect a user-provided name into domain, name, sid and type. @@ -34,7 +72,7 @@ If an explicit domain name was given in the form domain\user, it has to try that. If no explicit domain name was given, we have to do guesswork. -*****************************************************************/ +*****************************************************************/ bool lookup_name(TALLOC_CTX *mem_ctx, const char *full_name, int flags, @@ -45,7 +83,7 @@ bool lookup_name(TALLOC_CTX *mem_ctx, const char *tmp; const char *domain = NULL; const char *name = NULL; - uint32 rid; + uint32_t rid; struct dom_sid sid; enum lsa_SidType type; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); @@ -62,8 +100,18 @@ bool lookup_name(TALLOC_CTX *mem_ctx, PTR_DIFF(p, full_name)); name = talloc_strdup(tmp_ctx, p+1); } else { - domain = talloc_strdup(tmp_ctx, ""); - name = talloc_strdup(tmp_ctx, full_name); + char *q = strchr_m(full_name, '@'); + + /* Set the domain for UPNs */ + if (q != NULL) { + name = talloc_strndup(tmp_ctx, + full_name, + PTR_DIFF(q, full_name)); + domain = talloc_strdup(tmp_ctx, q + 1); + } else { + domain = talloc_strdup(tmp_ctx, ""); + name = talloc_strdup(tmp_ctx, full_name); + } } if ((domain == NULL) || (name == NULL)) { @@ -76,17 +124,36 @@ bool lookup_name(TALLOC_CTX *mem_ctx, full_name, domain, name)); DEBUG(10, ("lookup_name: flags = 0x0%x\n", flags)); - if ((flags & LOOKUP_NAME_DOMAIN) && - strequal(domain, get_global_sam_name())) - { + if ((flags & LOOKUP_NAME_DOMAIN) || (flags == 0)) { + bool check_global_sam = false; - /* It's our own domain, lookup the name in passdb */ - if (lookup_global_sam_name(name, flags, &rid, &type)) { - sid_compose(&sid, get_global_sam_sid(), rid); - goto ok; + check_global_sam = strequal(domain, get_global_sam_name()); + + /* If we are running on a DC that has PASSDB module with domain + * information, check if DNS forest name is matching the domain + * name. This is the case of IPA domain controller when + * trusted AD DC looks up users found in a Global Catalog of + * the forest root domain. */ + if (!check_global_sam && (IS_DC)) { + struct pdb_domain_info *dom_info = NULL; + dom_info = pdb_get_domain_info(tmp_ctx); + + if ((dom_info != NULL) && (dom_info->dns_forest != NULL)) { + check_global_sam = strequal(domain, dom_info->dns_forest); + } + + TALLOC_FREE(dom_info); + } + + if (check_global_sam) { + /* It's our own domain, lookup the name in passdb */ + if (lookup_global_sam_name(name, flags, &rid, &type)) { + sid_compose(&sid, get_global_sam_sid(), rid); + goto ok; + } + TALLOC_FREE(tmp_ctx); + return false; } - TALLOC_FREE(tmp_ctx); - return false; } if ((flags & LOOKUP_NAME_BUILTIN) && @@ -119,7 +186,7 @@ bool lookup_name(TALLOC_CTX *mem_ctx, goto ok; } - if (((flags & LOOKUP_NAME_NO_NSS) == 0) + if (((flags & (LOOKUP_NAME_NO_NSS|LOOKUP_NAME_GROUP)) == 0) && strequal(domain, unix_users_domain_name())) { if (lookup_unix_user_name(name, &sid)) { type = SID_NAME_USER; @@ -139,7 +206,31 @@ bool lookup_name(TALLOC_CTX *mem_ctx, return false; } - if ((domain[0] == '\0') && (!(flags & LOOKUP_NAME_ISOLATED))) { + /* + * Finally check for a well known domain name ("NT Authority"), + * this is being taken care of in lookup_wellknown_name(). + */ + if ((domain[0] != '\0') && + (flags & LOOKUP_NAME_WKN) && + lookup_wellknown_name(tmp_ctx, name, &sid, &domain)) + { + type = SID_NAME_WKN_GRP; + goto ok; + } + + /* + * If we're told not to look up 'isolated' names then we're + * done. + */ + if (!(flags & LOOKUP_NAME_ISOLATED)) { + TALLOC_FREE(tmp_ctx); + return false; + } + + /* + * No domain names beyond this point + */ + if (domain[0] != '\0') { TALLOC_FREE(tmp_ctx); return false; } @@ -151,6 +242,11 @@ bool lookup_name(TALLOC_CTX *mem_ctx, /* 1. well-known names */ + /* + * Check for well known names without a domain name. + * e.g. \Creator Owner. + */ + if ((flags & LOOKUP_NAME_WKN) && lookup_wellknown_name(tmp_ctx, name, &sid, &domain)) { @@ -214,7 +310,7 @@ bool lookup_name(TALLOC_CTX *mem_ctx, goto ok; } - /* 6. Builtin aliases */ + /* 6. Builtin aliases */ if ((flags & LOOKUP_NAME_BUILTIN) && lookup_builtin_name(name, &rid)) @@ -292,7 +388,7 @@ bool lookup_name(TALLOC_CTX *mem_ctx, /* 11. Ok, windows would end here. Samba has two more options: Unmapped users and unmapped groups */ - if (((flags & LOOKUP_NAME_NO_NSS) == 0) + if (((flags & (LOOKUP_NAME_NO_NSS|LOOKUP_NAME_GROUP)) == 0) && lookup_unix_user_name(name, &sid)) { domain = talloc_strdup(tmp_ctx, unix_users_domain_name()); type = SID_NAME_USER; @@ -338,7 +434,10 @@ bool lookup_name(TALLOC_CTX *mem_ctx, TALLOC_FREE(tmp_ctx); return false; } - strupper_m(tmp_dom); + if (!strupper_m(tmp_dom)) { + TALLOC_FREE(tmp_ctx); + return false; + } *ret_domain = tmp_dom; } @@ -365,25 +464,24 @@ bool lookup_name_smbconf(TALLOC_CTX *mem_ctx, const char **ret_domain, const char **ret_name, struct dom_sid *ret_sid, enum lsa_SidType *ret_type) { - char *qualified_name; - const char *p; + char *qualified_name = NULL; + const char *p = strchr_m(full_name, *lp_winbind_separator()); + bool is_qualified = p != NULL || strchr_m(full_name, '@') != NULL; - /* NB. No winbindd_separator here as lookup_name needs \\' */ - if ((p = strchr_m(full_name, *lp_winbind_separator())) != NULL) { + /* For DOMAIN\user or user@REALM directly call lookup_name(). */ + if (is_qualified) { /* The name is already qualified with a domain. */ - if (*lp_winbind_separator() != '\\') { - char *tmp; - + if (p != NULL && *lp_winbind_separator() != '\\') { /* lookup_name() needs '\\' as a separator */ - tmp = talloc_strdup(mem_ctx, full_name); - if (!tmp) { + qualified_name = talloc_strdup(mem_ctx, full_name); + if (qualified_name == NULL) { return false; } - tmp[p - full_name] = '\\'; - full_name = tmp; + qualified_name[p - full_name] = '\\'; + full_name = qualified_name; } return lookup_name(mem_ctx, full_name, flags, @@ -391,6 +489,30 @@ bool lookup_name_smbconf(TALLOC_CTX *mem_ctx, ret_sid, ret_type); } + /* Try with winbind default domain name. */ + if (lp_winbind_use_default_domain()) { + bool ok; + + qualified_name = talloc_asprintf(mem_ctx, + "%s\\%s", + lp_workgroup(), + full_name); + if (qualified_name == NULL) { + return false; + } + + ok = lookup_name(mem_ctx, + qualified_name, + flags, + ret_domain, + ret_name, + ret_sid, + ret_type); + if (ok) { + return true; + } + } + /* Try with our own SAM name. */ qualified_name = talloc_asprintf(mem_ctx, "%s\\%s", get_global_sam_name(), @@ -422,7 +544,7 @@ bool lookup_name_smbconf(TALLOC_CTX *mem_ctx, static bool wb_lookup_rids(TALLOC_CTX *mem_ctx, const struct dom_sid *domain_sid, - int num_rids, uint32 *rids, + int num_rids, uint32_t *rids, const char **domain_name, const char **names, enum lsa_SidType *types) { @@ -477,9 +599,10 @@ static bool lookup_rids(TALLOC_CTX *mem_ctx, const struct dom_sid *domain_sid, const char ***names, enum lsa_SidType **types) { int i; + struct dom_sid_buf buf; DEBUG(10, ("lookup_rids called for domain sid '%s'\n", - sid_string_dbg(domain_sid))); + dom_sid_str_buf(domain_sid, &buf))); if (num_rids) { *names = talloc_zero_array(mem_ctx, const char *, num_rids); @@ -496,7 +619,7 @@ static bool lookup_rids(TALLOC_CTX *mem_ctx, const struct dom_sid *domain_sid, *types = NULL; } - if (sid_check_is_domain(domain_sid)) { + if (sid_check_is_our_sam(domain_sid)) { NTSTATUS result; if (*domain_name == NULL) { @@ -612,7 +735,7 @@ static bool lookup_as_domain(const struct dom_sid *sid, TALLOC_CTX *mem_ctx, const char *tmp; enum lsa_SidType type; - if (sid_check_is_domain(sid)) { + if (sid_check_is_our_sam(sid)) { *name = talloc_strdup(mem_ctx, get_global_sam_name()); return true; } @@ -643,7 +766,7 @@ static bool lookup_as_domain(const struct dom_sid *sid, TALLOC_CTX *mem_ctx, } if (IS_DC) { - uint32 i, num_domains; + uint32_t i, num_domains; struct trustdom_info **domains; /* This is relatively expensive, but it happens only on DCs @@ -696,6 +819,7 @@ static bool lookup_as_domain(const struct dom_sid *sid, TALLOC_CTX *mem_ctx, static bool check_dom_sid_to_level(const struct dom_sid *sid, int level) { + struct dom_sid_buf buf; int ret = false; switch(level) { @@ -709,7 +833,7 @@ static bool check_dom_sid_to_level(const struct dom_sid *sid, int level) case 3: case 4: case 6: - ret = sid_check_is_domain(sid); + ret = sid_check_is_our_sam(sid); break; case 5: ret = false; @@ -718,7 +842,8 @@ static bool check_dom_sid_to_level(const struct dom_sid *sid, int level) DEBUG(10, ("%s SID %s in level %d\n", ret ? "Accepting" : "Rejecting", - sid_string_dbg(sid), level)); + dom_sid_str_buf(sid, &buf), + level)); return ret; } @@ -738,7 +863,7 @@ NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids, struct lsa_name_info **ret_names) { TALLOC_CTX *tmp_ctx; - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + NTSTATUS result; struct lsa_name_info *name_infos; struct lsa_dom_info *dom_infos = NULL; @@ -767,7 +892,7 @@ NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids, } /* First build up the data structures: - * + * * dom_infos is a list of domains referenced in the list of * SIDs. Later we will walk the list of domains and look up the RIDs * in bulk. @@ -895,13 +1020,18 @@ NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids, break; } - if (dom->num_idxs) { - if (!(rids = talloc_array(tmp_ctx, uint32, dom->num_idxs))) { - result = NT_STATUS_NO_MEMORY; - goto fail; - } - } else { - rids = NULL; + if (dom->num_idxs == 0) { + /* + * This happens only if the only sid related to + * this domain is the domain sid itself, which + * is mapped to SID_NAME_DOMAIN above. + */ + continue; + } + + if (!(rids = talloc_array(tmp_ctx, uint32_t, dom->num_idxs))) { + result = NT_STATUS_NO_MEMORY; + goto fail; } for (j=0; jnum_idxs; j++) { @@ -950,7 +1080,7 @@ NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids, /***************************************************************** *THE CANONICAL* convert SID to name function. -*****************************************************************/ +*****************************************************************/ bool lookup_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid, const char **ret_domain, const char **ret_name, @@ -958,10 +1088,12 @@ bool lookup_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid, { struct lsa_dom_info *domain; struct lsa_name_info *name; + struct dom_sid_buf buf; TALLOC_CTX *tmp_ctx; bool ret = false; - DEBUG(10, ("lookup_sid called for SID '%s'\n", sid_string_dbg(sid))); + DEBUG(10, ("lookup_sid called for SID '%s'\n", + dom_sid_str_buf(sid, &buf))); if (!(tmp_ctx = talloc_new(mem_ctx))) { DEBUG(0, ("talloc_new failed\n")); @@ -982,7 +1114,7 @@ bool lookup_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid, goto done; } - if ((ret_name != NULL) && + if ((ret_name != NULL) && !(*ret_name = talloc_strdup(mem_ctx, name->name))) { goto done; } @@ -995,298 +1127,159 @@ bool lookup_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid, done: if (ret) { - DEBUG(10, ("Sid %s -> %s\\%s(%d)\n", sid_string_dbg(sid), + DEBUG(10, ("Sid %s -> %s\\%s(%d)\n", + dom_sid_str_buf(sid, &buf), domain->name, name->name, name->type)); } else { - DEBUG(10, ("failed to lookup sid %s\n", sid_string_dbg(sid))); + DEBUG(10, ("failed to lookup sid %s\n", + dom_sid_str_buf(sid, &buf))); } TALLOC_FREE(tmp_ctx); return ret; } /***************************************************************** - Id mapping cache. This is to avoid Winbind mappings already - seen by smbd to be queried too frequently, keeping winbindd - busy, and blocking smbd while winbindd is busy with other - stuff. Written by Michael Steffens , - modified to use linked lists by jra. -*****************************************************************/ + *THE LEGACY* convert SID to id function. +*****************************************************************/ - -/***************************************************************** - *THE LEGACY* convert uid_t to SID function. -*****************************************************************/ - -static void legacy_uid_to_sid(struct dom_sid *psid, uid_t uid) +static bool legacy_sid_to_unixid(const struct dom_sid *psid, struct unixid *id) { bool ret; - ZERO_STRUCTP(psid); - become_root(); - ret = pdb_uid_to_sid(uid, psid); + ret = pdb_sid_to_id(psid, id); unbecome_root(); - if (ret) { - /* This is a mapped user */ - goto done; + if (!ret) { + struct dom_sid_buf buf; + DEBUG(10,("LEGACY: mapping failed for sid %s\n", + dom_sid_str_buf(psid, &buf))); + return false; } - /* This is an unmapped user */ - - uid_to_unix_users_sid(uid, psid); - - done: - DEBUG(10,("LEGACY: uid %u -> sid %s\n", (unsigned int)uid, - sid_string_dbg(psid))); - - return; + return true; } -/***************************************************************** - *THE LEGACY* convert gid_t to SID function. -*****************************************************************/ - -static void legacy_gid_to_sid(struct dom_sid *psid, gid_t gid) +static bool legacy_sid_to_gid(const struct dom_sid *psid, gid_t *pgid) { - bool ret; - - ZERO_STRUCTP(psid); - - become_root(); - ret = pdb_gid_to_sid(gid, psid); - unbecome_root(); - - if (ret) { - /* This is a mapped group */ - goto done; + struct unixid id; + if (!legacy_sid_to_unixid(psid, &id)) { + return false; } - - /* This is an unmapped group */ - - gid_to_unix_groups_sid(gid, psid); - - done: - DEBUG(10,("LEGACY: gid %u -> sid %s\n", (unsigned int)gid, - sid_string_dbg(psid))); - - return; -} - -/***************************************************************** - *THE LEGACY* convert SID to uid function. -*****************************************************************/ - -static bool legacy_sid_to_uid(const struct dom_sid *psid, uid_t *puid) -{ - enum lsa_SidType type; - - if (sid_check_is_in_our_domain(psid)) { - uid_t uid; - gid_t gid; - bool ret; - - become_root(); - ret = pdb_sid_to_id(psid, &uid, &gid, &type); - unbecome_root(); - - if (ret) { - if (type != SID_NAME_USER) { - DEBUG(5, ("sid %s is a %s, expected a user\n", - sid_string_dbg(psid), - sid_type_lookup(type))); - return false; - } - *puid = uid; - goto done; - } - - /* This was ours, but it was not mapped. Fail */ + if (id.type == ID_TYPE_GID || id.type == ID_TYPE_BOTH) { + *pgid = id.id; + return true; } - - DEBUG(10,("LEGACY: mapping failed for sid %s\n", - sid_string_dbg(psid))); return false; - -done: - DEBUG(10,("LEGACY: sid %s -> uid %u\n", sid_string_dbg(psid), - (unsigned int)*puid )); - - return true; } -/***************************************************************** - *THE LEGACY* convert SID to gid function. - Group mapping is used for gids that maps to Wellknown SIDs -*****************************************************************/ - -static bool legacy_sid_to_gid(const struct dom_sid *psid, gid_t *pgid) +static bool legacy_sid_to_uid(const struct dom_sid *psid, uid_t *puid) { - GROUP_MAP *map; - enum lsa_SidType type; - - map = talloc_zero(NULL, GROUP_MAP); - if (!map) { - return false; - } - - if ((sid_check_is_in_builtin(psid) || - sid_check_is_in_wellknown_domain(psid))) { - bool ret; - - become_root(); - ret = pdb_getgrsid(map, *psid); - unbecome_root(); - - if (ret) { - *pgid = map->gid; - goto done; - } - DEBUG(10,("LEGACY: mapping failed for sid %s\n", - sid_string_dbg(psid))); + struct unixid id; + if (!legacy_sid_to_unixid(psid, &id)) { return false; } - - if (sid_check_is_in_our_domain(psid)) { - uid_t uid; - gid_t gid; - bool ret; - - become_root(); - ret = pdb_sid_to_id(psid, &uid, &gid, &type); - unbecome_root(); - - if (ret) { - if ((type != SID_NAME_DOM_GRP) && - (type != SID_NAME_ALIAS)) { - DEBUG(5, ("LEGACY: sid %s is a %s, expected " - "a group\n", sid_string_dbg(psid), - sid_type_lookup(type))); - return false; - } - *pgid = gid; - goto done; - } - - /* This was ours, but it was not mapped. Fail */ + if (id.type == ID_TYPE_UID || id.type == ID_TYPE_BOTH) { + *puid = id.id; + return true; } - - DEBUG(10,("LEGACY: mapping failed for sid %s\n", - sid_string_dbg(psid))); return false; - - done: - DEBUG(10,("LEGACY: sid %s -> gid %u\n", sid_string_dbg(psid), - (unsigned int)*pgid )); - - TALLOC_FREE(map); - return true; } -/***************************************************************** - *THE CANONICAL* convert uid_t to SID function. -*****************************************************************/ - -void uid_to_sid(struct dom_sid *psid, uid_t uid) +void xid_to_sid(struct dom_sid *psid, const struct unixid *xid) { bool expired = true; bool ret; - ZERO_STRUCTP(psid); + struct dom_sid_buf buf; - /* Check the winbindd cache directly. */ - ret = idmap_cache_find_uid2sid(uid, psid, &expired); + SMB_ASSERT(xid->type == ID_TYPE_UID || xid->type == ID_TYPE_GID); + + *psid = (struct dom_sid) {0}; - if (ret && !expired && is_null_sid(psid)) { + ret = idmap_cache_find_xid2sid(xid, psid, &expired); + if (ret && !expired) { + DBG_DEBUG("%cID %"PRIu32" -> %s from cache\n", + xid->type == ID_TYPE_UID ? 'U' : 'G', + xid->id, + dom_sid_str_buf(psid, &buf)); + goto done; + } + + ret = winbind_xid_to_sid(psid, xid); + if (ret) { /* - * Negative cache entry, we already asked. - * do legacy. + * winbind can return an explicit negative mapping + * here. It's up to winbind to prime the cache either + * positively or negatively, don't mess with the cache + * here. */ - legacy_uid_to_sid(psid, uid); - return; + DBG_DEBUG("%cID %"PRIu32" -> %s from cache\n", + xid->type == ID_TYPE_UID ? 'U' : 'G', + xid->id, + dom_sid_str_buf(psid, &buf)); + goto done; } - if (!ret || expired) { - /* Not in cache. Ask winbindd. */ - if (!winbind_uid_to_sid(psid, uid)) { - /* - * We shouldn't return the NULL SID - * here if winbind was running and - * couldn't map, as winbind will have - * added a negative entry that will - * cause us to go though the - * legacy_uid_to_sid() - * function anyway in the case above - * the next time we ask. - */ - DEBUG(5, ("uid_to_sid: winbind failed to find a sid " - "for uid %u\n", (unsigned int)uid)); + { + /* + * Make a copy, pdb_id_to_sid might want to turn + * xid->type into ID_TYPE_BOTH, which we ignore here. + */ + struct unixid rw_xid = *xid; - legacy_uid_to_sid(psid, uid); - return; - } + become_root(); + ret = pdb_id_to_sid(&rw_xid, psid); + unbecome_root(); } - DEBUG(10,("uid %u -> sid %s\n", (unsigned int)uid, - sid_string_dbg(psid))); - - return; -} - -/***************************************************************** - *THE CANONICAL* convert gid_t to SID function. -*****************************************************************/ - -void gid_to_sid(struct dom_sid *psid, gid_t gid) -{ - bool expired = true; - bool ret; - ZERO_STRUCTP(psid); - - /* Check the winbindd cache directly. */ - ret = idmap_cache_find_gid2sid(gid, psid, &expired); + if (ret) { + DBG_DEBUG("%cID %"PRIu32" -> %s from passdb\n", + xid->type == ID_TYPE_UID ? 'U' : 'G', + xid->id, + dom_sid_str_buf(psid, &buf)); + goto done; + } - if (ret && !expired && is_null_sid(psid)) { +done: + if (is_null_sid(psid)) { /* - * Negative cache entry, we already asked. - * do legacy. + * Nobody found anything: Return S-1-22-xx-yy. Don't + * store that in caches, this is up to the layers + * beneath us. */ - legacy_gid_to_sid(psid, gid); - return; - } - - if (!ret || expired) { - /* Not in cache. Ask winbindd. */ - if (!winbind_gid_to_sid(psid, gid)) { - /* - * We shouldn't return the NULL SID - * here if winbind was running and - * couldn't map, as winbind will have - * added a negative entry that will - * cause us to go though the - * legacy_gid_to_sid() - * function anyway in the case above - * the next time we ask. - */ - DEBUG(5, ("gid_to_sid: winbind failed to find a sid " - "for gid %u\n", (unsigned int)gid)); - - legacy_gid_to_sid(psid, gid); - return; + if (xid->type == ID_TYPE_UID) { + uid_to_unix_users_sid(xid->id, psid); + } else { + gid_to_unix_groups_sid(xid->id, psid); } + + DBG_DEBUG("%cID %"PRIu32" -> %s fallback\n", + xid->type == ID_TYPE_UID ? 'U' : 'G', + xid->id, + dom_sid_str_buf(psid, &buf)); } +} - DEBUG(10,("gid %u -> sid %s\n", (unsigned int)gid, - sid_string_dbg(psid))); +void uid_to_sid(struct dom_sid *psid, uid_t uid) +{ + struct unixid xid = { .type = ID_TYPE_UID, .id = uid}; + xid_to_sid(psid, &xid); +} - return; +void gid_to_sid(struct dom_sid *psid, gid_t gid) +{ + struct unixid xid = { .type = ID_TYPE_GID, .id = gid}; + xid_to_sid(psid, &xid); } -bool sids_to_unix_ids(const struct dom_sid *sids, uint32_t num_sids, - struct wbcUnixId *ids) +bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids, + struct unixid *ids) { struct wbcDomainSid *wbc_sids = NULL; struct wbcUnixId *wbc_ids = NULL; + struct bitmap *found = NULL; uint32_t i, num_not_cached; + uint32_t wbc_ids_size = 0; wbcErr err; bool ret = false; @@ -1294,6 +1287,20 @@ bool sids_to_unix_ids(const struct dom_sid *sids, uint32_t num_sids, if (wbc_sids == NULL) { return false; } + found = bitmap_talloc(wbc_sids, num_sids); + if (found == NULL) { + goto fail; + } + + /* + * We go through the requested SID array three times. + * First time to look for global_sid_Unix_Users + * and global_sid_Unix_Groups SIDS, and to look + * for mappings cached in the idmap_cache. + * + * Use bitmap_set() to mark an ids[] array entry as + * being mapped. + */ num_not_cached = 0; @@ -1303,29 +1310,25 @@ bool sids_to_unix_ids(const struct dom_sid *sids, uint32_t num_sids, if (sid_peek_check_rid(&global_sid_Unix_Users, &sids[i], &rid)) { - ids[i].type = WBC_ID_TYPE_UID; - ids[i].id.uid = rid; + ids[i].type = ID_TYPE_UID; + ids[i].id = rid; + bitmap_set(found, i); continue; } if (sid_peek_check_rid(&global_sid_Unix_Groups, &sids[i], &rid)) { - ids[i].type = WBC_ID_TYPE_GID; - ids[i].id.gid = rid; - continue; - } - if (idmap_cache_find_sid2uid(&sids[i], &ids[i].id.uid, - &expired) - && !expired) { - ids[i].type = WBC_ID_TYPE_UID; + ids[i].type = ID_TYPE_GID; + ids[i].id = rid; + bitmap_set(found, i); continue; } - if (idmap_cache_find_sid2gid(&sids[i], &ids[i].id.gid, - &expired) - && !expired) { - ids[i].type = WBC_ID_TYPE_GID; + if (idmap_cache_find_sid2unixid(&sids[i], &ids[i], &expired) + && !expired) + { + bitmap_set(found, i); continue; } - ids[i].type = WBC_ID_TYPE_NOT_SPECIFIED; + ids[i].type = ID_TYPE_NOT_SPECIFIED; memcpy(&wbc_sids[num_not_cached], &sids[i], ndr_size_dom_sid(&sids[i], 0)); num_not_cached += 1; @@ -1333,42 +1336,136 @@ bool sids_to_unix_ids(const struct dom_sid *sids, uint32_t num_sids, if (num_not_cached == 0) { goto done; } - wbc_ids = talloc_array(talloc_tos(), struct wbcUnixId, num_not_cached); + + /* + * For the ones that we couldn't map in the loop above, query winbindd + * via wbcSidsToUnixIds(). + */ + + wbc_ids_size = num_not_cached; + wbc_ids = talloc_array(talloc_tos(), struct wbcUnixId, wbc_ids_size); if (wbc_ids == NULL) { goto fail; } - for (i=0; i uid %u\n", sid_string_dbg(psid), - (unsigned int)*puid )); + DEBUG(10,("sid %s -> uid %u\n", + dom_sid_str_buf(psid, &buf), + (unsigned int)*puid )); return true; } + if (sid_check_is_in_unix_groups(psid)) { + DBG_DEBUG("SID %s is a group, failing\n", + dom_sid_str_buf(psid, &buf)); + return false; + } + /* Check the winbindd cache directly. */ ret = idmap_cache_find_sid2uid(psid, puid, &expired); @@ -1414,7 +1518,7 @@ bool sid_to_uid(const struct dom_sid *psid, uid_t *puid) /* Not in cache. Ask winbindd. */ if (!winbind_sid_to_uid(puid, psid)) { DEBUG(5, ("winbind failed to find a uid for sid %s\n", - sid_string_dbg(psid))); + dom_sid_str_buf(psid, &buf))); /* winbind failed. do legacy */ return legacy_sid_to_uid(psid, puid); } @@ -1423,7 +1527,8 @@ bool sid_to_uid(const struct dom_sid *psid, uid_t *puid) /* TODO: Here would be the place to allocate both a gid and a uid for * the SID in question */ - DEBUG(10,("sid %s -> uid %u\n", sid_string_dbg(psid), + DEBUG(10,("sid %s -> uid %u\n", + dom_sid_str_buf(psid, &buf), (unsigned int)*puid )); return true; @@ -1432,14 +1537,14 @@ bool sid_to_uid(const struct dom_sid *psid, uid_t *puid) /***************************************************************** *THE CANONICAL* convert SID to gid function. Group mapping is used for gids that maps to Wellknown SIDs -*****************************************************************/ +*****************************************************************/ bool sid_to_gid(const struct dom_sid *psid, gid_t *pgid) { bool expired = true; bool ret; - uint32 rid; - uid_t uid; + uint32_t rid; + struct dom_sid_buf buf; /* Optimize for the Unix Groups Domain * as the conversion is straightforward */ @@ -1448,11 +1553,18 @@ bool sid_to_gid(const struct dom_sid *psid, gid_t *pgid) *pgid = gid; /* return here, don't cache */ - DEBUG(10,("sid %s -> gid %u\n", sid_string_dbg(psid), + DEBUG(10,("sid %s -> gid %u\n", + dom_sid_str_buf(psid, &buf), (unsigned int)*pgid )); return true; } + if (sid_check_is_in_unix_users(psid)) { + DBG_DEBUG("SID %s is a user, failing\n", + dom_sid_str_buf(psid, &buf)); + return false; + } + /* Check the winbindd cache directly. */ ret = idmap_cache_find_sid2gid(psid, pgid, &expired); @@ -1472,13 +1584,14 @@ bool sid_to_gid(const struct dom_sid *psid, gid_t *pgid) if ( !winbind_sid_to_gid(pgid, psid) ) { DEBUG(10,("winbind failed to find a gid for sid %s\n", - sid_string_dbg(psid))); + dom_sid_str_buf(psid, &buf))); /* winbind failed. do legacy */ return legacy_sid_to_gid(psid, pgid); } } - DEBUG(10,("sid %s -> gid %u\n", sid_string_dbg(psid), + DEBUG(10,("sid %s -> gid %u\n", + dom_sid_str_buf(psid, &buf), (unsigned int)*pgid )); return true; @@ -1526,7 +1639,7 @@ NTSTATUS get_primary_group_sid(TALLOC_CTX *mem_ctx, if (!pwd) { pwd = Get_Pwnam_alloc(mem_ctx, username); if (!pwd) { - DEBUG(0, ("Failed to find a Unix account for %s", + DEBUG(0, ("Failed to find a Unix account for %s\n", username)); TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_SUCH_USER; @@ -1562,8 +1675,13 @@ NTSTATUS get_primary_group_sid(TALLOC_CTX *mem_ctx, } } else { /* Try group mapping */ + struct unixid id; + + id.id = pwd->pw_gid; + id.type = ID_TYPE_GID; + ZERO_STRUCTP(group_sid); - if (pdb_gid_to_sid(pwd->pw_gid, group_sid)) { + if (pdb_id_to_sid(&id, group_sid)) { need_lookup_sid = true; } } @@ -1574,9 +1692,11 @@ NTSTATUS get_primary_group_sid(TALLOC_CTX *mem_ctx, if (need_lookup_sid) { enum lsa_SidType type = SID_NAME_UNKNOWN; bool lookup_ret; + struct dom_sid_buf buf; DEBUG(10, ("do lookup_sid(%s) for group of user %s\n", - sid_string_dbg(group_sid), username)); + dom_sid_str_buf(group_sid, &buf), + username)); /* Now check that it's actually a domain group and * not something else */ @@ -1589,7 +1709,8 @@ NTSTATUS get_primary_group_sid(TALLOC_CTX *mem_ctx, DEBUG(3, ("Primary group %s for user %s is" " a %s and not a domain group\n", - sid_string_dbg(group_sid), username, + dom_sid_str_buf(group_sid, &buf), + username, sid_type_lookup(type))); }