X-Git-Url: http://git.samba.org/samba.git/?p=kai%2Fsamba.git;a=blobdiff_plain;f=source3%2Fwinbindd%2Fidmap_ldap.c;h=0c58bf4236cefad1db0f877f585a187641cb25ff;hp=c7bc80f98a813c286e77c55397b7925f4e1a6a48;hb=ff32391808322029a8d6caa9fdf1a4d253d9b1ff;hpb=5f77570bb6ba0a8e8233e5f8081acac48829e772 diff --git a/source3/winbindd/idmap_ldap.c b/source3/winbindd/idmap_ldap.c index c7bc80f98a8..0c58bf4236c 100644 --- a/source3/winbindd/idmap_ldap.c +++ b/source3/winbindd/idmap_ldap.c @@ -7,6 +7,7 @@ Copyright (C) Jim McDonough 2003 Copyright (C) Gerald Carter 2003 Copyright (C) Simo Sorce 2003-2007 + Copyright (C) Michael Adam 2010 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 @@ -25,6 +26,9 @@ #include "includes.h" #include "winbindd.h" #include "secrets.h" +#include "idmap.h" +#include "idmap_rw.h" +#include "../libcli/security/security.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_IDMAP @@ -33,23 +37,25 @@ #include #include "smbldap.h" +#include "passdb/pdb_ldap_schema.h" -static char *idmap_fetch_secret(const char *backend, bool alloc, +static char *idmap_fetch_secret(const char *backend, const char *domain, const char *identity) { char *tmp, *ret; int r; - if (alloc) { - r = asprintf(&tmp, "IDMAP_ALLOC_%s", backend); - } else { - r = asprintf(&tmp, "IDMAP_%s_%s", backend, domain); - } + r = asprintf(&tmp, "IDMAP_%s_%s", backend, domain); if (r < 0) return NULL; - strupper_m(tmp); /* make sure the key is case insensitive */ + /* make sure the key is case insensitive */ + if (!strupper_m(tmp)) { + SAFE_FREE(tmp); + return NULL; + } + ret = secrets_fetch_generic(tmp, identity); SAFE_FREE(tmp); @@ -57,20 +63,13 @@ static char *idmap_fetch_secret(const char *backend, bool alloc, return ret; } -struct idmap_ldap_alloc_context { - struct smbldap_state *smbldap_state; - char *url; - char *suffix; - char *user_dn; -}; - struct idmap_ldap_context { struct smbldap_state *smbldap_state; char *url; char *suffix; char *user_dn; bool anon; - struct idmap_ldap_alloc_context *alloc; + struct idmap_rw_ops *rw_ops; }; #define CHECK_ALLOC_DONE(mem) do { \ @@ -105,12 +104,13 @@ static NTSTATUS get_credentials( TALLOC_CTX *mem_ctx, if ( tmp ) { if (!dom) { - /* only the alloc backend can pass in a NULL dom */ - secret = idmap_fetch_secret("ldap", True, - NULL, tmp); + DEBUG(0, ("get_credentials: Invalid domain 'NULL' " + "encountered for user DN %s\n", + tmp)); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; } else { - secret = idmap_fetch_secret("ldap", False, - dom->name, tmp); + secret = idmap_fetch_secret("ldap", dom->name, tmp); } if (!secret) { @@ -163,11 +163,7 @@ static NTSTATUS verify_idpool(struct idmap_domain *dom) ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context); - if (!ctx->alloc) { - return NT_STATUS_UNSUCCESSFUL; - } - - mem_ctx = talloc_new(ctx->alloc); + mem_ctx = talloc_new(ctx); if (mem_ctx == NULL) { DEBUG(0, ("Out of memory!\n")); return NT_STATUS_NO_MEMORY; @@ -179,8 +175,8 @@ static NTSTATUS verify_idpool(struct idmap_domain *dom) attr_list = get_attr_list(mem_ctx, idpool_attr_list); CHECK_ALLOC_DONE(attr_list); - rc = smbldap_search(ctx->alloc->smbldap_state, - ctx->alloc->suffix, + rc = smbldap_search(ctx->smbldap_state, + ctx->suffix, LDAP_SCOPE_SUBTREE, filter, attr_list, @@ -193,14 +189,13 @@ static NTSTATUS verify_idpool(struct idmap_domain *dom) return NT_STATUS_UNSUCCESSFUL; } - count = ldap_count_entries(ctx->alloc->smbldap_state->ldap_struct, - result); + count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result); ldap_msgfree(result); if ( count > 1 ) { DEBUG(0,("Multiple entries returned from %s (base == %s)\n", - filter, ctx->alloc->suffix)); + filter, ctx->suffix)); ret = NT_STATUS_UNSUCCESSFUL; goto done; } @@ -223,8 +218,8 @@ static NTSTATUS verify_idpool(struct idmap_domain *dom) LDAP_ATTR_GIDNUMBER), gid_str); if (mods) { - rc = smbldap_modify(ctx->alloc->smbldap_state, - ctx->alloc->suffix, + rc = smbldap_modify(ctx->smbldap_state, + ctx->suffix, mods); ldap_mods_free(mods, True); } else { @@ -239,106 +234,12 @@ done: return ret; } -/***************************************************************************** - Initialise idmap database. -*****************************************************************************/ - -static int idmap_ldap_alloc_close_destructor(struct idmap_ldap_alloc_context *ctx) -{ - smbldap_free_struct(&ctx->smbldap_state); - DEBUG(5,("The connection to the LDAP server was closed\n")); - /* maybe free the results here --metze */ - return 0; -} - -static NTSTATUS idmap_ldap_alloc_init(struct idmap_domain *dom, - const char *params) -{ - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - const char *tmp; - struct idmap_ldap_context *ctx; - - /* Only do init if we are online */ - if (idmap_is_offline()) { - return NT_STATUS_FILE_IS_OFFLINE; - } - - ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context); - - ctx->alloc = talloc_zero(ctx, struct idmap_ldap_alloc_context); - CHECK_ALLOC_DONE(ctx->alloc); - - if (params && *params) { - /* assume location is the only parameter */ - ctx->alloc->url = talloc_strdup(ctx->alloc, params); - } else { - tmp = lp_parm_const_string(-1, "idmap alloc config", - "ldap_url", NULL); - - if ( ! tmp) { - DEBUG(1, ("ERROR: missing idmap ldap url\n")); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; - } - - ctx->alloc->url = talloc_strdup(ctx->alloc, tmp); - } - CHECK_ALLOC_DONE(ctx->alloc->url); - - trim_char(ctx->alloc->url, '\"', '\"'); - - tmp = lp_parm_const_string(-1, "idmap alloc config", - "ldap_base_dn", NULL); - if ( ! tmp || ! *tmp) { - tmp = lp_ldap_idmap_suffix(); - if ( ! tmp) { - DEBUG(1, ("ERROR: missing idmap ldap suffix\n")); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; - } - } - - ctx->alloc->suffix = talloc_strdup(ctx->alloc, tmp); - CHECK_ALLOC_DONE(ctx->alloc->suffix); - - ret = smbldap_init(ctx->alloc, winbind_event_context(), - ctx->alloc->url, - &ctx->alloc->smbldap_state); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", - ctx->alloc->url)); - goto done; - } - - talloc_set_destructor(ctx->alloc, idmap_ldap_alloc_close_destructor); - - ret = get_credentials(ctx->alloc, - ctx->alloc->smbldap_state, - "idmap alloc config", NULL, - &ctx->alloc->user_dn); - if ( !NT_STATUS_IS_OK(ret) ) { - DEBUG(1,("idmap_ldap_alloc_init: Failed to get connection " - "credentials (%s)\n", nt_errstr(ret))); - goto done; - } - - /* see if the idmap suffix and sub entries exists */ - - ret = verify_idpool(dom); - - done: - if ( !NT_STATUS_IS_OK( ret ) ) - TALLOC_FREE(ctx->alloc); - - return ret; -} - /******************************** Allocate a new uid or gid ********************************/ -static NTSTATUS idmap_ldap_allocate_id(struct idmap_domain *dom, - struct unixid *xid) +static NTSTATUS idmap_ldap_allocate_id_internal(struct idmap_domain *dom, + struct unixid *xid) { TALLOC_CTX *mem_ctx; NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; @@ -362,11 +263,7 @@ static NTSTATUS idmap_ldap_allocate_id(struct idmap_domain *dom, ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context); - if (!ctx->alloc) { - return NT_STATUS_UNSUCCESSFUL; - } - - mem_ctx = talloc_new(ctx->alloc); + mem_ctx = talloc_new(ctx); if (!mem_ctx) { DEBUG(0, ("Out of memory!\n")); return NT_STATUS_NO_MEMORY; @@ -398,37 +295,35 @@ static NTSTATUS idmap_ldap_allocate_id(struct idmap_domain *dom, DEBUG(10, ("Search of the id pool (filter: %s)\n", filter)); - rc = smbldap_search(ctx->alloc->smbldap_state, - ctx->alloc->suffix, - LDAP_SCOPE_SUBTREE, filter, - attr_list, 0, &result); + rc = smbldap_search(ctx->smbldap_state, + ctx->suffix, + LDAP_SCOPE_SUBTREE, filter, + attr_list, 0, &result); if (rc != LDAP_SUCCESS) { DEBUG(0,("%s object not found\n", LDAP_OBJ_IDPOOL)); goto done; } - talloc_autofree_ldapmsg(mem_ctx, result); + smbldap_talloc_autofree_ldapmsg(mem_ctx, result); - count = ldap_count_entries(ctx->alloc->smbldap_state->ldap_struct, - result); + count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result); if (count != 1) { DEBUG(0,("Single %s object not found\n", LDAP_OBJ_IDPOOL)); goto done; } - entry = ldap_first_entry(ctx->alloc->smbldap_state->ldap_struct, - result); + entry = ldap_first_entry(ctx->smbldap_state->ldap_struct, result); dn = smbldap_talloc_dn(mem_ctx, - ctx->alloc->smbldap_state->ldap_struct, + ctx->smbldap_state->ldap_struct, entry); if ( ! dn) { goto done; } id_str = smbldap_talloc_single_attribute( - ctx->alloc->smbldap_state->ldap_struct, + ctx->smbldap_state->ldap_struct, entry, type, mem_ctx); if (id_str == NULL) { DEBUG(0,("%s attribute not found\n", type)); @@ -480,7 +375,7 @@ static NTSTATUS idmap_ldap_allocate_id(struct idmap_domain *dom, DEBUG(10, ("Try to atomically increment the id (%s -> %s)\n", id_str, new_id_str)); - rc = smbldap_modify(ctx->alloc->smbldap_state, dn, mods); + rc = smbldap_modify(ctx->smbldap_state, dn, mods); ldap_mods_free(mods, True); @@ -497,6 +392,31 @@ done: return ret; } +/** + * Allocate a new unix-ID. + * For now this is for the default idmap domain only. + * Should be extended later on. + */ +static NTSTATUS idmap_ldap_allocate_id(struct idmap_domain *dom, + struct unixid *id) +{ + NTSTATUS ret; + + if (!strequal(dom->name, "*")) { + DEBUG(3, ("idmap_ldap_allocate_id: " + "Refusing allocation of a new unixid for domain'%s'. " + "This is only supported for the default " + "domain \"*\".\n", + dom->name)); + return NT_STATUS_NOT_IMPLEMENTED; + } + + ret = idmap_ldap_allocate_id_internal(dom, id); + + return ret; +} + + /********************************************************************** IDMAP MAPPING LDAP BACKEND **********************************************************************/ @@ -514,8 +434,10 @@ static int idmap_ldap_close_destructor(struct idmap_ldap_context *ctx) Initialise idmap database. ********************************/ -static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom, - const char *params) +static NTSTATUS idmap_ldap_set_mapping(struct idmap_domain *dom, + const struct id_map *map); + +static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom) { NTSTATUS ret; struct idmap_ldap_context *ctx = NULL; @@ -527,44 +449,34 @@ static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom, return NT_STATUS_FILE_IS_OFFLINE; } - ctx = TALLOC_ZERO_P(dom, struct idmap_ldap_context); + ctx = talloc_zero(dom, struct idmap_ldap_context); if ( ! ctx) { DEBUG(0, ("Out of memory!\n")); return NT_STATUS_NO_MEMORY; } - if (strequal(dom->name, "*")) { - /* more specific configuration can go here */ - } else { - config_option = talloc_asprintf(ctx, "idmap config %s", dom->name); - if ( ! config_option) { - DEBUG(0, ("Out of memory!\n")); - ret = NT_STATUS_NO_MEMORY; - goto done; - } + config_option = talloc_asprintf(ctx, "idmap config %s", dom->name); + if (!config_option) { + DEBUG(0, ("Out of memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; } - if (params != NULL) { - /* assume location is the only parameter */ - ctx->url = talloc_strdup(ctx, params); - } else { - tmp = lp_parm_const_string(-1, config_option, "ldap_url", NULL); + tmp = lp_parm_const_string(-1, config_option, "ldap_url", NULL); - if ( ! tmp) { - DEBUG(1, ("ERROR: missing idmap ldap url\n")); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; - } - - ctx->url = talloc_strdup(ctx, tmp); + if ( ! tmp) { + DEBUG(1, ("ERROR: missing idmap ldap url\n")); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; } - CHECK_ALLOC_DONE(ctx->url); + + ctx->url = talloc_strdup(ctx, tmp); trim_char(ctx->url, '\"', '\"'); tmp = lp_parm_const_string(-1, config_option, "ldap_base_dn", NULL); if ( ! tmp || ! *tmp) { - tmp = lp_ldap_idmap_suffix(); + tmp = lp_ldap_idmap_suffix(talloc_tos()); if ( ! tmp) { DEBUG(1, ("ERROR: missing idmap ldap suffix\n")); ret = NT_STATUS_UNSUCCESSFUL; @@ -575,8 +487,16 @@ static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom, ctx->suffix = talloc_strdup(ctx, tmp); CHECK_ALLOC_DONE(ctx->suffix); + ctx->rw_ops = talloc_zero(ctx, struct idmap_rw_ops); + CHECK_ALLOC_DONE(ctx->rw_ops); + + ctx->rw_ops->get_new_id = idmap_ldap_allocate_id_internal; + ctx->rw_ops->set_mapping = idmap_ldap_set_mapping; + + /* get_credentials deals with setting up creds */ + ret = smbldap_init(ctx, winbind_event_context(), ctx->url, - &ctx->smbldap_state); + false, NULL, NULL, &ctx->smbldap_state); if (!NT_STATUS_IS_OK(ret)) { DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", ctx->url)); goto done; @@ -590,17 +510,18 @@ static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom, goto done; } - /* set the destructor on the context, so that resource are properly - freed if the contexts is released */ - + /* + * Set the destructor on the context, so that resources are + * properly freed when the context is released. + */ talloc_set_destructor(ctx, idmap_ldap_close_destructor); dom->private_data = ctx; - ret = idmap_ldap_alloc_init(dom, params); + ret = verify_idpool(dom); if (!NT_STATUS_IS_OK(ret)) { - DEBUG(1, ("idmap_ldap_db_init: Failed to initialize alloc " - "subsystem: %s\n", nt_errstr(ret))); + DEBUG(1, ("idmap_ldap_db_init: failed to verify ID pool (%s)\n", + nt_errstr(ret))); goto done; } @@ -725,6 +646,23 @@ done: return ret; } +/** + * Create a new mapping for an unmapped SID, also allocating a new ID. + * If possible, this should be run inside a transaction to make the + * action atomic. + */ +static NTSTATUS idmap_ldap_new_mapping(struct idmap_domain *dom, struct id_map *map) +{ + NTSTATUS ret; + struct idmap_ldap_context *ctx; + + ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context); + + ret = idmap_rw_new_mapping(dom, ctx->rw_ops, map); + + return ret; +} + /* max number of ids requested per batch query */ #define IDMAP_LDAP_MAX_IDS 30 @@ -975,7 +913,7 @@ static struct id_map *find_map_by_sid(struct id_map **maps, struct dom_sid *sid) if (maps[i] == NULL) { /* end of the run */ return NULL; } - if (sid_equal(maps[i]->sid, sid)) { + if (dom_sid_equal(maps[i]->sid, sid)) { return maps[i]; } } @@ -1183,14 +1121,23 @@ again: goto again; } - ret = NT_STATUS_OK; - - /* mark all unknwon/expired ones as unmapped */ + /* + * try to create new mappings for unmapped sids + */ for (i = 0; ids[i]; i++) { - if (ids[i]->status != ID_MAPPED) + if (ids[i]->status != ID_MAPPED) { ids[i]->status = ID_UNMAPPED; + if (ids[i]->sid != NULL) { + ret = idmap_ldap_new_mapping(dom, ids[i]); + if (!NT_STATUS_IS_OK(ret)) { + goto done; + } + } + } } + ret = NT_STATUS_OK; + done: talloc_free(memctx); return ret; @@ -1200,28 +1147,12 @@ done: Close the idmap ldap instance **********************************/ -static NTSTATUS idmap_ldap_close(struct idmap_domain *dom) -{ - struct idmap_ldap_context *ctx; - - if (dom->private_data) { - ctx = talloc_get_type(dom->private_data, - struct idmap_ldap_context); - - talloc_free(ctx); - dom->private_data = NULL; - } - - return NT_STATUS_OK; -} - static struct idmap_methods idmap_ldap_methods = { .init = idmap_ldap_db_init, .unixids_to_sids = idmap_ldap_unixids_to_sids, .sids_to_unixids = idmap_ldap_sids_to_unixids, - .allocate_id = idmap_ldap_get_new_id, - .close_fn = idmap_ldap_close + .allocate_id = idmap_ldap_allocate_id, }; NTSTATUS idmap_ldap_init(void);