X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fpassdb%2Flookup_sid.c;h=23566b657d1d1ae675a1831aceaf283e963b2871;hb=64421129b672d0ce55c5aa235e5038dd2ea1b32b;hp=10ff36d51b8bef04849609011de1df59bb103fc4;hpb=be1dfff02d562e42a7847bd02fed8538630d3f41;p=samba.git diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c index 10ff36d51b8..23566b657d1 100644 --- a/source3/passdb/lookup_sid.c +++ b/source3/passdb/lookup_sid.c @@ -4,22 +4,27 @@ Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) Gerald (Jerry) Carter 2003 Copyright (C) Volker Lendecke 2005 - + 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 3 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, see . */ #include "includes.h" +#include "../librpc/gen_ndr/ndr_security.h" +#include "secrets.h" +#include "memcache.h" +#include "idmap_cache.h" +#include "../libcli/security/security.h" /***************************************************************** Dissect a user-provided name into domain, name, sid and type. @@ -32,14 +37,14 @@ bool lookup_name(TALLOC_CTX *mem_ctx, const char *full_name, int flags, const char **ret_domain, const char **ret_name, - DOM_SID *ret_sid, enum lsa_SidType *ret_type) + struct dom_sid *ret_sid, enum lsa_SidType *ret_type) { char *p; const char *tmp; const char *domain = NULL; const char *name = NULL; uint32 rid; - DOM_SID sid; + struct dom_sid sid; enum lsa_SidType type; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); @@ -65,7 +70,7 @@ bool lookup_name(TALLOC_CTX *mem_ctx, return false; } - DEBUG(10,("lookup_name: %s => %s (domain), %s (name)\n", + DEBUG(10,("lookup_name: %s => domain=[%s], name=[%s]\n", full_name, domain, name)); DEBUG(10, ("lookup_name: flags = 0x0%x\n", flags)); @@ -75,8 +80,7 @@ bool lookup_name(TALLOC_CTX *mem_ctx, /* It's our own domain, lookup the name in passdb */ if (lookup_global_sam_name(name, flags, &rid, &type)) { - sid_copy(&sid, get_global_sam_sid()); - sid_append_rid(&sid, rid); + sid_compose(&sid, get_global_sam_sid(), rid); goto ok; } TALLOC_FREE(tmp_ctx); @@ -86,10 +90,17 @@ bool lookup_name(TALLOC_CTX *mem_ctx, if ((flags & LOOKUP_NAME_BUILTIN) && strequal(domain, builtin_domain_name())) { + if (strlen(name) == 0) { + /* Swap domain and name */ + tmp = name; name = domain; domain = tmp; + sid_copy(&sid, &global_sid_Builtin); + type = SID_NAME_DOMAIN; + goto ok; + } + /* Explicit request for a name in BUILTIN */ if (lookup_builtin_name(name, &rid)) { - sid_copy(&sid, &global_sid_Builtin); - sid_append_rid(&sid, rid); + sid_compose(&sid, &global_sid_Builtin, rid); type = SID_NAME_ALIAS; goto ok; } @@ -106,7 +117,8 @@ bool lookup_name(TALLOC_CTX *mem_ctx, goto ok; } - if (!(flags & LOOKUP_NAME_EXPLICIT) && strequal(domain, unix_users_domain_name())) { + if (((flags & LOOKUP_NAME_NO_NSS) == 0) + && strequal(domain, unix_users_domain_name())) { if (lookup_unix_user_name(name, &sid)) { type = SID_NAME_USER; goto ok; @@ -115,7 +127,8 @@ bool lookup_name(TALLOC_CTX *mem_ctx, return false; } - if (!(flags & LOOKUP_NAME_EXPLICIT) && strequal(domain, unix_groups_domain_name())) { + if (((flags & LOOKUP_NAME_NO_NSS) == 0) + && strequal(domain, unix_groups_domain_name())) { if (lookup_unix_group_name(name, &sid)) { type = SID_NAME_DOM_GRP; goto ok; @@ -205,8 +218,7 @@ bool lookup_name(TALLOC_CTX *mem_ctx, lookup_builtin_name(name, &rid)) { domain = talloc_strdup(tmp_ctx, builtin_domain_name()); - sid_copy(&sid, &global_sid_Builtin); - sid_append_rid(&sid, rid); + sid_compose(&sid, &global_sid_Builtin, rid); type = SID_NAME_ALIAS; goto ok; } @@ -220,8 +232,7 @@ bool lookup_name(TALLOC_CTX *mem_ctx, lookup_global_sam_name(name, flags, &rid, &type)) { domain = talloc_strdup(tmp_ctx, get_global_sam_name()); - sid_copy(&sid, get_global_sam_sid()); - sid_append_rid(&sid, rid); + sid_compose(&sid, get_global_sam_sid(), rid); goto ok; } @@ -247,10 +258,9 @@ bool lookup_name(TALLOC_CTX *mem_ctx, * that (yet), but give it a chance. */ if (IS_DC && winbind_lookup_name("", name, &sid, &type)) { - DOM_SID dom_sid; - uint32 tmp_rid; + struct dom_sid dom_sid; enum lsa_SidType domain_type; - + if (type == SID_NAME_DOMAIN) { /* Swap name and type */ tmp = name; name = domain; domain = tmp; @@ -262,7 +272,7 @@ bool lookup_name(TALLOC_CTX *mem_ctx, * domain it figured out itself. Maybe fix that later... */ sid_copy(&dom_sid, &sid); - sid_split_rid(&dom_sid, &tmp_rid); + sid_split_rid(&dom_sid, NULL); if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL, &domain_type) || @@ -280,13 +290,15 @@ 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_EXPLICIT) && lookup_unix_user_name(name, &sid)) { + if (((flags & LOOKUP_NAME_NO_NSS) == 0) + && lookup_unix_user_name(name, &sid)) { domain = talloc_strdup(tmp_ctx, unix_users_domain_name()); type = SID_NAME_USER; goto ok; } - if (!(flags & LOOKUP_NAME_EXPLICIT) && lookup_unix_group_name(name, &sid)) { + if (((flags & LOOKUP_NAME_NO_NSS) == 0) + && lookup_unix_group_name(name, &sid)) { domain = talloc_strdup(tmp_ctx, unix_groups_domain_name()); type = SID_NAME_DOM_GRP; goto ok; @@ -349,7 +361,7 @@ bool lookup_name(TALLOC_CTX *mem_ctx, bool lookup_name_smbconf(TALLOC_CTX *mem_ctx, const char *full_name, int flags, const char **ret_domain, const char **ret_name, - DOM_SID *ret_sid, enum lsa_SidType *ret_type) + struct dom_sid *ret_sid, enum lsa_SidType *ret_type) { char *qualified_name; const char *p; @@ -390,7 +402,7 @@ bool lookup_name_smbconf(TALLOC_CTX *mem_ctx, ret_sid, ret_type)) { return true; } - + /* Finally try with "Unix Users" or "Unix Group" */ qualified_name = talloc_asprintf(mem_ctx, "%s\\%s", flags & LOOKUP_NAME_GROUP ? @@ -407,7 +419,7 @@ bool lookup_name_smbconf(TALLOC_CTX *mem_ctx, } static bool wb_lookup_rids(TALLOC_CTX *mem_ctx, - const DOM_SID *domain_sid, + const struct dom_sid *domain_sid, int num_rids, uint32 *rids, const char **domain_name, const char **names, enum lsa_SidType *types) @@ -457,7 +469,7 @@ static bool wb_lookup_rids(TALLOC_CTX *mem_ctx, return true; } -static bool lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid, +static bool lookup_rids(TALLOC_CTX *mem_ctx, const struct dom_sid *domain_sid, int num_rids, uint32_t *rids, const char **domain_name, const char ***names, enum lsa_SidType **types) @@ -468,12 +480,15 @@ static bool lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid, sid_string_dbg(domain_sid))); if (num_rids) { - *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids); + *names = TALLOC_ZERO_ARRAY(mem_ctx, const char *, num_rids); *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids); if ((*names == NULL) || (*types == NULL)) { return false; } + + for (i = 0; i < num_rids; i++) + (*types)[i] = SID_NAME_UNKNOWN; } else { *names = NULL; *types = NULL; @@ -528,9 +543,8 @@ static bool lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid, if (sid_check_is_wellknown_domain(domain_sid, NULL)) { for (i=0; isid)) { + if (dom_sid_equal(sid, &domains[i]->sid)) { *name = talloc_strdup(mem_ctx, domains[i]->name); return true; @@ -678,7 +692,7 @@ static bool lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx, * Level 6: Like 4 */ -static bool check_dom_sid_to_level(const DOM_SID *sid, int level) +static bool check_dom_sid_to_level(const struct dom_sid *sid, int level) { int ret = false; @@ -713,13 +727,11 @@ static bool check_dom_sid_to_level(const DOM_SID *sid, int level) * This attempts to be as efficient as possible: It collects all SIDs * belonging to a domain and hands them in bulk to the appropriate lookup * function. In particular pdb_lookup_rids with ldapsam_trusted benefits - * *hugely* from this. Winbind is going to be extended with a lookup_rids - * interface as well, so on a DC we can do a bulk lsa_lookuprids to the - * appropriate DC. + * *hugely* from this. */ NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids, - const DOM_SID **sids, int level, + const struct dom_sid **sids, int level, struct lsa_dom_info **ret_domains, struct lsa_name_info **ret_names) { @@ -767,8 +779,8 @@ NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids, */ for (i=0; inum_idxs; j++) { int idx = dom->idxs[j]; name_infos[idx].type = types[j]; @@ -938,7 +950,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 DOM_SID *sid, +bool lookup_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid, const char **ret_domain, const char **ret_name, enum lsa_SidType *ret_type) { @@ -1002,7 +1014,7 @@ bool lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid, Find a SID given a uid. *****************************************************************/ -static bool fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid) +static bool fetch_sid_from_uid_cache(struct dom_sid *psid, uid_t uid) { DATA_BLOB cache_value; @@ -1014,7 +1026,7 @@ static bool fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid) memcpy(psid, cache_value.data, MIN(sizeof(*psid), cache_value.length)); SMB_ASSERT(cache_value.length >= offsetof(struct dom_sid, id_auth)); - SMB_ASSERT(cache_value.length == ndr_size_dom_sid(psid, NULL, 0)); + SMB_ASSERT(cache_value.length == ndr_size_dom_sid(psid, 0)); return true; } @@ -1023,12 +1035,12 @@ static bool fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid) Find a uid given a SID. *****************************************************************/ -static bool fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid ) +static bool fetch_uid_from_cache( uid_t *puid, const struct dom_sid *psid ) { DATA_BLOB cache_value; if (!memcache_lookup(NULL, SID_UID_CACHE, - data_blob_const(psid, ndr_size_dom_sid(psid, NULL, 0)), + data_blob_const(psid, ndr_size_dom_sid(psid, 0)), &cache_value)) { return false; } @@ -1043,21 +1055,21 @@ static bool fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid ) Store uid to SID mapping in cache. *****************************************************************/ -void store_uid_sid_cache(const DOM_SID *psid, uid_t uid) +void store_uid_sid_cache(const struct dom_sid *psid, uid_t uid) { memcache_add(NULL, SID_UID_CACHE, - data_blob_const(psid, ndr_size_dom_sid(psid, NULL, 0)), + data_blob_const(psid, ndr_size_dom_sid(psid, 0)), data_blob_const(&uid, sizeof(uid))); memcache_add(NULL, UID_SID_CACHE, data_blob_const(&uid, sizeof(uid)), - data_blob_const(psid, ndr_size_dom_sid(psid, NULL, 0))); + data_blob_const(psid, ndr_size_dom_sid(psid, 0))); } /***************************************************************** Find a SID given a gid. *****************************************************************/ -static bool fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid) +static bool fetch_sid_from_gid_cache(struct dom_sid *psid, gid_t gid) { DATA_BLOB cache_value; @@ -1069,7 +1081,7 @@ static bool fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid) memcpy(psid, cache_value.data, MIN(sizeof(*psid), cache_value.length)); SMB_ASSERT(cache_value.length >= offsetof(struct dom_sid, id_auth)); - SMB_ASSERT(cache_value.length == ndr_size_dom_sid(psid, NULL, 0)); + SMB_ASSERT(cache_value.length == ndr_size_dom_sid(psid, 0)); return true; } @@ -1078,12 +1090,12 @@ static bool fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid) Find a gid given a SID. *****************************************************************/ -static bool fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid) +static bool fetch_gid_from_cache(gid_t *pgid, const struct dom_sid *psid) { DATA_BLOB cache_value; - if (!memcache_lookup(NULL, SID_UID_CACHE, - data_blob_const(psid, ndr_size_dom_sid(psid, NULL, 0)), + if (!memcache_lookup(NULL, SID_GID_CACHE, + data_blob_const(psid, ndr_size_dom_sid(psid, 0)), &cache_value)) { return false; } @@ -1098,35 +1110,32 @@ static bool fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid) Store gid to SID mapping in cache. *****************************************************************/ -void store_gid_sid_cache(const DOM_SID *psid, gid_t gid) +void store_gid_sid_cache(const struct dom_sid *psid, gid_t gid) { memcache_add(NULL, SID_GID_CACHE, - data_blob_const(psid, ndr_size_dom_sid(psid, NULL, 0)), + data_blob_const(psid, ndr_size_dom_sid(psid, 0)), data_blob_const(&gid, sizeof(gid))); memcache_add(NULL, GID_SID_CACHE, data_blob_const(&gid, sizeof(gid)), - data_blob_const(psid, ndr_size_dom_sid(psid, NULL, 0))); + data_blob_const(psid, ndr_size_dom_sid(psid, 0))); } /***************************************************************** *THE LEGACY* convert uid_t to SID function. *****************************************************************/ -static void legacy_uid_to_sid(DOM_SID *psid, uid_t uid) +static void legacy_uid_to_sid(struct dom_sid *psid, uid_t uid) { - uint32 rid; bool ret; ZERO_STRUCTP(psid); become_root(); - ret = pdb_uid_to_rid(uid, &rid); + ret = pdb_uid_to_sid(uid, psid); unbecome_root(); if (ret) { /* This is a mapped user */ - sid_copy(psid, get_global_sam_sid()); - sid_append_rid(psid, rid); goto done; } @@ -1146,7 +1155,7 @@ static void legacy_uid_to_sid(DOM_SID *psid, uid_t uid) *THE LEGACY* convert gid_t to SID function. *****************************************************************/ -static void legacy_gid_to_sid(DOM_SID *psid, gid_t gid) +static void legacy_gid_to_sid(struct dom_sid *psid, gid_t gid) { bool ret; @@ -1160,7 +1169,7 @@ static void legacy_gid_to_sid(DOM_SID *psid, gid_t gid) /* This is a mapped group */ goto done; } - + /* This is an unmapped group */ gid_to_unix_groups_sid(gid, psid); @@ -1177,12 +1186,11 @@ static void legacy_gid_to_sid(DOM_SID *psid, gid_t gid) *THE LEGACY* convert SID to uid function. *****************************************************************/ -static bool legacy_sid_to_uid(const DOM_SID *psid, uid_t *puid) +static bool legacy_sid_to_uid(const struct dom_sid *psid, uid_t *puid) { enum lsa_SidType type; - uint32 rid; - if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) { + if (sid_check_is_in_our_domain(psid)) { union unid_t id; bool ret; @@ -1221,9 +1229,8 @@ done: Group mapping is used for gids that maps to Wellknown SIDs *****************************************************************/ -static bool legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid) +static bool legacy_sid_to_gid(const struct dom_sid *psid, gid_t *pgid) { - uint32 rid; GROUP_MAP map; union unid_t id; enum lsa_SidType type; @@ -1245,7 +1252,7 @@ static bool legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid) return false; } - if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) { + if (sid_check_is_in_our_domain(psid)) { bool ret; become_root(); @@ -1263,14 +1270,14 @@ static bool legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid) *pgid = id.gid; goto done; } - + /* This was ours, but it was not mapped. Fail */ } 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 )); @@ -1284,7 +1291,7 @@ static bool legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid) *THE CANONICAL* convert uid_t to SID function. *****************************************************************/ -void uid_to_sid(DOM_SID *psid, uid_t uid) +void uid_to_sid(struct dom_sid *psid, uid_t uid) { bool expired = true; bool ret; @@ -1309,15 +1316,18 @@ void uid_to_sid(DOM_SID *psid, uid_t uid) /* 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. - */ + * 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)); + legacy_uid_to_sid(psid, uid); return; } @@ -1334,7 +1344,7 @@ void uid_to_sid(DOM_SID *psid, uid_t uid) *THE CANONICAL* convert gid_t to SID function. *****************************************************************/ -void gid_to_sid(DOM_SID *psid, gid_t gid) +void gid_to_sid(struct dom_sid *psid, gid_t gid) { bool expired = true; bool ret; @@ -1359,15 +1369,18 @@ void gid_to_sid(DOM_SID *psid, gid_t gid) /* 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. - */ + * 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; } @@ -1384,7 +1397,7 @@ void gid_to_sid(DOM_SID *psid, gid_t gid) *THE CANONICAL* convert SID to uid function. *****************************************************************/ -bool sid_to_uid(const DOM_SID *psid, uid_t *puid) +bool sid_to_uid(const struct dom_sid *psid, uid_t *puid) { bool expired = true; bool ret; @@ -1424,13 +1437,10 @@ bool sid_to_uid(const DOM_SID *psid, uid_t *puid) if (!ret || expired) { /* Not in cache. Ask winbindd. */ if (!winbind_sid_to_uid(puid, psid)) { - if (!winbind_ping()) { - return legacy_sid_to_uid(psid, puid); - } - DEBUG(5, ("winbind failed to find a uid for sid %s\n", sid_string_dbg(psid))); - return false; + /* winbind failed. do legacy */ + return legacy_sid_to_uid(psid, puid); } } @@ -1449,7 +1459,7 @@ bool sid_to_uid(const DOM_SID *psid, uid_t *puid) Group mapping is used for gids that maps to Wellknown SIDs *****************************************************************/ -bool sid_to_gid(const DOM_SID *psid, gid_t *pgid) +bool sid_to_gid(const struct dom_sid *psid, gid_t *pgid) { bool expired = true; bool ret; @@ -1491,13 +1501,11 @@ bool sid_to_gid(const DOM_SID *psid, gid_t *pgid) * (Idmap will check it is a valid SID and of the right type) */ if ( !winbind_sid_to_gid(pgid, psid) ) { - if (!winbind_ping()) { - return legacy_sid_to_gid(psid, pgid); - } DEBUG(10,("winbind failed to find a gid for sid %s\n", sid_string_dbg(psid))); - return false; + /* winbind failed. do legacy */ + return legacy_sid_to_gid(psid, pgid); } } @@ -1507,3 +1515,193 @@ bool sid_to_gid(const DOM_SID *psid, gid_t *pgid) store_gid_sid_cache(psid, *pgid); return true; } + +/** + * @brief This function gets the primary group SID mapping the primary + * GID of the user as obtained by an actual getpwnam() call. + * This is necessary to avoid issues with arbitrary group SIDs + * stored in passdb. We try as hard as we can to get the SID + * corresponding to the GID, including trying group mapping. + * If nothing else works, we will force "Domain Users" as the + * primary group. + * This is needed because we must always be able to lookup the + * primary group SID, so we cannot settle for an arbitrary SID. + * + * This call can be expensive. Use with moderation. + * If you have a "samu" struct around use pdb_get_group_sid() + * instead as it does properly cache results. + * + * @param mem_ctx[in] The memory context iused to allocate the result. + * @param username[in] The user's name + * @param _pwd[in|out] If available, pass in user's passwd struct. + * It will contain a tallocated passwd if NULL was + * passed in. + * @param _group_sid[out] The user's Primary Group SID + * + * @return NTSTATUS error code. + */ +NTSTATUS get_primary_group_sid(TALLOC_CTX *mem_ctx, + const char *username, + struct passwd **_pwd, + struct dom_sid **_group_sid) +{ + TALLOC_CTX *tmp_ctx; + bool need_lookup_sid = false; + struct dom_sid *group_sid; + struct passwd *pwd = *_pwd; + + tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) { + return NT_STATUS_NO_MEMORY; + } + + if (!pwd) { + pwd = Get_Pwnam_alloc(mem_ctx, username); + if (!pwd) { + DEBUG(0, ("Failed to find a Unix account for %s", + username)); + TALLOC_FREE(tmp_ctx); + return NT_STATUS_NO_SUCH_USER; + } + } + + group_sid = talloc_zero(mem_ctx, struct dom_sid); + if (!group_sid) { + TALLOC_FREE(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + + gid_to_sid(group_sid, pwd->pw_gid); + if (!is_null_sid(group_sid)) { + struct dom_sid domain_sid; + uint32_t rid; + + /* We need a sid within our domain */ + sid_copy(&domain_sid, group_sid); + sid_split_rid(&domain_sid, &rid); + if (dom_sid_equal(&domain_sid, get_global_sam_sid())) { + /* + * As shortcut for the expensive lookup_sid call + * compare the domain sid part + */ + switch (rid) { + case DOMAIN_RID_ADMINS: + case DOMAIN_RID_USERS: + goto done; + default: + need_lookup_sid = true; + break; + } + } else { + /* Try group mapping */ + ZERO_STRUCTP(group_sid); + if (pdb_gid_to_sid(pwd->pw_gid, group_sid)) { + need_lookup_sid = true; + } + } + } + + /* We must verify that this is a valid SID that resolves to a + * group of the correct type */ + if (need_lookup_sid) { + enum lsa_SidType type = SID_NAME_UNKNOWN; + bool lookup_ret; + + DEBUG(10, ("do lookup_sid(%s) for group of user %s\n", + sid_string_dbg(group_sid), username)); + + /* Now check that it's actually a domain group and + * not something else */ + lookup_ret = lookup_sid(tmp_ctx, group_sid, + NULL, NULL, &type); + + if (lookup_ret && (type == SID_NAME_DOM_GRP)) { + goto done; + } + + DEBUG(3, ("Primary group %s for user %s is" + " a %s and not a domain group\n", + sid_string_dbg(group_sid), username, + sid_type_lookup(type))); + } + + /* Everything else, failed. + * Just set it to the 'Domain Users' RID of 513 which will + always resolve to a name */ + DEBUG(3, ("Forcing Primary Group to 'Domain Users' for %s\n", + username)); + + sid_compose(group_sid, get_global_sam_sid(), DOMAIN_RID_USERS); + +done: + *_pwd = talloc_move(mem_ctx, &pwd); + *_group_sid = talloc_move(mem_ctx, &group_sid); + TALLOC_FREE(tmp_ctx); + return NT_STATUS_OK; +} + +bool delete_uid_cache(uid_t puid) +{ + DATA_BLOB uid = data_blob_const(&puid, sizeof(puid)); + DATA_BLOB sid; + + if (!memcache_lookup(NULL, UID_SID_CACHE, uid, &sid)) { + DEBUG(3, ("UID %d is not memcached!\n", (int)puid)); + return false; + } + DEBUG(3, ("Delete mapping UID %d <-> %s from memcache\n", (int)puid, + sid_string_dbg((struct dom_sid*)sid.data))); + memcache_delete(NULL, SID_UID_CACHE, sid); + memcache_delete(NULL, UID_SID_CACHE, uid); + return true; +} + +bool delete_gid_cache(gid_t pgid) +{ + DATA_BLOB gid = data_blob_const(&pgid, sizeof(pgid)); + DATA_BLOB sid; + if (!memcache_lookup(NULL, GID_SID_CACHE, gid, &sid)) { + DEBUG(3, ("GID %d is not memcached!\n", (int)pgid)); + return false; + } + DEBUG(3, ("Delete mapping GID %d <-> %s from memcache\n", (int)pgid, + sid_string_dbg((struct dom_sid*)sid.data))); + memcache_delete(NULL, SID_GID_CACHE, sid); + memcache_delete(NULL, GID_SID_CACHE, gid); + return true; +} + +bool delete_sid_cache(const struct dom_sid* psid) +{ + DATA_BLOB sid = data_blob_const(psid, ndr_size_dom_sid(psid, 0)); + DATA_BLOB id; + if (memcache_lookup(NULL, SID_GID_CACHE, sid, &id)) { + DEBUG(3, ("Delete mapping %s <-> GID %d from memcache\n", + sid_string_dbg(psid), *(int*)id.data)); + memcache_delete(NULL, SID_GID_CACHE, sid); + memcache_delete(NULL, GID_SID_CACHE, id); + } else if (memcache_lookup(NULL, SID_UID_CACHE, sid, &id)) { + DEBUG(3, ("Delete mapping %s <-> UID %d from memcache\n", + sid_string_dbg(psid), *(int*)id.data)); + memcache_delete(NULL, SID_UID_CACHE, sid); + memcache_delete(NULL, UID_SID_CACHE, id); + } else { + DEBUG(3, ("SID %s is not memcached!\n", sid_string_dbg(psid))); + return false; + } + return true; +} + +void flush_gid_cache(void) +{ + DEBUG(3, ("Flush GID <-> SID memcache\n")); + memcache_flush(NULL, SID_GID_CACHE); + memcache_flush(NULL, GID_SID_CACHE); +} + +void flush_uid_cache(void) +{ + DEBUG(3, ("Flush UID <-> SID memcache\n")); + memcache_flush(NULL, SID_UID_CACHE); + memcache_flush(NULL, UID_SID_CACHE); +}