#include "ads.h"
#include "nss_info.h"
#include "../libcli/security/dom_sid.h"
+#include "libsmb/samlogon_cache.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
}
/*********************************************************************
- Hash a Relative ID to a 20 bit number
+ Hash a Relative ID to a 19 bit number
********************************************************************/
static uint32_t hash_rid(uint32_t rid)
{
- /* 20 bits for the rid which allows us to support
- the first 100K users/groups in a domain */
+ /*
+ * 19 bits for the rid which allows us to support
+ * the first 50K users/groups in a domain
+ *
+ */
return (rid & 0x0007FFFF);
}
{
uint32_t return_id = 0;
- /* shift the hash_domain 19 bits to the left and OR with the
- hash_rid */
+ /*
+ * shift the hash_domain 19 bits to the left and OR with the
+ * hash_rid
+ *
+ * This will generate a 31 bit number out of
+ * 12 bit domain and 19 bit rid.
+ */
return_id = ((h_domain<<19) | h_rid);
/*********************************************************************
********************************************************************/
-static NTSTATUS be_init(struct idmap_domain *dom)
+static NTSTATUS idmap_hash_initialize(struct idmap_domain *dom)
{
struct sid_hash_table *hashed_domains;
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
struct winbindd_tdc_domain *dom_list = NULL;
size_t num_domains = 0;
- int i;
+ size_t i;
- /* If the domain SID hash table has been initialized, assume
- that we completed this function previously */
+ DBG_ERR("The idmap_hash module is deprecated and should not be used. "
+ "Please migrate to a different plugin. This module will be "
+ "removed in a future version of Samba\n");
- if (dom->private_data != NULL) {
- nt_status = NT_STATUS_OK;
- goto done;
+ if (!strequal(dom->name, "*")) {
+ DBG_ERR("Error: idmap_hash configured for domain '%s'. "
+ "But the hash module can only be used for the default "
+ "idmap configuration.\n", dom->name);
+ return NT_STATUS_INVALID_PARAMETER;
}
if (!wcache_tdc_fetch_list(&dom_list, &num_domains)) {
/* create the hash table of domain SIDs */
for (i=0; i<num_domains; i++) {
+ struct dom_sid_buf buf;
uint32_t hash;
if (is_null_sid(&dom_list[i].sid))
continue;
+
+ /*
+ * Check if the domain from the list is not already configured
+ * to use another idmap backend. Not checking this makes the
+ * idmap_hash module map IDs for *all* domains implicitly. This
+ * is quite dangerous in setups that use multiple idmap
+ * configurations.
+ */
+
+ if (domain_has_idmap_config(dom_list[i].domain_name)) {
+ continue;
+ }
+
if ((hash = hash_domain_sid(&dom_list[i].sid)) == 0)
continue;
- DEBUG(5,("hash:be_init() Adding %s (%s) -> %d\n",
+ DBG_INFO("Adding %s (%s) -> %d\n",
dom_list[i].domain_name,
- sid_string_dbg(&dom_list[i].sid),
- hash));
+ dom_sid_str_buf(&dom_list[i].sid, &buf),
+ hash);
hashed_domains[hash].sid = talloc(hashed_domains, struct dom_sid);
sid_copy(hashed_domains[hash].sid, &dom_list[i].sid);
/*********************************************************************
********************************************************************/
+static NTSTATUS idmap_hash_id_to_sid(struct sid_hash_table *hashed_domains,
+ struct idmap_domain *dom,
+ struct id_map *id)
+{
+ uint32_t h_domain, h_rid;
+
+ id->status = ID_UNMAPPED;
+
+ separate_hashes(id->xid.id, &h_domain, &h_rid);
+
+ /*
+ * If the domain hash doesn't find a SID in the table,
+ * skip it
+ */
+ if (hashed_domains[h_domain].sid == NULL) {
+ return NT_STATUS_NONE_MAPPED;
+ }
+
+ sid_compose(id->sid, hashed_domains[h_domain].sid, h_rid);
+ id->status = ID_MAPPED;
+
+ return NT_STATUS_OK;
+}
+
static NTSTATUS unixids_to_sids(struct idmap_domain *dom,
struct id_map **ids)
{
struct sid_hash_table *hashed_domains = talloc_get_type_abort(
dom->private_data, struct sid_hash_table);
- NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
int i;
+ int num_tomap = 0;
+ int num_mapped = 0;
- /* initialize the status to avoid suprise */
+ /* initialize the status to avoid surprise */
for (i = 0; ids[i]; i++) {
ids[i]->status = ID_UNKNOWN;
- }
-
- nt_status = be_init(dom);
- BAIL_ON_NTSTATUS_ERROR(nt_status);
-
- if (!ids) {
- nt_status = NT_STATUS_INVALID_PARAMETER;
- BAIL_ON_NTSTATUS_ERROR(nt_status);
+ num_tomap++;
}
for (i=0; ids[i]; i++) {
- uint32_t h_domain, h_rid;
+ NTSTATUS ret;
- ids[i]->status = ID_UNMAPPED;
+ ret = idmap_hash_id_to_sid(hashed_domains, dom, ids[i]);
- separate_hashes(ids[i]->xid.id, &h_domain, &h_rid);
-
- /* Make sure the caller allocated memor for us */
-
- if (!ids[i]->sid) {
- nt_status = NT_STATUS_INVALID_PARAMETER;
- BAIL_ON_NTSTATUS_ERROR(nt_status);
+ if ((!NT_STATUS_IS_OK(ret)) &&
+ (!NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED))) {
+ /* some fatal error occurred, log it */
+ DBG_NOTICE("Unexpected error resolving an ID "
+ "(%d): %s\n", ids[i]->xid.id,
+ nt_errstr(ret));
+ return ret;
}
- /* If the domain hash doesn't find a SID in the table,
- skip it */
-
- if (!hashed_domains[h_domain].sid)
- continue;
+ if (NT_STATUS_IS_OK(ret) && ids[i]->status == ID_MAPPED) {
+ num_mapped++;
+ }
+ }
- sid_compose(ids[i]->sid, hashed_domains[h_domain].sid, h_rid);
- ids[i]->status = ID_MAPPED;
+ if (num_tomap == num_mapped) {
+ return NT_STATUS_OK;
+ } else if (num_mapped == 0) {
+ return NT_STATUS_NONE_MAPPED;
}
-done:
- return nt_status;
+ return STATUS_SOME_UNMAPPED;
}
/*********************************************************************
********************************************************************/
-static NTSTATUS sids_to_unixids(struct idmap_domain *dom,
- struct id_map **ids)
+static NTSTATUS idmap_hash_sid_to_id(struct sid_hash_table *hashed_domains,
+ struct idmap_domain *dom,
+ struct id_map *id)
{
- NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
- int i;
-
- /* initialize the status to avoid suprise */
- for (i = 0; ids[i]; i++) {
- ids[i]->status = ID_UNKNOWN;
- }
+ struct dom_sid sid;
+ uint32_t rid;
+ uint32_t h_domain, h_rid;
- nt_status = be_init(dom);
- BAIL_ON_NTSTATUS_ERROR(nt_status);
+ id->status = ID_UNMAPPED;
- if (!ids) {
- nt_status = NT_STATUS_INVALID_PARAMETER;
- BAIL_ON_NTSTATUS_ERROR(nt_status);
- }
-
- for (i=0; ids[i]; i++) {
- struct dom_sid sid;
- uint32_t rid;
- uint32_t h_domain, h_rid;
+ sid_copy(&sid, id->sid);
+ sid_split_rid(&sid, &rid);
- ids[i]->status = ID_UNMAPPED;
+ h_domain = hash_domain_sid(&sid);
+ h_rid = hash_rid(rid);
- sid_copy(&sid, ids[i]->sid);
- sid_split_rid(&sid, &rid);
+ /* Check that both hashes are non-zero*/
+ if (h_domain == 0) {
+ return NT_STATUS_NONE_MAPPED;
+ }
+ if (h_rid == 0) {
+ return NT_STATUS_NONE_MAPPED;
+ }
- h_domain = hash_domain_sid(&sid);
- h_rid = hash_rid(rid);
+ /*
+ * If the domain hash already exists find a SID in the table,
+ * just return the mapping.
+ */
+ if (hashed_domains[h_domain].sid != NULL) {
+ goto return_mapping;
+ }
- /* Check that both hashes are non-zero*/
+ /*
+ * If the caller already did a lookup sid and made sure the
+ * domain sid is valid, we can allocate a new range.
+ *
+ * Currently the winbindd parent already does a lookup sids
+ * first, but hopefully changes in future. If the
+ * caller knows the domain sid, ID_TYPE_BOTH should be
+ * passed instead of ID_TYPE_NOT_SPECIFIED.
+ */
+ if (id->xid.type == ID_TYPE_NOT_SPECIFIED) {
+ /*
+ * We keep the legacy behavior and
+ * just return the mapping, but
+ * the reverse mapping would not
+ * still not work.
+ *
+ * Maybe we should return NT_STATUS_NONE_MAPPED,
+ * but for now we keep what we already have.
+ */
+ goto return_mapping;
+ }
- if (h_domain && h_rid) {
- ids[i]->xid.id = combine_hashes(h_domain, h_rid);
- ids[i]->status = ID_MAPPED;
- }
+ /*
+ * Check of last resort: A domain is valid if a user from that
+ * domain has recently logged in. The samlogon_cache these
+ * days also stores the domain sid.
+ *
+ * We used to check the list of trusted domains we received
+ * from "our" dc, but this is not reliable enough.
+ */
+ if (!netsamlogon_cache_have(&sid)) {
+ /*
+ * We keep the legacy behavior and
+ * just return the mapping, but
+ * the reverse mapping would not
+ * still not work.
+ *
+ * Maybe we should return NT_STATUS_NONE_MAPPED,
+ * but for now we keep what we already have.
+ */
+ goto return_mapping;
}
-done:
- return nt_status;
-}
+ /*
+ * Now we're sure the domain exist, remember
+ * the domain in order to return reverse mappings
+ * in future.
+ */
+ hashed_domains[h_domain].sid = dom_sid_dup(hashed_domains, &sid);
+ if (hashed_domains[h_domain].sid == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
-/*********************************************************************
- ********************************************************************/
+return_mapping:
+ id->xid.id = combine_hashes(h_domain, h_rid);
+ id->status = ID_MAPPED;
-static NTSTATUS nss_hash_init(struct nss_domain_entry *e )
-{
- return be_init(NULL);
+ return NT_STATUS_OK;
}
-/**********************************************************************
- *********************************************************************/
-
-static NTSTATUS nss_hash_get_info(struct nss_domain_entry *e,
- const struct dom_sid *sid,
- TALLOC_CTX *ctx,
- const char **homedir,
- const char **shell,
- const char **gecos,
- gid_t *p_gid )
+static NTSTATUS sids_to_unixids(struct idmap_domain *dom,
+ struct id_map **ids)
{
- NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
-
- nt_status = nss_hash_init(e);
- BAIL_ON_NTSTATUS_ERROR(nt_status);
+ struct sid_hash_table *hashed_domains = talloc_get_type_abort(
+ dom->private_data, struct sid_hash_table);
+ int i;
+ int num_tomap = 0;
+ int num_mapped = 0;
- if (!homedir || !shell || !gecos) {
- nt_status = NT_STATUS_INVALID_PARAMETER;
- BAIL_ON_NTSTATUS_ERROR(nt_status);
+ /* initialize the status to avoid surprise */
+ for (i = 0; ids[i]; i++) {
+ ids[i]->status = ID_UNKNOWN;
+ num_tomap++;
}
- *homedir = talloc_strdup(ctx, lp_template_homedir());
- BAIL_ON_PTR_NT_ERROR(*homedir, nt_status);
+ for (i=0; ids[i]; i++) {
+ NTSTATUS ret;
+
+ ret = idmap_hash_sid_to_id(hashed_domains, dom, ids[i]);
+
+ if ((!NT_STATUS_IS_OK(ret)) &&
+ (!NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED))) {
+ struct dom_sid_buf buf;
+ /* some fatal error occurred, log it */
+ DBG_NOTICE("Unexpected error resolving a SID "
+ "(%s): %s\n",
+ dom_sid_str_buf(ids[i]->sid, &buf),
+ nt_errstr(ret));
+ return ret;
+ }
- *shell = talloc_strdup(ctx, lp_template_shell());
- BAIL_ON_PTR_NT_ERROR(*shell, nt_status);
+ if (NT_STATUS_IS_OK(ret) && ids[i]->status == ID_MAPPED) {
+ num_mapped++;
+ }
+ }
- *gecos = NULL;
+ if (num_tomap == num_mapped) {
+ return NT_STATUS_OK;
+ } else if (num_mapped == 0) {
+ return NT_STATUS_NONE_MAPPED;
+ }
- /* Initialize the gid so that the upper layer fills
- in the proper Windows primary group */
+ return STATUS_SOME_UNMAPPED;
+}
- if (*p_gid) {
- *p_gid = (gid_t)-1;
- }
+/*********************************************************************
+ ********************************************************************/
-done:
- return nt_status;
+static NTSTATUS nss_hash_init(struct nss_domain_entry *e )
+{
+ return NT_STATUS_OK;
}
/**********************************************************************
Dispatch Tables for IDMap and NssInfo Methods
********************************************************************/
-static struct idmap_methods hash_idmap_methods = {
- .init = be_init,
+static const struct idmap_methods hash_idmap_methods = {
+ .init = idmap_hash_initialize,
.unixids_to_sids = unixids_to_sids,
.sids_to_unixids = sids_to_unixids,
};
-static struct nss_info_methods hash_nss_methods = {
+static const struct nss_info_methods hash_nss_methods = {
.init = nss_hash_init,
- .get_nss_info = nss_hash_get_info,
.map_to_alias = nss_hash_map_to_alias,
.map_from_alias = nss_hash_map_from_alias,
.close_fn = nss_hash_close
state.
**********************************************************************/
-NTSTATUS samba_init_module(void)
+static_decl_idmap;
+NTSTATUS idmap_hash_init(TALLOC_CTX *ctx)
{
static NTSTATUS idmap_status = NT_STATUS_UNSUCCESSFUL;
static NTSTATUS nss_status = NT_STATUS_UNSUCCESSFUL;