-/*
+/*
Unix SMB/CIFS implementation.
uid/user handling
Copyright (C) Andrew Tridgell 1992-1998
#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.
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,
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);
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)) {
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) &&
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;
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;
}
/* 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))
{
goto ok;
}
- /* 6. Builtin aliases */
+ /* 6. Builtin aliases */
if ((flags & LOOKUP_NAME_BUILTIN) &&
lookup_builtin_name(name, &rid))
/* 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;
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,
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(),
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)
{
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);
}
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
static bool check_dom_sid_to_level(const struct dom_sid *sid, int level)
{
+ struct dom_sid_buf buf;
int ret = false;
switch(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;
}
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;
}
/* 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.
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; j<dom->num_idxs; j++) {
/*****************************************************************
*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,
{
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"));
goto done;
}
- if ((ret_name != NULL) &&
+ if ((ret_name != NULL) &&
!(*ret_name = talloc_strdup(mem_ctx, name->name))) {
goto done;
}
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 <michael.steffens@hp.com>,
- modified to use linked lists by jra.
-*****************************************************************/
-
-
-/*****************************************************************
- *THE LEGACY* convert uid_t to SID function.
-*****************************************************************/
-
-static void legacy_uid_to_sid(struct dom_sid *psid, uid_t uid)
-{
- bool ret;
-
- ZERO_STRUCTP(psid);
-
- become_root();
- ret = pdb_uid_to_sid(uid, psid);
- unbecome_root();
-
- if (ret) {
- /* This is a mapped user */
- goto done;
- }
-
- /* 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;
-}
-
-/*****************************************************************
- *THE LEGACY* convert gid_t to SID function.
-*****************************************************************/
-
-static void legacy_gid_to_sid(struct dom_sid *psid, gid_t gid)
-{
- 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;
- }
-
- /* 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 id function.
-*****************************************************************/
+*****************************************************************/
static bool legacy_sid_to_unixid(const struct dom_sid *psid, struct unixid *id)
{
unbecome_root();
if (!ret) {
+ struct dom_sid_buf buf;
DEBUG(10,("LEGACY: mapping failed for sid %s\n",
- sid_string_dbg(psid)));
+ dom_sid_str_buf(psid, &buf)));
return false;
}
return false;
}
-/*****************************************************************
- *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);
- if (ret && !expired && is_null_sid(psid)) {
+ *psid = (struct dom_sid) {0};
+
+ 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_unixids(const struct dom_sid *sids, uint32_t num_sids,
{
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;
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;
&sids[i], &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 = ID_TYPE_GID;
ids[i].id = rid;
+ bitmap_set(found, i);
continue;
}
if (idmap_cache_find_sid2unixid(&sids[i], &ids[i], &expired)
&& !expired)
{
+ bitmap_set(found, i);
continue;
}
ids[i].type = ID_TYPE_NOT_SPECIFIED;
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<num_not_cached; i++) {
+ for (i=0; i<wbc_ids_size; i++) {
wbc_ids[i].type = WBC_ID_TYPE_NOT_SPECIFIED;
+ wbc_ids[i].id.gid = (uint32_t)-1;
}
- err = wbcSidsToUnixIds(wbc_sids, num_not_cached, wbc_ids);
+ err = wbcSidsToUnixIds(wbc_sids, wbc_ids_size, wbc_ids);
if (!WBC_ERROR_IS_OK(err)) {
DEBUG(10, ("wbcSidsToUnixIds returned %s\n",
wbcErrorString(err)));
}
+ /*
+ * Second time through the SID array, replace
+ * the ids[] entries that wbcSidsToUnixIds() was able to
+ * map.
+ *
+ * Use bitmap_set() to mark an ids[] array entry as
+ * being mapped.
+ */
+
num_not_cached = 0;
for (i=0; i<num_sids; i++) {
- if (ids[i].type == ID_TYPE_NOT_SPECIFIED) {
- switch (wbc_ids[num_not_cached].type) {
- case WBC_ID_TYPE_UID:
- ids[i].type = ID_TYPE_UID;
- ids[i].id = wbc_ids[num_not_cached].id.uid;
- break;
- case WBC_ID_TYPE_GID:
- ids[i].type = ID_TYPE_GID;
- ids[i].id = wbc_ids[num_not_cached].id.gid;
- break;
- default:
- /* The types match, and wbcUnixId -> id is a union anyway */
- ids[i].type = (enum id_type)wbc_ids[num_not_cached].type;
- ids[i].id = wbc_ids[num_not_cached].id.gid;
- break;
- }
- num_not_cached += 1;
+ if (bitmap_query(found, i)) {
+ continue;
+ }
+
+ SMB_ASSERT(num_not_cached < wbc_ids_size);
+
+ switch (wbc_ids[num_not_cached].type) {
+ case WBC_ID_TYPE_UID:
+ ids[i].type = ID_TYPE_UID;
+ ids[i].id = wbc_ids[num_not_cached].id.uid;
+ bitmap_set(found, i);
+ break;
+ case WBC_ID_TYPE_GID:
+ ids[i].type = ID_TYPE_GID;
+ ids[i].id = wbc_ids[num_not_cached].id.gid;
+ bitmap_set(found, i);
+ break;
+ case WBC_ID_TYPE_BOTH:
+ ids[i].type = ID_TYPE_BOTH;
+ ids[i].id = wbc_ids[num_not_cached].id.uid;
+ bitmap_set(found, i);
+ break;
+ case WBC_ID_TYPE_NOT_SPECIFIED:
+ /*
+ * wbcSidsToUnixIds() wasn't able to map this
+ * so we still need to check legacy_sid_to_XXX()
+ * below. Don't mark the bitmap entry
+ * as being found so the final loop knows
+ * to try and map this entry.
+ */
+ ids[i].type = ID_TYPE_NOT_SPECIFIED;
+ ids[i].id = (uint32_t)-1;
+ break;
+ default:
+ /*
+ * A successful return from wbcSidsToUnixIds()
+ * cannot return anything other than the values
+ * checked for above. Ensure this is so.
+ */
+ smb_panic(__location__);
+ break;
}
+ num_not_cached += 1;
}
+ /*
+ * Third and final time through the SID array,
+ * try legacy_sid_to_gid()/legacy_sid_to_uid()
+ * for entries we haven't already been able to
+ * map.
+ *
+ * Use bitmap_set() to mark an ids[] array entry as
+ * being mapped.
+ */
+
for (i=0; i<num_sids; i++) {
- if (ids[i].type != ID_TYPE_NOT_SPECIFIED) {
+ if (bitmap_query(found, i)) {
continue;
}
if (legacy_sid_to_gid(&sids[i], &ids[i].id)) {
ids[i].type = ID_TYPE_GID;
+ bitmap_set(found, i);
continue;
}
if (legacy_sid_to_uid(&sids[i], &ids[i].id)) {
ids[i].type = ID_TYPE_UID;
+ bitmap_set(found, i);
continue;
}
}
done:
+ /*
+ * Pass through the return array for consistency.
+ * Any ids[].id mapped to (uint32_t)-1 must be returned
+ * as ID_TYPE_NOT_SPECIFIED.
+ */
for (i=0; i<num_sids; i++) {
switch(ids[i].type) {
- case WBC_ID_TYPE_GID:
- case WBC_ID_TYPE_UID:
- case WBC_ID_TYPE_BOTH:
- if (ids[i].id == -1) {
+ case ID_TYPE_GID:
+ case ID_TYPE_UID:
+ case ID_TYPE_BOTH:
+ if (ids[i].id == (uint32_t)-1) {
ids[i].type = ID_TYPE_NOT_SPECIFIED;
}
break;
- case WBC_ID_TYPE_NOT_SPECIFIED:
+ case ID_TYPE_NOT_SPECIFIED:
+ break;
+ case ID_TYPE_WB_REQUIRE_TYPE:
+ /*
+ * these are internal between winbindd
+ * parent and child.
+ */
+ smb_panic(__location__);
break;
}
}
/*****************************************************************
*THE CANONICAL* convert SID to uid function.
-*****************************************************************/
+*****************************************************************/
bool sid_to_uid(const struct dom_sid *psid, uid_t *puid)
{
bool expired = true;
bool ret;
- uint32 rid;
+ uint32_t rid;
+ struct dom_sid_buf buf;
/* Optimize for the Unix Users Domain
* as the conversion is straightforward */
*puid = uid;
/* return here, don't cache */
- DEBUG(10,("sid %s -> 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);
/* 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);
}
/* 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;
/*****************************************************************
*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;
+ uint32_t rid;
+ struct dom_sid_buf buf;
/* Optimize for the Unix Groups Domain
* as the conversion is straightforward */
*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);
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;
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;
}
} 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;
}
}
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 */
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)));
}