diff options
author | Volker Lendecke <vl@samba.org> | 2008-07-13 12:07:40 +0200 |
---|---|---|
committer | Volker Lendecke <vl@samba.org> | 2008-08-12 11:28:29 +0200 |
commit | 340ab6a256802a22c11b7f707748397249075b65 (patch) | |
tree | 20d297829eb3e27c6c80ad537712627ae845a4ef /source3 | |
parent | 8d4bd2d960ebf11bc85891210c6f72a371e08417 (diff) | |
download | samba-340ab6a256802a22c11b7f707748397249075b65.tar.gz samba-340ab6a256802a22c11b7f707748397249075b65.tar.bz2 samba-340ab6a256802a22c11b7f707748397249075b65.zip |
idmap rewrite
(This used to be commit 30a180f2fce8cf6a3e5548f6bba453272ba70b33)
Diffstat (limited to 'source3')
-rw-r--r-- | source3/include/idmap.h | 8 | ||||
-rw-r--r-- | source3/param/loadparm.c | 18 | ||||
-rw-r--r-- | source3/winbindd/idmap.c | 1151 | ||||
-rw-r--r-- | source3/winbindd/idmap_ad.c | 20 | ||||
-rw-r--r-- | source3/winbindd/idmap_cache.c | 38 | ||||
-rw-r--r-- | source3/winbindd/idmap_ldap.c | 55 | ||||
-rw-r--r-- | source3/winbindd/idmap_nss.c | 12 | ||||
-rw-r--r-- | source3/winbindd/idmap_passdb.c | 11 | ||||
-rw-r--r-- | source3/winbindd/idmap_rid.c | 20 | ||||
-rw-r--r-- | source3/winbindd/idmap_tdb.c | 45 | ||||
-rw-r--r-- | source3/winbindd/idmap_tdb2.c | 28 | ||||
-rw-r--r-- | source3/winbindd/idmap_util.c | 162 | ||||
-rw-r--r-- | source3/winbindd/winbindd.c | 6 | ||||
-rw-r--r-- | source3/winbindd/winbindd.h | 7 | ||||
-rw-r--r-- | source3/winbindd/winbindd_dual.c | 2 | ||||
-rw-r--r-- | source3/winbindd/winbindd_group.c | 6 | ||||
-rw-r--r-- | source3/winbindd/winbindd_idmap.c | 64 | ||||
-rw-r--r-- | source3/winbindd/winbindd_sid.c | 14 | ||||
-rw-r--r-- | source3/winbindd/winbindd_user.c | 6 | ||||
-rw-r--r-- | source3/winbindd/winbindd_util.c | 34 |
20 files changed, 656 insertions, 1051 deletions
diff --git a/source3/include/idmap.h b/source3/include/idmap.h index e059ab2337..95c3e4c0c2 100644 --- a/source3/include/idmap.h +++ b/source3/include/idmap.h @@ -36,19 +36,15 @@ struct idmap_domain { const char *name; - bool default_domain; - bool readonly; - void *private_data; struct idmap_methods *methods; - bool initialized; - const char *params; + void *private_data; }; /* Filled out by IDMAP backends */ struct idmap_methods { /* Called when backend is first loaded */ - NTSTATUS (*init)(struct idmap_domain *dom); + NTSTATUS (*init)(struct idmap_domain *dom, const char *params); /* Map an array of uids/gids to SIDs. The caller specifies the uid/gid and type. Gets back the SID. */ diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 7882b37c2c..7fd7bb2bf4 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -194,8 +194,7 @@ struct global { bool bWinbindOfflineLogon; bool bWinbindNormalizeNames; bool bWinbindRpcOnly; - char **szIdmapDomains; - char **szIdmapBackend; /* deprecated */ + char *szIdmapBackend; char *szIdmapAllocBackend; char *szAddShareCommand; char *szChangeShareCommand; @@ -4256,17 +4255,8 @@ static struct parm_struct parm_table[] = { .flags = FLAG_ADVANCED, }, { - .label = "idmap domains", - .type = P_LIST, - .p_class = P_GLOBAL, - .ptr = &Globals.szIdmapDomains, - .special = NULL, - .enum_list = NULL, - .flags = FLAG_ADVANCED, - }, - { .label = "idmap backend", - .type = P_LIST, + .type = P_STRING, .p_class = P_GLOBAL, .ptr = &Globals.szIdmapBackend, .special = NULL, @@ -4825,6 +4815,7 @@ static void init_globals(bool first_time_only) Globals.bKernelOplocks = True; Globals.bAllowTrustedDomains = True; + string_set(&Globals.szIdmapBackend, "tdb"); string_set(&Globals.szTemplateShell, "/bin/false"); string_set(&Globals.szTemplateHomedir, "/home/%D/%U"); @@ -5091,8 +5082,7 @@ FN_GLOBAL_BOOL(lp_winbind_offline_logon, &Globals.bWinbindOfflineLogon) FN_GLOBAL_BOOL(lp_winbind_normalize_names, &Globals.bWinbindNormalizeNames) FN_GLOBAL_BOOL(lp_winbind_rpc_only, &Globals.bWinbindRpcOnly) -FN_GLOBAL_LIST(lp_idmap_domains, &Globals.szIdmapDomains) -FN_GLOBAL_LIST(lp_idmap_backend, &Globals.szIdmapBackend) /* deprecated */ +FN_GLOBAL_CONST_STRING(lp_idmap_backend, &Globals.szIdmapBackend) /* deprecated */ FN_GLOBAL_STRING(lp_idmap_alloc_backend, &Globals.szIdmapAllocBackend) FN_GLOBAL_INTEGER(lp_idmap_cache_time, &Globals.iIdmapCacheTime) FN_GLOBAL_INTEGER(lp_idmap_negative_cache_time, &Globals.iIdmapNegativeCacheTime) diff --git a/source3/winbindd/idmap.c b/source3/winbindd/idmap.c index 2c18164f8c..bace38876b 100644 --- a/source3/winbindd/idmap.c +++ b/source3/winbindd/idmap.c @@ -40,41 +40,25 @@ struct idmap_alloc_backend { struct idmap_alloc_backend *prev, *next; }; -struct idmap_cache_ctx; - struct idmap_alloc_context { - const char *params; struct idmap_alloc_methods *methods; - bool initialized; }; -static TALLOC_CTX *idmap_ctx = NULL; -static struct idmap_cache_ctx *idmap_cache; - +/* + * Lists for the module initializations + */ static struct idmap_backend *backends = NULL; +static struct idmap_alloc_backend *alloc_backends = NULL; + + +static struct idmap_domain *default_idmap_domain; +static struct idmap_domain *passdb_idmap_domain; + static struct idmap_domain **idmap_domains = NULL; static int num_domains = 0; -static int pdb_dom_num = -1; -static int def_dom_num = -1; -static struct idmap_alloc_backend *alloc_backends = NULL; static struct idmap_alloc_context *idmap_alloc_ctx = NULL; -#define IDMAP_CHECK_RET(ret) do { \ - if ( ! NT_STATUS_IS_OK(ret)) { \ - DEBUG(2, ("ERROR: NTSTATUS = 0x%08x\n", NT_STATUS_V(ret))); \ - goto done; \ - } } while(0) -#define IDMAP_REPORT_RET(ret) do { \ - if ( ! NT_STATUS_IS_OK(ret)) { \ - DEBUG(2, ("ERROR: NTSTATUS = 0x%08x\n", NT_STATUS_V(ret))); \ - } } while(0) -#define IDMAP_CHECK_ALLOC(mem) do { \ - if (!mem) { \ - DEBUG(0, ("Out of memory!\n")); ret = NT_STATUS_NO_MEMORY; \ - goto done; \ - } } while(0) - static struct idmap_methods *get_methods(struct idmap_backend *be, const char *name) { @@ -110,6 +94,11 @@ bool idmap_is_offline(void) get_global_winbindd_state_offline() ); } +bool idmap_is_online(void) +{ + return !idmap_is_offline(); +} + /********************************************************************** Allow a module to register itself as a method. **********************************************************************/ @@ -117,13 +106,8 @@ bool idmap_is_offline(void) NTSTATUS smb_register_idmap(int version, const char *name, struct idmap_methods *methods) { - struct idmap_methods *test; struct idmap_backend *entry; - if (!idmap_ctx) { - return NT_STATUS_INTERNAL_DB_ERROR; - } - if ((version != SMB_IDMAP_INTERFACE_VERSION)) { DEBUG(0, ("Failed to register idmap module.\n" "The module was compiled against " @@ -140,19 +124,20 @@ NTSTATUS smb_register_idmap(int version, const char *name, return NT_STATUS_INVALID_PARAMETER; } - test = get_methods(backends, name); - if (test) { - DEBUG(0,("Idmap module %s already registered!\n", name)); - return NT_STATUS_OBJECT_NAME_COLLISION; + for (entry = backends; entry != NULL; entry = entry->next) { + if (strequal(entry->name, name)) { + DEBUG(0,("Idmap module %s already registered!\n", name)); + return NT_STATUS_OBJECT_NAME_COLLISION; + } } - entry = talloc(idmap_ctx, struct idmap_backend); + entry = talloc(NULL, struct idmap_backend); if ( ! entry) { DEBUG(0,("Out of memory!\n")); TALLOC_FREE(entry); return NT_STATUS_NO_MEMORY; } - entry->name = talloc_strdup(idmap_ctx, name); + entry->name = talloc_strdup(entry, name); if ( ! entry->name) { DEBUG(0,("Out of memory!\n")); TALLOC_FREE(entry); @@ -175,10 +160,6 @@ NTSTATUS smb_register_idmap_alloc(int version, const char *name, struct idmap_alloc_methods *test; struct idmap_alloc_backend *entry; - if (!idmap_ctx) { - return NT_STATUS_INTERNAL_DB_ERROR; - } - if ((version != SMB_IDMAP_INTERFACE_VERSION)) { DEBUG(0, ("Failed to register idmap alloc module.\n" "The module was compiled against " @@ -201,12 +182,12 @@ NTSTATUS smb_register_idmap_alloc(int version, const char *name, return NT_STATUS_OBJECT_NAME_COLLISION; } - entry = talloc(idmap_ctx, struct idmap_alloc_backend); + entry = talloc(NULL, struct idmap_alloc_backend); if ( ! entry) { DEBUG(0,("Out of memory!\n")); return NT_STATUS_NO_MEMORY; } - entry->name = talloc_strdup(idmap_ctx, name); + entry->name = talloc_strdup(entry, name); if ( ! entry->name) { DEBUG(0,("Out of memory!\n")); return NT_STATUS_NO_MEMORY; @@ -230,610 +211,313 @@ static int close_domain_destructor(struct idmap_domain *dom) return 0; } -/************************************************************************** - Shutdown. -**************************************************************************/ - -NTSTATUS idmap_close(void) +static bool parse_idmap_module(TALLOC_CTX *mem_ctx, const char *param, + char **pmodulename, char **pargs) { - /* close the alloc backend first before freeing idmap_ctx */ - if (idmap_alloc_ctx) { - idmap_alloc_ctx->methods->close_fn(); - idmap_alloc_ctx->methods = NULL; - } - alloc_backends = NULL; - - /* this talloc_free call will fire the talloc destructors - * that will free all active backends resources */ - TALLOC_FREE(idmap_ctx); - idmap_cache = NULL; - idmap_domains = NULL; - backends = NULL; - - return NT_STATUS_OK; -} + char *modulename; + char *args; -/**************************************************************************** - ****************************************************************************/ + if (strncmp(param, "idmap_", 6) == 0) { + param += 6; + DEBUG(1, ("idmap_init: idmap backend uses deprecated " + "'idmap_' prefix. Please replace 'idmap_%s' by " + "'%s'\n", param, param)); + } -NTSTATUS idmap_init_cache(void) -{ - /* Always initialize the cache. We'll have to delay initialization - of backends if we are offline */ + modulename = talloc_strdup(mem_ctx, param); + if (modulename == NULL) { + return false; + } - if ( idmap_ctx ) { - return NT_STATUS_OK; + args = strchr(modulename, ':'); + if (args == NULL) { + *pmodulename = modulename; + *pargs = NULL; + return true; } - if ( (idmap_ctx = talloc_named_const(NULL, 0, "idmap_ctx")) == NULL ) { - return NT_STATUS_NO_MEMORY; + *args = '\0'; + + args = talloc_strdup(mem_ctx, args+1); + if (args == NULL) { + TALLOC_FREE(modulename); + return false; } - return NT_STATUS_OK; + *pmodulename = modulename; + *pargs = args; + return true; } -/**************************************************************************** - ****************************************************************************/ - -static NTSTATUS idmap_init(void) +static struct idmap_domain *idmap_init_domain(TALLOC_CTX *mem_ctx, + const char *domainname, + const char *modulename, + const char *params) { - NTSTATUS ret; - static NTSTATUS idmap_init_status = NT_STATUS_UNSUCCESSFUL; - struct idmap_domain *dom; - char *compat_backend = NULL; - char *compat_params = NULL; - const char **dom_list = NULL; - const char *default_domain = NULL; - char *alloc_backend = NULL; - bool default_already_defined = False; - bool pri_dom_is_in_list = False; - int compat = 0; - int i; + struct idmap_domain *result; + NTSTATUS status; - ret = idmap_init_cache(); - if (!NT_STATUS_IS_OK(ret)) - return ret; - - if (NT_STATUS_IS_OK(idmap_init_status)) { - return NT_STATUS_OK; + result = talloc_zero(mem_ctx, struct idmap_domain); + if (result == NULL) { + DEBUG(0, ("talloc failed\n")); + return NULL; } - /* We can't reliably call intialization code here unless - we are online. But return NT_STATUS_OK so the upper - level code doesn't abort idmap lookups. */ - - if ( get_global_winbindd_state_offline() ) { - idmap_init_status = NT_STATUS_FILE_IS_OFFLINE; - return NT_STATUS_OK; + result->name = talloc_strdup(result, domainname); + if (result->name == NULL) { + DEBUG(0, ("talloc failed\n")); + goto fail; } - static_init_idmap; + result->methods = get_methods(backends, modulename); + if (result->methods == NULL) { + DEBUG(3, ("idmap backend %s not found\n", modulename)); - dom_list = lp_idmap_domains(); - - if ( lp_idmap_backend() ) { - const char **compat_list = lp_idmap_backend(); - char *p = NULL; - const char *q = NULL; - - if ( dom_list ) { - DEBUG(0, ("WARNING: idmap backend and idmap domains are" - " mutually exclusive!\n")); - DEBUGADD(0,("idmap backend option will be IGNORED!\n")); - } else { - compat = 1; - - compat_backend = talloc_strdup(idmap_ctx, *compat_list); - - /* strip any leading idmap_ prefix of */ - if (strncmp(*compat_list, "idmap_", 6) == 0 ) { - q = *compat_list += 6; - DEBUG(0, ("WARNING: idmap backend uses obsolete" - " and deprecated 'idmap_' prefix.\n" - "Please replace 'idmap_%s' by '%s' in" - " %s\n", q, q, get_dyn_CONFIGFILE())); - compat_backend = talloc_strdup(idmap_ctx, q); - } else { - compat_backend = talloc_strdup(idmap_ctx, - *compat_list); - } - - if (compat_backend == NULL ) { - ret = NT_STATUS_NO_MEMORY; - goto done; - } - - /* separate the backend and module arguments */ - if ((p = strchr(compat_backend, ':')) != NULL) { - *p = '\0'; - compat_params = p + 1; - } + status = smb_probe_module("idmap", modulename); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3, ("Could not probe idmap module %s\n", + modulename)); + goto fail; } - } else if ( !dom_list ) { - /* Back compatible: without idmap domains and explicit - idmap backend. Taking default idmap backend: tdb */ - compat = 1; - compat_backend = talloc_strdup( idmap_ctx, "tdb"); - compat_params = compat_backend; + result->methods = get_methods(backends, modulename); } - - if ( ! dom_list) { - /* generate a list with our main domain */ - const char ** dl; - - dl = talloc_array(idmap_ctx, const char *, 2); - if (dl == NULL) { - ret = NT_STATUS_NO_MEMORY; - goto done; - } - dl[0] = talloc_strdup(dl, lp_workgroup()); - if (dl[0] == NULL) { - ret = NT_STATUS_NO_MEMORY; - goto done; - } - - /* terminate */ - dl[1] = NULL; - - dom_list = dl; - default_domain = dl[0]; + if (result->methods == NULL) { + DEBUG(1, ("idmap backend %s not found\n", modulename)); + goto fail; } - /*************************** - * initialize idmap domains - */ - DEBUG(1, ("Initializing idmap domains\n")); - - for (i=0, num_domains=0; dom_list[i]; i++) { - const char *parm_backend; - char *config_option; - - /* ignore BUILTIN and local MACHINE domains */ - if (strequal(dom_list[i], "BUILTIN") - || strequal(dom_list[i], get_global_sam_name())) - { - DEBUG(0,("idmap_init: Ignoring domain %s\n", - dom_list[i])); - continue; - } - - if ((dom_list[i] != default_domain) && - strequal(dom_list[i], lp_workgroup())) { - pri_dom_is_in_list = True; - } - /* init domain */ - - dom = TALLOC_ZERO_P(idmap_ctx, struct idmap_domain); - IDMAP_CHECK_ALLOC(dom); - - dom->name = talloc_strdup(dom, dom_list[i]); - IDMAP_CHECK_ALLOC(dom->name); - - config_option = talloc_asprintf(dom, "idmap config %s", - dom->name); - IDMAP_CHECK_ALLOC(config_option); - - /* default or specific ? */ - - dom->default_domain = lp_parm_bool(-1, config_option, - "default", False); - - if (dom->default_domain || - (default_domain && strequal(dom_list[i], default_domain))) { - - /* make sure this is set even when we match - * default_domain */ - dom->default_domain = True; - - if (default_already_defined) { - DEBUG(1, ("ERROR: Multiple domains defined as" - " default!\n")); - ret = NT_STATUS_INVALID_PARAMETER; - goto done; - } - - default_already_defined = True; - - } - - dom->readonly = lp_parm_bool(-1, config_option, - "readonly", False); - - /* find associated backend (default: tdb) */ - if (compat) { - parm_backend = talloc_strdup(idmap_ctx, compat_backend); - } else { - parm_backend = talloc_strdup(idmap_ctx, - lp_parm_const_string( - -1, config_option, - "backend", "tdb")); - } - IDMAP_CHECK_ALLOC(parm_backend); - - /* get the backend methods for this domain */ - dom->methods = get_methods(backends, parm_backend); - - if ( ! dom->methods) { - ret = smb_probe_module("idmap", parm_backend); - if (NT_STATUS_IS_OK(ret)) { - dom->methods = get_methods(backends, - parm_backend); - } - } - if ( ! dom->methods) { - DEBUG(0, ("ERROR: Could not get methods for " - "backend %s\n", parm_backend)); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; - } - - /* check the set_mapping function exists otherwise mark the - * module as readonly */ - if ( ! dom->methods->set_mapping) { - DEBUG(5, ("Forcing to readonly, as this module can't" - " store arbitrary mappings.\n")); - dom->readonly = True; - } - - /* now that we have methods, - * set the destructor for this domain */ - talloc_set_destructor(dom, close_domain_destructor); + status = result->methods->init(result, params); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("idmap initialization returned %s\n", + nt_errstr(status))); + goto fail; + } - if (compat_params) { - dom->params = talloc_strdup(dom, compat_params); - IDMAP_CHECK_ALLOC(dom->params); - } else { - dom->params = NULL; - } + talloc_set_destructor(result, close_domain_destructor); - /* Finally instance a backend copy for this domain */ - ret = dom->methods->init(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - DEBUG(0, ("ERROR: Initialization failed for backend " - "%s (domain %s), deferred!\n", - parm_backend, dom->name)); - } - idmap_domains = talloc_realloc(idmap_ctx, idmap_domains, - struct idmap_domain *, i+1); - if ( ! idmap_domains) { - DEBUG(0, ("Out of memory!\n")); - ret = NT_STATUS_NO_MEMORY; - goto done; - } - idmap_domains[num_domains] = dom; + return result; - /* save default domain position for future uses */ - if (dom->default_domain) { - def_dom_num = num_domains; - } +fail: + TALLOC_FREE(result); + return NULL; +} - /* Bump counter to next available slot */ +static struct idmap_domain *idmap_init_default_domain(TALLOC_CTX *mem_ctx) +{ + struct idmap_domain *result; + char *modulename; + char *params; - num_domains++; + DEBUG(10, ("idmap_init_default_domain: calling static_init_idmap\n")); - DEBUG(10, ("Domain %s - Backend %s - %sdefault - %sreadonly\n", - dom->name, parm_backend, - dom->default_domain?"":"not ", - dom->readonly?"":"not ")); + static_init_idmap; - talloc_free(config_option); + if (!parse_idmap_module(talloc_tos(), lp_idmap_backend(), &modulename, + ¶ms)) { + DEBUG(1, ("parse_idmap_module failed\n")); + return NULL; } - /* on DCs we need to add idmap_tdb as the default backend if compat is - * defined (when the old implicit configuration is used) - * This is not done in the previous loop a on member server we exclude - * the local domain. But on a DC the local domain is the only domain - * available therefore we are left with no default domain */ - if (((lp_server_role() == ROLE_DOMAIN_PDC) || - (lp_server_role() == ROLE_DOMAIN_BDC)) && - ((num_domains == 0) && (compat == 1))) { - - dom = TALLOC_ZERO_P(idmap_ctx, struct idmap_domain); - IDMAP_CHECK_ALLOC(dom); - - dom->name = talloc_strdup(dom, "__default__"); - IDMAP_CHECK_ALLOC(dom->name); - - dom->default_domain = True; - dom->readonly = False; - - /* get the backend methods for this domain */ - dom->methods = get_methods(backends, compat_backend); - - if ( ! dom->methods) { - ret = smb_probe_module("idmap", compat_backend); - if (NT_STATUS_IS_OK(ret)) { - dom->methods = get_methods(backends, - compat_backend); - } - } - if ( ! dom->methods) { - DEBUG(0, ("ERROR: Could not get methods for " - "backend %s\n", compat_backend)); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; - } - - /* now that we have methods, - * set the destructor for this domain */ - talloc_set_destructor(dom, close_domain_destructor); + DEBUG(3, ("idmap_init: using '%s' as remote backend\n", modulename)); - dom->params = talloc_strdup(dom, compat_params); - IDMAP_CHECK_ALLOC(dom->params); + result = idmap_init_domain(mem_ctx, "*", modulename, params); + if (result == NULL) { + goto fail; + } - /* Finally instance a backend copy for this domain */ - ret = dom->methods->init(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - DEBUG(0, ("ERROR: Initialization failed for backend " - "%s (domain %s), deferred!\n", - compat_backend, dom->name)); - } - idmap_domains = talloc_realloc(idmap_ctx, idmap_domains, - struct idmap_domain *, 2); - if ( ! idmap_domains) { - DEBUG(0, ("Out of memory!\n")); - ret = NT_STATUS_NO_MEMORY; - goto done; - } - idmap_domains[num_domains] = dom; + TALLOC_FREE(modulename); + TALLOC_FREE(params); + return result; - def_dom_num = num_domains; +fail: + TALLOC_FREE(modulename); + TALLOC_FREE(params); + TALLOC_FREE(result); + return NULL; +} - /* Bump counter to next available slot */ +static struct idmap_domain *idmap_init_named_domain(TALLOC_CTX *mem_ctx, + const char *domname) +{ + struct idmap_domain *result = NULL; + char *config_option; + const char *backend; - num_domains++; + config_option = talloc_asprintf(talloc_tos(), "idmap config %s", + domname); + if (config_option == NULL) { + DEBUG(0, ("talloc failed\n")); + goto fail; + } - DEBUG(10, ("Domain %s - Backend %s - %sdefault - %sreadonly\n", - dom->name, compat_backend, - dom->default_domain?"":"not ", - dom->readonly?"":"not ")); + backend = lp_parm_const_string(-1, config_option, "backend", NULL); + if (backend == NULL) { + DEBUG(1, ("no backend defined for %s\n", config_option)); + goto fail; } - /* automatically add idmap_nss backend if needed */ - if ((lp_server_role() == ROLE_DOMAIN_MEMBER) && - ( ! pri_dom_is_in_list) && - lp_winbind_trusted_domains_only()) { + result = idmap_init_domain(mem_ctx, domname, backend, NULL); + if (result == NULL) { + goto fail; + } - dom = TALLOC_ZERO_P(idmap_ctx, struct idmap_domain); - IDMAP_CHECK_ALLOC(dom); + TALLOC_FREE(config_option); + return result; - dom->name = talloc_strdup(dom, lp_workgroup()); - IDMAP_CHECK_ALLOC(dom->name); +fail: + TALLOC_FREE(config_option); + TALLOC_FREE(result); + return NULL; +} - dom->default_domain = False; - dom->readonly = True; +static struct idmap_domain *idmap_init_passdb_domain(TALLOC_CTX *mem_ctx) +{ + if (passdb_idmap_domain != NULL) { + return passdb_idmap_domain; + } - /* get the backend methods for passdb */ - dom->methods = get_methods(backends, "nss"); + passdb_idmap_domain = idmap_init_domain(NULL, get_global_sam_name(), + "passdb", NULL); + if (passdb_idmap_domain == NULL) { + DEBUG(1, ("Could not init passdb idmap domain\n")); + } - /* (the nss module is always statically linked) */ - if ( ! dom->methods) { - DEBUG(0, ("ERROR: No methods for idmap_nss ?!\n")); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; - } + return passdb_idmap_domain; +} - /* now that we have methods, - * set the destructor for this domain */ - talloc_set_destructor(dom, close_domain_destructor); +static struct idmap_domain *idmap_find_domain(const char *domname) +{ + struct idmap_domain *result; + int i; - if (compat_params) { - dom->params = talloc_strdup(dom, compat_params); - IDMAP_CHECK_ALLOC(dom->params); - } else { - dom->params = NULL; - } + /* + * Always init the default domain, we can't go without one + */ + if (default_idmap_domain == NULL) { + default_idmap_domain = idmap_init_default_domain(NULL); + } + if (default_idmap_domain == NULL) { + return NULL; + } - /* Finally instance a backend copy for this domain */ - ret = dom->methods->init(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - DEBUG(0, ("ERROR: Init. failed for idmap_nss ?!\n")); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; - } + if ((domname == NULL) || (domname[0] == '\0')) { + return default_idmap_domain; + } - idmap_domains = talloc_realloc(idmap_ctx, - idmap_domains, - struct idmap_domain *, - num_domains+1); - if ( ! idmap_domains) { - DEBUG(0, ("Out of memory!\n")); - ret = NT_STATUS_NO_MEMORY; - goto done; + for (i=0; i<num_domains; i++) { + if (strequal(idmap_domains[i]->name, domname)) { + return idmap_domains[i]; } - idmap_domains[num_domains] = dom; + } - DEBUG(10, ("Domain %s - Backend nss - not default - readonly\n", - dom->name )); + if (idmap_domains == NULL) { + /* + * talloc context for all idmap domains + */ + idmap_domains = TALLOC_ARRAY(NULL, struct idmap_domain *, 1); + } - num_domains++; + if (idmap_domains == NULL) { + DEBUG(0, ("talloc failed\n")); + return NULL; } - /**** automatically add idmap_passdb backend ****/ - dom = TALLOC_ZERO_P(idmap_ctx, struct idmap_domain); - IDMAP_CHECK_ALLOC(dom); + result = idmap_init_named_domain(idmap_domains, domname); + if (result == NULL) { + /* + * Could not init that domain -- try the default one + */ + return default_idmap_domain; + } - dom->name = talloc_strdup(dom, get_global_sam_name()); - IDMAP_CHECK_ALLOC(dom->name); + ADD_TO_ARRAY(idmap_domains, struct idmap_domain *, result, + &idmap_domains, &num_domains); + return result; +} - dom->default_domain = False; - dom->readonly = True; +void idmap_close(void) +{ + if (idmap_alloc_ctx) { + idmap_alloc_ctx->methods->close_fn(); + idmap_alloc_ctx->methods = NULL; + } + alloc_backends = NULL; + TALLOC_FREE(default_idmap_domain); + TALLOC_FREE(passdb_idmap_domain); + TALLOC_FREE(idmap_domains); + num_domains = 0; +} - /* get the backend methods for passdb */ - dom->methods = get_methods(backends, "passdb"); +static NTSTATUS idmap_alloc_init(struct idmap_alloc_context **ctx) +{ + const char *backend; + char *modulename, *params; + NTSTATUS ret = NT_STATUS_NO_MEMORY;; - /* (the passdb module is always statically linked) */ - if ( ! dom->methods) { - DEBUG(0, ("ERROR: No methods for idmap_passdb ?!\n")); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; + if (idmap_alloc_ctx != NULL) { + *ctx = idmap_alloc_ctx; + return NT_STATUS_OK; } - /* now that we have methods, set the destructor for this domain */ - talloc_set_destructor(dom, close_domain_destructor); - - if (compat_params) { - dom->params = talloc_strdup(dom, compat_params); - IDMAP_CHECK_ALLOC(dom->params); - } else { - dom->params = NULL; + idmap_alloc_ctx = talloc(NULL, struct idmap_alloc_context); + if (idmap_alloc_ctx == NULL) { + DEBUG(0, ("talloc failed\n")); + goto fail; } - /* Finally instance a backend copy for this domain */ - ret = dom->methods->init(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - DEBUG(0, ("ERROR: Init. failed for idmap_passdb ?!\n")); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; + backend = lp_idmap_alloc_backend(); + if ((backend == NULL) || (backend[0] == '\0')) { + backend = lp_idmap_backend(); } - idmap_domains = talloc_realloc(idmap_ctx, - idmap_domains, - struct idmap_domain *, - num_domains+1); - if ( ! idmap_domains) { - DEBUG(0, ("Out of memory!\n")); - ret = NT_STATUS_NO_MEMORY; - goto done; + if (backend == NULL) { + DEBUG(3, ("no idmap alloc backend defined\n")); + ret = NT_STATUS_INVALID_PARAMETER; + goto fail; } - idmap_domains[num_domains] = dom; - - /* needed to handle special BUILTIN and wellknown SIDs cases */ - pdb_dom_num = num_domains; - - DEBUG(10, ("Domain %s - Backend passdb - not default - readonly\n", - dom->name)); - - num_domains++; - /**** finished adding idmap_passdb backend ****/ - - /* sort domains so that the default is the last one */ - /* don't sort if no default domain defined */ - if (def_dom_num != -1 && def_dom_num != num_domains-1) { - /* default is not last, move it */ - struct idmap_domain *tmp; - - if (pdb_dom_num > def_dom_num) { - pdb_dom_num --; - - } else if (pdb_dom_num == def_dom_num) { /* ?? */ - pdb_dom_num = num_domains - 1; - } - - tmp = idmap_domains[def_dom_num]; - for (i = def_dom_num; i < num_domains-1; i++) { - idmap_domains[i] = idmap_domains[i+1]; - } - idmap_domains[i] = tmp; - def_dom_num = i; + if (!parse_idmap_module(idmap_alloc_ctx, backend, &modulename, + ¶ms)) { + DEBUG(1, ("parse_idmap_module %s failed\n", backend)); + goto fail; } + idmap_alloc_ctx->methods = get_alloc_methods(alloc_backends, + modulename); - /* Initialize alloc module */ - - DEBUG(3, ("Initializing idmap alloc module\n")); - - alloc_backend = NULL; - if (compat) { - alloc_backend = talloc_strdup(idmap_ctx, compat_backend); - } else { - char *ab = lp_idmap_alloc_backend(); - - if (ab && (ab[0] != '\0')) { - alloc_backend = talloc_strdup(idmap_ctx, - lp_idmap_alloc_backend()); + if (idmap_alloc_ctx->methods == NULL) { + ret = smb_probe_module("idmap", modulename); + if (NT_STATUS_IS_OK(ret)) { + idmap_alloc_ctx->methods = + get_alloc_methods(alloc_backends, + modulename); } } - if ( alloc_backend ) { - - idmap_alloc_ctx = TALLOC_ZERO_P(idmap_ctx, - struct idmap_alloc_context); - IDMAP_CHECK_ALLOC(idmap_alloc_ctx); - - idmap_alloc_ctx->methods = get_alloc_methods(alloc_backends, - alloc_backend); - if ( ! idmap_alloc_ctx->methods) { - ret = smb_probe_module("idmap", alloc_backend); - if (NT_STATUS_IS_OK(ret)) { - idmap_alloc_ctx->methods = - get_alloc_methods(alloc_backends, - alloc_backend); - } - } - if (idmap_alloc_ctx->methods) { - - if (compat_params) { - idmap_alloc_ctx->params = - talloc_strdup(idmap_alloc_ctx, - compat_params); - IDMAP_CHECK_ALLOC(idmap_alloc_ctx->params); - } else { - idmap_alloc_ctx->params = NULL; - } - - ret = idmap_alloc_ctx->methods->init(idmap_alloc_ctx->params); - if ( ! NT_STATUS_IS_OK(ret)) { - DEBUG(0, ("ERROR: Initialization failed for " - "alloc backend %s, deferred!\n", - alloc_backend)); - } else { - idmap_alloc_ctx->initialized = True; - } - } else { - DEBUG(2, ("idmap_init: Unable to get methods for " - "alloc backend %s\n", - alloc_backend)); - /* certain compat backends are just readonly */ - if ( compat ) { - TALLOC_FREE(idmap_alloc_ctx); - ret = NT_STATUS_OK; - } else { - ret = NT_STATUS_UNSUCCESSFUL; - } - } + if (idmap_alloc_ctx->methods == NULL) { + DEBUG(1, ("could not find idmap alloc module %s\n", backend)); + ret = NT_STATUS_INVALID_PARAMETER; + goto fail; } - /* cleanup temporary strings */ - TALLOC_FREE( compat_backend ); - - idmap_init_status = NT_STATUS_OK; - - return ret; + ret = idmap_alloc_ctx->methods->init(params); -done: - DEBUG(0, ("Aborting IDMAP Initialization ...\n")); - idmap_close(); - - return ret; -} - -static NTSTATUS idmap_alloc_init(void) -{ - NTSTATUS ret; - - if (! NT_STATUS_IS_OK(ret = idmap_init())) { - return ret; - } - - if ( ! idmap_alloc_ctx) { - return NT_STATUS_NOT_SUPPORTED; + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0, ("ERROR: Initialization failed for alloc " + "backend, deferred!\n")); + goto fail; } - if ( ! idmap_alloc_ctx->initialized) { - ret = idmap_alloc_ctx->methods->init(idmap_alloc_ctx->params); - if ( ! NT_STATUS_IS_OK(ret)) { - DEBUG(0, ("ERROR: Initialization failed for alloc " - "backend, deferred!\n")); - return ret; - } else { - idmap_alloc_ctx->initialized = True; - } - } + TALLOC_FREE(modulename); + TALLOC_FREE(params); + *ctx = idmap_alloc_ctx; return NT_STATUS_OK; + +fail: + TALLOC_FREE(idmap_alloc_ctx); + return ret; } /************************************************************************** @@ -842,343 +526,180 @@ static NTSTATUS idmap_alloc_init(void) NTSTATUS idmap_allocate_uid(struct unixid *id) { + struct idmap_alloc_context *ctx; NTSTATUS ret; - if (! NT_STATUS_IS_OK(ret = idmap_alloc_init())) { + if (!NT_STATUS_IS_OK(ret = idmap_alloc_init(&ctx))) { return ret; } id->type = ID_TYPE_UID; - return idmap_alloc_ctx->methods->allocate_id(id); + return ctx->methods->allocate_id(id); } NTSTATUS idmap_allocate_gid(struct unixid *id) { + struct idmap_alloc_context *ctx; NTSTATUS ret; - if (! NT_STATUS_IS_OK(ret = idmap_alloc_init())) { + if (!NT_STATUS_IS_OK(ret = idmap_alloc_init(&ctx))) { return ret; } id->type = ID_TYPE_GID; - return idmap_alloc_ctx->methods->allocate_id(id); + return ctx->methods->allocate_id(id); } NTSTATUS idmap_set_uid_hwm(struct unixid *id) { + struct idmap_alloc_context *ctx; NTSTATUS ret; - if (! NT_STATUS_IS_OK(ret = idmap_alloc_init())) { + if (!NT_STATUS_IS_OK(ret = idmap_alloc_init(&ctx))) { return ret; } id->type = ID_TYPE_UID; - return idmap_alloc_ctx->methods->set_id_hwm(id); + return ctx->methods->set_id_hwm(id); } NTSTATUS idmap_set_gid_hwm(struct unixid *id) { + struct idmap_alloc_context *ctx; NTSTATUS ret; - if (! NT_STATUS_IS_OK(ret = idmap_alloc_init())) { + if (!NT_STATUS_IS_OK(ret = idmap_alloc_init(&ctx))) { return ret; } id->type = ID_TYPE_GID; - return idmap_alloc_ctx->methods->set_id_hwm(id); -} - -/****************************************************************************** - Lookup an idmap_domain give a full user or group SID - ******************************************************************************/ - -static struct idmap_domain* find_idmap_domain_from_sid( DOM_SID *account_sid ) -{ - DOM_SID domain_sid; - uint32 rid; - struct winbindd_domain *domain = NULL; - int i; - - /* 1. Handle BUILTIN or Special SIDs and prevent them from - falling into the default domain space (if we have a - configured passdb backend. */ - - if ( (pdb_dom_num != -1) && - (sid_check_is_in_builtin(account_sid) || - sid_check_is_in_wellknown_domain(account_sid) || - sid_check_is_in_unix_groups(account_sid) || - sid_check_is_in_unix_users(account_sid)) ) - { - return idmap_domains[pdb_dom_num]; - } - - /* 2. Lookup the winbindd_domain from the account_sid */ - - sid_copy( &domain_sid, account_sid ); - sid_split_rid( &domain_sid, &rid ); - domain = find_domain_from_sid_noinit( &domain_sid ); - - for (i = 0; domain && i < num_domains; i++) { - if ( strequal( idmap_domains[i]->name, domain->name ) ) { - return idmap_domains[i]; - } - } - - /* 3. Fall back to the default domain */ - - if ( def_dom_num != -1 ) { - return idmap_domains[def_dom_num]; - } - - return NULL; + return ctx->methods->set_id_hwm(id); } -/****************************************************************************** - Lookup an index given an idmap_domain pointer - ******************************************************************************/ - -static uint32 find_idmap_domain_index( struct idmap_domain *id_domain) -{ - int i; - - for (i = 0; i < num_domains; i++) { - if ( idmap_domains[i] == id_domain ) - return i; - } - - return -1; -} - - -/********************************************************* - Check if creating a mapping is permitted for the domain -*********************************************************/ - -static NTSTATUS idmap_can_map(const struct id_map *map, - struct idmap_domain **ret_dom) +NTSTATUS idmap_new_mapping(const struct dom_sid *psid, enum id_type type, + struct unixid *pxid) { + struct dom_sid sid; struct idmap_domain *dom; + struct id_map map; + NTSTATUS status; - /* Check we do not create mappings for our own local domain, - * or BUILTIN or special SIDs */ - if ((sid_compare_domain(map->sid, get_global_sam_sid()) == 0) || - sid_check_is_in_builtin(map->sid) || - sid_check_is_in_wellknown_domain(map->sid) || - sid_check_is_in_unix_users(map->sid) || - sid_check_is_in_unix_groups(map->sid) ) - { - DEBUG(10, ("We are not supposed to create mappings for our own " - "domains (local, builtin, specials)\n")); - return NT_STATUS_UNSUCCESSFUL; - } - - /* Special check for trusted domain only = Yes */ - if (lp_winbind_trusted_domains_only()) { - struct winbindd_domain *wdom = find_our_domain(); - if (wdom && (sid_compare_domain(map->sid, &wdom->sid) == 0)) { - DEBUG(10, ("We are not supposed to create mappings for " - "our primary domain when <trusted domain " - "only> is True\n")); - DEBUGADD(10, ("Leave [%s] unmapped\n", - sid_string_dbg(map->sid))); - return NT_STATUS_UNSUCCESSFUL; - } - } - - if ( (dom = find_idmap_domain_from_sid( map->sid )) == NULL ) { - /* huh, couldn't find a suitable domain, - * let's just leave it unmapped */ - DEBUG(10, ("Could not find idmap backend for SID %s\n", - sid_string_dbg(map->sid))); - return NT_STATUS_NO_SUCH_DOMAIN; + dom = idmap_find_domain(NULL); + if (dom == NULL) { + DEBUG(3, ("no default domain, no place to write\n")); + return NT_STATUS_ACCESS_DENIED; } - - if (dom->readonly) { - /* ouch the domain is read only, - * let's just leave it unmapped */ - DEBUG(10, ("idmap backend for SID %s is READONLY!\n", - sid_string_dbg(map->sid))); - return NT_STATUS_UNSUCCESSFUL; + if (dom->methods->set_mapping == NULL) { + DEBUG(3, ("default domain not writable\n")); + return NT_STATUS_MEDIA_WRITE_PROTECTED; } - *ret_dom = dom; - return NT_STATUS_OK; -} - -static NTSTATUS idmap_new_mapping(TALLOC_CTX *ctx, struct id_map *map) -{ - NTSTATUS ret; - struct idmap_domain *dom; + sid_copy(&sid, psid); + map.sid = &sid; + map.xid.type = type; - /* If we are offline we cannot lookup SIDs, deny mapping */ - if (idmap_is_offline()) { - return NT_STATUS_FILE_IS_OFFLINE; - } - - ret = idmap_can_map(map, &dom); - if ( ! NT_STATUS_IS_OK(ret)) { - return NT_STATUS_NONE_MAPPED; - } - - /* check if this is a valid SID and then map it */ - switch (map->xid.type) { + switch (type) { case ID_TYPE_UID: - ret = idmap_allocate_uid(&map->xid); - if ( ! NT_STATUS_IS_OK(ret)) { - /* can't allocate id, let's just leave it unmapped */ - DEBUG(2, ("uid allocation failed! " - "Can't create mapping\n")); - return NT_STATUS_NONE_MAPPED; - } + status = idmap_allocate_uid(&map.xid); break; case ID_TYPE_GID: - ret = idmap_allocate_gid(&map->xid); - if ( ! NT_STATUS_IS_OK(ret)) { - /* can't allocate id, let's just leave it unmapped */ - DEBUG(2, ("gid allocation failed! " - "Can't create mapping\n")); - return NT_STATUS_NONE_MAPPED; - } + status = idmap_allocate_gid(&map.xid); break; default: - /* invalid sid, let's just leave it unmapped */ - DEBUG(3,("idmap_new_mapping: Refusing to create a " - "mapping for an unspecified ID type.\n")); - return NT_STATUS_NONE_MAPPED; + status = NT_STATUS_INVALID_PARAMETER; + break; } - /* ok, got a new id, let's set a mapping */ - map->status = ID_MAPPED; - - DEBUG(10, ("Setting mapping: %s <-> %s %lu\n", - sid_string_dbg(map->sid), - (map->xid.type == ID_TYPE_UID) ? "UID" : "GID", - (unsigned long)map->xid.id)); - ret = dom->methods->set_mapping(dom, map); - - if ( ! NT_STATUS_IS_OK(ret)) { - /* something wrong here :-( */ - DEBUG(2, ("Failed to commit mapping\n!")); - - /* TODO: would it make sense to have an "unalloc_id function?" */ - - return NT_STATUS_NONE_MAPPED; + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3, ("Could not allocate id: %s\n", nt_errstr(status))); + return status; } - return NT_STATUS_OK; -} + map.status = ID_MAPPED; -static NTSTATUS idmap_backends_set_mapping(const struct id_map *map) -{ - struct idmap_domain *dom; - NTSTATUS ret; + DEBUG(10, ("Setting mapping: %s <-> %s %lu\n", + sid_string_dbg(map.sid), + (map.xid.type == ID_TYPE_UID) ? "UID" : "GID", + (unsigned long)map.xid.id)); - DEBUG(10, ("Setting mapping %s <-> %s %lu\n", - sid_string_dbg(map->sid), - (map->xid.type == ID_TYPE_UID) ? "UID" : "GID", - (unsigned long)map->xid.id)); + status = dom->methods->set_mapping(dom, &map); - ret = idmap_can_map(map, &dom); - if ( ! NT_STATUS_IS_OK(ret)) { - return ret; + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3, ("Could not store the new mapping: %s\n", + nt_errstr(status))); + return status; } - DEBUG(10,("set_mapping for domain %s\n", dom->name )); + *pxid = map.xid; - return dom->methods->set_mapping(dom, map); + return NT_STATUS_OK; } -NTSTATUS idmap_backends_unixid_to_sid(struct id_map *id) +NTSTATUS idmap_backends_unixid_to_sid(const char *domname, struct id_map *id) { + struct idmap_domain *dom; struct id_map *maps[2]; - int i; maps[0] = id; maps[1] = NULL; - for (i = num_domains-1; i>=0; i--) { - struct idmap_domain *dom = idmap_domains[i]; - NTSTATUS status; + /* + * Always give passdb a chance first + */ - DEBUG(10, ("Query sids from domain %s\n", dom->name)); + dom = idmap_init_passdb_domain(NULL); + if ((dom != NULL) + && NT_STATUS_IS_OK(dom->methods->unixids_to_sids(dom, maps))) { + return NT_STATUS_OK; + } - status = dom->methods->unixids_to_sids(dom, maps); - if (NT_STATUS_IS_OK(status)) { - return NT_STATUS_OK; - } + dom = idmap_find_domain(domname); + if (dom == NULL) { + return NT_STATUS_NONE_MAPPED; } - return NT_STATUS_NONE_MAPPED; + return dom->methods->unixids_to_sids(dom, maps); } -NTSTATUS idmap_backends_sid_to_unixid(struct id_map *id) +NTSTATUS idmap_backends_sid_to_unixid(const char *domain, struct id_map *id) { struct idmap_domain *dom; struct id_map *maps[2]; - dom = find_idmap_domain_from_sid(id->sid); - if (dom == NULL) { - return NT_STATUS_NONE_MAPPED; - } - maps[0] = id; maps[1] = NULL; - return dom->methods->sids_to_unixids(dom, maps); -} - -NTSTATUS idmap_set_mapping(const struct id_map *id) -{ - TALLOC_CTX *ctx; - NTSTATUS ret; - - if (! NT_STATUS_IS_OK(ret = idmap_init())) { - return ret; - } + if (sid_check_is_in_builtin(id->sid) + || (sid_check_is_in_our_domain(id->sid))) { - /* sanity checks */ - if ((id->sid == NULL) || (id->status != ID_MAPPED)) { - DEBUG(1, ("NULL SID or unmapped entry\n")); - return NT_STATUS_INVALID_PARAMETER; + dom = idmap_init_passdb_domain(NULL); + if (dom == NULL) { + return NT_STATUS_NONE_MAPPED; + } + return dom->methods->sids_to_unixids(dom, maps); } - /* TODO: check uid/gid range ? */ - - ctx = talloc_named_const(NULL, 0, "idmap_set_mapping ctx"); - if ( ! ctx) { - DEBUG(1, ("failed to allocate talloc context, OOM?\n")); - return NT_STATUS_NO_MEMORY; + dom = idmap_find_domain(domain); + if (dom == NULL) { + return NT_STATUS_NONE_MAPPED; } - /* set the new mapping */ - ret = idmap_backends_set_mapping(id); - IDMAP_CHECK_RET(ret); - -done: - talloc_free(ctx); - return ret; + return dom->methods->sids_to_unixids(dom, maps); } -char *idmap_fetch_secret(const char *backend, bool alloc, - const char *domain, const char *identity) +NTSTATUS idmap_set_mapping(const struct id_map *map) { - char *tmp, *ret; - int r; + struct idmap_domain *dom; - if (alloc) { - r = asprintf(&tmp, "IDMAP_ALLOC_%s", backend); - } else { - r = asprintf(&tmp, "IDMAP_%s_%s", backend, domain); + dom = idmap_find_domain(NULL); + if (dom == NULL) { + DEBUG(3, ("no default domain, no place to write\n")); + return NT_STATUS_ACCESS_DENIED; + } + if (dom->methods->set_mapping == NULL) { + DEBUG(3, ("default domain not writable\n")); + return NT_STATUS_MEDIA_WRITE_PROTECTED; } - if (r < 0) - return NULL; - - strupper_m(tmp); /* make sure the key is case insensitive */ - ret = secrets_fetch_generic(tmp, identity); - - SAFE_FREE(tmp); - - return ret; + return dom->methods->set_mapping(dom, map); } - diff --git a/source3/winbindd/idmap_ad.c b/source3/winbindd/idmap_ad.c index 0d7c068844..9fefb1bba7 100644 --- a/source3/winbindd/idmap_ad.c +++ b/source3/winbindd/idmap_ad.c @@ -160,7 +160,8 @@ static ADS_STRUCT *ad_idmap_cached_connection(void) /************************************************************************ ***********************************************************************/ -static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom) +static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom, + const char *params) { struct idmap_ad_context *ctx; char *config_option; @@ -206,7 +207,6 @@ static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom) } dom->private_data = ctx; - dom->initialized = True; talloc_free(config_option); @@ -277,14 +277,6 @@ static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map return NT_STATUS_FILE_IS_OFFLINE; } - /* Initilization my have been deferred because we were offline */ - if ( ! dom->initialized) { - ret = idmap_ad_initialize(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - return ret; - } - } - ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); if ( (memctx = talloc_new(ctx)) == NULL ) { @@ -496,14 +488,6 @@ static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map return NT_STATUS_FILE_IS_OFFLINE; } - /* Initilization my have been deferred because we were offline */ - if ( ! dom->initialized) { - ret = idmap_ad_initialize(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - return ret; - } - } - ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); if ( (memctx = talloc_new(ctx)) == NULL ) { diff --git a/source3/winbindd/idmap_cache.c b/source3/winbindd/idmap_cache.c index 1e82314440..b818d0dafb 100644 --- a/source3/winbindd/idmap_cache.c +++ b/source3/winbindd/idmap_cache.c @@ -59,7 +59,7 @@ bool idmap_cache_find_uid2sid(uid_t uid, struct dom_sid *sid, bool *expired) char *key; char *value; time_t timeout; - bool ret; + bool ret = true; key = talloc_asprintf(talloc_tos(), "IDMAP/UID2SID/%d", (int)uid); if (key == NULL) { @@ -71,7 +71,9 @@ bool idmap_cache_find_uid2sid(uid_t uid, struct dom_sid *sid, bool *expired) return false; } ZERO_STRUCTP(sid); - ret = string_to_sid(sid, value); + if (value[0] != '-') { + ret = string_to_sid(sid, value); + } SAFE_FREE(value); if (ret) { *expired = (timeout <= time(NULL)); @@ -96,10 +98,15 @@ void idmap_cache_set_sid2uid(const struct dom_sid *sid, uid_t uid) } if (uid != -1) { fstr_sprintf(key, "IDMAP/UID2SID/%d", (int)uid); - sid_to_fstring(value, sid); - timeout = is_null_sid(sid) - ? lp_idmap_negative_cache_time() - : lp_idmap_cache_time(); + if (is_null_sid(sid)) { + /* negative uid mapping */ + fstrcpy(value, "-"); + timeout = lp_idmap_negative_cache_time(); + } + else { + sid_to_fstring(value, sid); + timeout = lp_idmap_cache_time(); + } gencache_set(key, value, now + timeout); } } @@ -140,7 +147,7 @@ bool idmap_cache_find_gid2sid(gid_t gid, struct dom_sid *sid, bool *expired) char *key; char *value; time_t timeout; - bool ret; + bool ret = true; key = talloc_asprintf(talloc_tos(), "IDMAP/GID2SID/%d", (int)gid); if (key == NULL) { @@ -152,7 +159,9 @@ bool idmap_cache_find_gid2sid(gid_t gid, struct dom_sid *sid, bool *expired) return false; } ZERO_STRUCTP(sid); - ret = string_to_sid(sid, value); + if (value[0] != '-') { + ret = string_to_sid(sid, value); + } SAFE_FREE(value); if (ret) { *expired = (timeout <= time(NULL)); @@ -177,10 +186,15 @@ void idmap_cache_set_sid2gid(const struct dom_sid *sid, gid_t gid) } if (gid != -1) { fstr_sprintf(key, "IDMAP/GID2SID/%d", (int)gid); - sid_to_fstring(value, sid); - timeout = is_null_sid(sid) - ? lp_idmap_negative_cache_time() - : lp_idmap_cache_time(); + if (is_null_sid(sid)) { + /* negative gid mapping */ + fstrcpy(value, "-"); + timeout = lp_idmap_negative_cache_time(); + } + else { + sid_to_fstring(value, sid); + timeout = lp_idmap_cache_time(); + } gencache_set(key, value, now + timeout); } } diff --git a/source3/winbindd/idmap_ldap.c b/source3/winbindd/idmap_ldap.c index fa80fae5d8..64b176389e 100644 --- a/source3/winbindd/idmap_ldap.c +++ b/source3/winbindd/idmap_ldap.c @@ -33,6 +33,29 @@ #include "smbldap.h" +static char *idmap_fetch_secret(const char *backend, bool alloc, + 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); + } + + if (r < 0) + return NULL; + + strupper_m(tmp); /* make sure the key is case insensitive */ + ret = secrets_fetch_generic(tmp, identity); + + SAFE_FREE(tmp); + + return ret; +} + struct idmap_ldap_context { struct smbldap_state *smbldap_state; char *url; @@ -760,7 +783,8 @@ static int idmap_ldap_close_destructor(struct idmap_ldap_context *ctx) Initialise idmap database. ********************************/ -static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom) +static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom, + const char *params) { NTSTATUS ret; struct idmap_ldap_context *ctx = NULL; @@ -798,9 +822,9 @@ static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom) } } - if (dom->params && *(dom->params)) { + if (params != NULL) { /* assume location is the only parameter */ - ctx->url = talloc_strdup(ctx, dom->params); + ctx->url = talloc_strdup(ctx, params); } else { tmp = lp_parm_const_string(-1, config_option, "ldap_url", NULL); @@ -848,7 +872,6 @@ static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom) talloc_set_destructor(ctx, idmap_ldap_close_destructor); dom->private_data = ctx; - dom->initialized = True; talloc_free(config_option); return NT_STATUS_OK; @@ -909,14 +932,6 @@ static NTSTATUS idmap_ldap_unixids_to_sids(struct idmap_domain *dom, return NT_STATUS_FILE_IS_OFFLINE; } - /* Initilization my have been deferred because we were offline */ - if ( ! dom->initialized) { - ret = idmap_ldap_db_init(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - return ret; - } - } - ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context); memctx = talloc_new(ctx); @@ -1138,14 +1153,6 @@ static NTSTATUS idmap_ldap_sids_to_unixids(struct idmap_domain *dom, return NT_STATUS_FILE_IS_OFFLINE; } - /* Initilization my have been deferred because we were offline */ - if ( ! dom->initialized) { - ret = idmap_ldap_db_init(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - return ret; - } - } - ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context); memctx = talloc_new(ctx); @@ -1350,14 +1357,6 @@ static NTSTATUS idmap_ldap_set_mapping(struct idmap_domain *dom, return NT_STATUS_FILE_IS_OFFLINE; } - /* Initilization my have been deferred because we were offline */ - if ( ! dom->initialized) { - ret = idmap_ldap_db_init(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - return ret; - } - } - ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context); switch(map->xid.type) { diff --git a/source3/winbindd/idmap_nss.c b/source3/winbindd/idmap_nss.c index e4acd9ce65..156fdc7cc9 100644 --- a/source3/winbindd/idmap_nss.c +++ b/source3/winbindd/idmap_nss.c @@ -29,9 +29,9 @@ Initialise idmap database. *****************************/ -static NTSTATUS idmap_nss_int_init(struct idmap_domain *dom) +static NTSTATUS idmap_nss_int_init(struct idmap_domain *dom, + const char *params) { - dom->initialized = True; return NT_STATUS_OK; } @@ -44,10 +44,6 @@ static NTSTATUS idmap_nss_unixids_to_sids(struct idmap_domain *dom, struct id_ma TALLOC_CTX *ctx; int i; - if (! dom->initialized) { - return NT_STATUS_UNSUCCESSFUL; - } - ctx = talloc_new(dom); if ( ! ctx) { DEBUG(0, ("Out of memory!\n")); @@ -134,10 +130,6 @@ static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_ma TALLOC_CTX *ctx; int i; - if (! dom->initialized) { - return NT_STATUS_UNSUCCESSFUL; - } - ctx = talloc_new(dom); if ( ! ctx) { DEBUG(0, ("Out of memory!\n")); diff --git a/source3/winbindd/idmap_passdb.c b/source3/winbindd/idmap_passdb.c index 17afd71ab8..4dcf74416c 100644 --- a/source3/winbindd/idmap_passdb.c +++ b/source3/winbindd/idmap_passdb.c @@ -28,9 +28,8 @@ Initialise idmap database. *****************************/ -static NTSTATUS idmap_pdb_init(struct idmap_domain *dom) +static NTSTATUS idmap_pdb_init(struct idmap_domain *dom, const char *params) { - dom->initialized = True; return NT_STATUS_OK; } @@ -42,10 +41,6 @@ static NTSTATUS idmap_pdb_unixids_to_sids(struct idmap_domain *dom, struct id_ma { int i; - if (! dom->initialized) { - return NT_STATUS_UNSUCCESSFUL; - } - for (i = 0; ids[i]; i++) { /* unmapped by default */ @@ -78,10 +73,6 @@ static NTSTATUS idmap_pdb_sids_to_unixids(struct idmap_domain *dom, struct id_ma { int i; - if (! dom->initialized) { - return NT_STATUS_UNSUCCESSFUL; - } - for (i = 0; ids[i]; i++) { enum lsa_SidType type; union unid_t id; diff --git a/source3/winbindd/idmap_rid.c b/source3/winbindd/idmap_rid.c index f1cd77853c..9d1898708c 100644 --- a/source3/winbindd/idmap_rid.c +++ b/source3/winbindd/idmap_rid.c @@ -36,7 +36,8 @@ struct idmap_rid_context { we support multiple domains in the new idmap *****************************************************************************/ -static NTSTATUS idmap_rid_initialize(struct idmap_domain *dom) +static NTSTATUS idmap_rid_initialize(struct idmap_domain *dom, + const char *params) { NTSTATUS ret; struct idmap_rid_context *ctx; @@ -95,7 +96,6 @@ static NTSTATUS idmap_rid_initialize(struct idmap_domain *dom) ctx->domain_name = talloc_strdup( ctx, dom->name ); dom->private_data = ctx; - dom->initialized = True; talloc_free(config_option); return NT_STATUS_OK; @@ -171,14 +171,6 @@ static NTSTATUS idmap_rid_unixids_to_sids(struct idmap_domain *dom, struct id_ma NTSTATUS ret; int i; - /* Initilization my have been deferred because of an error, retry or fail */ - if ( ! dom->initialized) { - ret = idmap_rid_initialize(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - return ret; - } - } - ridctx = talloc_get_type(dom->private_data, struct idmap_rid_context); ctx = talloc_new(dom); @@ -213,14 +205,6 @@ static NTSTATUS idmap_rid_sids_to_unixids(struct idmap_domain *dom, struct id_ma NTSTATUS ret; int i; - /* Initilization my have been deferred because of an error, retry or fail */ - if ( ! dom->initialized) { - ret = idmap_rid_initialize(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - return ret; - } - } - ridctx = talloc_get_type(dom->private_data, struct idmap_rid_context); ctx = talloc_new(dom); diff --git a/source3/winbindd/idmap_tdb.c b/source3/winbindd/idmap_tdb.c index e5f605361b..3f6cccd35a 100644 --- a/source3/winbindd/idmap_tdb.c +++ b/source3/winbindd/idmap_tdb.c @@ -585,7 +585,7 @@ struct idmap_tdb_context { Initialise idmap database. *****************************/ -static NTSTATUS idmap_tdb_db_init(struct idmap_domain *dom) +static NTSTATUS idmap_tdb_db_init(struct idmap_domain *dom, const char *params) { NTSTATUS ret; struct idmap_tdb_context *ctx; @@ -619,7 +619,6 @@ static NTSTATUS idmap_tdb_db_init(struct idmap_domain *dom) } dom->private_data = ctx; - dom->initialized = True; talloc_free(config_option); return NT_STATUS_OK; @@ -774,14 +773,6 @@ static NTSTATUS idmap_tdb_unixids_to_sids(struct idmap_domain *dom, struct id_ma NTSTATUS ret; int i; - /* make sure we initialized */ - if ( ! dom->initialized) { - ret = idmap_tdb_db_init(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - return ret; - } - } - ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context); for (i = 0; ids[i]; i++) { @@ -820,14 +811,6 @@ static NTSTATUS idmap_tdb_sids_to_unixids(struct idmap_domain *dom, struct id_ma NTSTATUS ret; int i; - /* make sure we initialized */ - if ( ! dom->initialized) { - ret = idmap_tdb_db_init(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - return ret; - } - } - ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context); for (i = 0; ids[i]; i++) { @@ -868,14 +851,6 @@ static NTSTATUS idmap_tdb_set_mapping(struct idmap_domain *dom, const struct id_ char *ksidstr, *kidstr; fstring tmp; - /* make sure we initialized */ - if ( ! dom->initialized) { - ret = idmap_tdb_db_init(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - return ret; - } - } - if (!map || !map->sid) { return NT_STATUS_INVALID_PARAMETER; } @@ -983,14 +958,6 @@ static NTSTATUS idmap_tdb_remove_mapping(struct idmap_domain *dom, const struct char *ksidstr, *kidstr; fstring tmp; - /* make sure we initialized */ - if ( ! dom->initialized) { - ret = idmap_tdb_db_init(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - return ret; - } - } - if (!map || !map->sid) { return NT_STATUS_INVALID_PARAMETER; } @@ -1171,14 +1138,6 @@ static NTSTATUS idmap_tdb_dump_data(struct idmap_domain *dom, struct id_map **ma struct dump_data *data; NTSTATUS ret = NT_STATUS_OK; - /* make sure we initialized */ - if ( ! dom->initialized) { - ret = idmap_tdb_db_init(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - return ret; - } - } - ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context); data = TALLOC_ZERO_P(ctx, struct dump_data); @@ -1229,6 +1188,8 @@ NTSTATUS idmap_tdb_init(void) { NTSTATUS ret; + DEBUG(10, ("calling idmap_tdb_init\n")); + /* FIXME: bad hack to actually register also the alloc_tdb module without changining configure.in */ ret = idmap_alloc_tdb_init(); if (! NT_STATUS_IS_OK(ret)) { diff --git a/source3/winbindd/idmap_tdb2.c b/source3/winbindd/idmap_tdb2.c index ab89e615f7..d30b6459fb 100644 --- a/source3/winbindd/idmap_tdb2.c +++ b/source3/winbindd/idmap_tdb2.c @@ -431,7 +431,8 @@ static NTSTATUS tdb2_delete_bystring(const char *keystr) /* Initialise idmap database. */ -static NTSTATUS idmap_tdb2_db_init(struct idmap_domain *dom) +static NTSTATUS idmap_tdb2_db_init(struct idmap_domain *dom, + const char *params) { NTSTATUS ret; struct idmap_tdb2_context *ctx; @@ -464,7 +465,6 @@ static NTSTATUS idmap_tdb2_db_init(struct idmap_domain *dom) } dom->private_data = ctx; - dom->initialized = True; talloc_free(config_option); return NT_STATUS_OK; @@ -725,14 +725,6 @@ static NTSTATUS idmap_tdb2_unixids_to_sids(struct idmap_domain *dom, struct id_m NTSTATUS ret; int i; - /* make sure we initialized */ - if ( ! dom->initialized) { - ret = idmap_tdb2_db_init(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - return ret; - } - } - ctx = talloc_get_type(dom->private_data, struct idmap_tdb2_context); for (i = 0; ids[i]; i++) { @@ -770,14 +762,6 @@ static NTSTATUS idmap_tdb2_sids_to_unixids(struct idmap_domain *dom, struct id_m NTSTATUS ret; int i; - /* make sure we initialized */ - if ( ! dom->initialized) { - ret = idmap_tdb2_db_init(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - return ret; - } - } - ctx = talloc_get_type(dom->private_data, struct idmap_tdb2_context); for (i = 0; ids[i]; i++) { @@ -819,14 +803,6 @@ static NTSTATUS idmap_tdb2_set_mapping(struct idmap_domain *dom, const struct id struct db_record *update_lock = NULL; struct db_record *rec = NULL; - /* make sure we initialized */ - if ( ! dom->initialized) { - ret = idmap_tdb2_db_init(dom); - if ( ! NT_STATUS_IS_OK(ret)) { - return ret; - } - } - if (!map || !map->sid) { return NT_STATUS_INVALID_PARAMETER; } diff --git a/source3/winbindd/idmap_util.c b/source3/winbindd/idmap_util.c index 31b9895224..04d12944e2 100644 --- a/source3/winbindd/idmap_util.c +++ b/source3/winbindd/idmap_util.c @@ -27,28 +27,50 @@ If mapping is not possible returns an error. *****************************************************************/ -NTSTATUS idmap_uid_to_sid(DOM_SID *sid, uid_t uid) +NTSTATUS idmap_uid_to_sid(const char *domname, DOM_SID *sid, uid_t uid) { NTSTATUS ret; struct id_map map; + bool expired; DEBUG(10,("uid = [%lu]\n", (unsigned long)uid)); + if (idmap_cache_find_uid2sid(uid, sid, &expired)) { + DEBUG(10, ("idmap_cache_find_uid2sid found %d%s\n", uid, + expired ? " (expired)": "")); + if (expired && idmap_is_online()) { + DEBUG(10, ("revalidating expired entry\n")); + goto backend; + } + if (is_null_sid(sid)) { + DEBUG(10, ("Returning negative cache entry\n")); + return NT_STATUS_NONE_MAPPED; + } + DEBUG(10, ("Returning positive cache entry\n")); + return NT_STATUS_OK; + } + +backend: map.sid = sid; map.xid.type = ID_TYPE_UID; map.xid.id = uid; - ret = idmap_backends_unixid_to_sid(&map); + ret = idmap_backends_unixid_to_sid(domname, &map); if ( ! NT_STATUS_IS_OK(ret)) { DEBUG(10, ("error mapping uid [%lu]\n", (unsigned long)uid)); return ret; } if (map.status != ID_MAPPED) { + struct dom_sid null_sid; + ZERO_STRUCT(null_sid); + idmap_cache_set_sid2uid(&null_sid, uid); DEBUG(10, ("uid [%lu] not mapped\n", (unsigned long)uid)); return NT_STATUS_NONE_MAPPED; } + idmap_cache_set_sid2uid(sid, uid); + return NT_STATUS_OK; } @@ -57,28 +79,50 @@ NTSTATUS idmap_uid_to_sid(DOM_SID *sid, uid_t uid) If mapping is not possible returns an error. *****************************************************************/ -NTSTATUS idmap_gid_to_sid(DOM_SID *sid, gid_t gid) +NTSTATUS idmap_gid_to_sid(const char *domname, DOM_SID *sid, gid_t gid) { NTSTATUS ret; struct id_map map; + bool expired; DEBUG(10,("gid = [%lu]\n", (unsigned long)gid)); + if (idmap_cache_find_uid2sid(gid, sid, &expired)) { + DEBUG(10, ("idmap_cache_find_gid2sid found %d%s\n", gid, + expired ? " (expired)": "")); + if (expired && idmap_is_online()) { + DEBUG(10, ("revalidating expired entry\n")); + goto backend; + } + if (is_null_sid(sid)) { + DEBUG(10, ("Returning negative cache entry\n")); + return NT_STATUS_NONE_MAPPED; + } + DEBUG(10, ("Returning positive cache entry\n")); + return NT_STATUS_OK; + } + +backend: map.sid = sid; map.xid.type = ID_TYPE_GID; map.xid.id = gid; - ret = idmap_backends_unixid_to_sid(&map); + ret = idmap_backends_unixid_to_sid(domname, &map); if ( ! NT_STATUS_IS_OK(ret)) { DEBUG(10, ("error mapping gid [%lu]\n", (unsigned long)gid)); return ret; } if (map.status != ID_MAPPED) { + struct dom_sid null_sid; + ZERO_STRUCT(null_sid); + idmap_cache_set_sid2uid(&null_sid, gid); DEBUG(10, ("gid [%lu] not mapped\n", (unsigned long)gid)); return NT_STATUS_NONE_MAPPED; } + idmap_cache_set_sid2uid(sid, gid); + return NT_STATUS_OK; } @@ -87,34 +131,61 @@ NTSTATUS idmap_gid_to_sid(DOM_SID *sid, gid_t gid) If mapping is not possible or SID maps to a GID returns an error. *****************************************************************/ -NTSTATUS idmap_sid_to_uid(DOM_SID *sid, uid_t *uid) +NTSTATUS idmap_sid_to_uid(const char *dom_name, DOM_SID *sid, uid_t *uid) { NTSTATUS ret; struct id_map map; + bool expired; DEBUG(10,("idmap_sid_to_uid: sid = [%s]\n", sid_string_dbg(sid))); + if (idmap_cache_find_sid2uid(sid, uid, &expired)) { + DEBUG(10, ("idmap_cache_find_sid2uid found %d%s\n", + (int)(*uid), expired ? " (expired)": "")); + if (expired && idmap_is_online()) { + DEBUG(10, ("revalidating expired entry\n")); + goto backend; + } + if ((*uid) == -1) { + DEBUG(10, ("Returning negative cache entry\n")); + return NT_STATUS_NONE_MAPPED; + } + DEBUG(10, ("Returning positive cache entry\n")); + return NT_STATUS_OK; + } + +backend: map.sid = sid; map.xid.type = ID_TYPE_UID; - ret = idmap_backends_sid_to_unixid(&map); - if ( ! NT_STATUS_IS_OK(ret)) { - DEBUG(10, ("error mapping sid [%s] to uid\n", - sid_string_dbg(sid))); - return ret; + ret = idmap_backends_sid_to_unixid(dom_name, &map); + + if (NT_STATUS_IS_OK(ret) && (map.status == ID_MAPPED)) { + if (map.xid.type != ID_TYPE_UID) { + DEBUG(10, ("sid [%s] not mapped to a uid " + "[%u,%u,%u]\n", + sid_string_dbg(sid), + map.status, + map.xid.type, + map.xid.id)); + idmap_cache_set_sid2uid(sid, -1); + return NT_STATUS_NONE_MAPPED; + } + goto done; } - if ((map.status != ID_MAPPED) || (map.xid.type != ID_TYPE_UID)) { - DEBUG(10, ("sid [%s] not mapped to an uid [%u,%u,%u]\n", - sid_string_dbg(sid), - map.status, - map.xid.type, - map.xid.id)); - return NT_STATUS_NONE_MAPPED; - } + ret = idmap_new_mapping(sid, ID_TYPE_UID, &map.xid); - *uid = map.xid.id; + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(10, ("idmap_new_mapping failed: %s\n", + nt_errstr(ret))); + idmap_cache_set_sid2uid(sid, -1); + return ret; + } +done: + *uid = (uid_t)map.xid.id; + idmap_cache_set_sid2uid(sid, *uid); return NT_STATUS_OK; } @@ -123,32 +194,59 @@ NTSTATUS idmap_sid_to_uid(DOM_SID *sid, uid_t *uid) If mapping is not possible or SID maps to a UID returns an error. *****************************************************************/ -NTSTATUS idmap_sid_to_gid(DOM_SID *sid, gid_t *gid) +NTSTATUS idmap_sid_to_gid(const char *domname, DOM_SID *sid, gid_t *gid) { NTSTATUS ret; struct id_map map; + bool expired; DEBUG(10,("idmap_sid_to_gid: sid = [%s]\n", sid_string_dbg(sid))); + if (idmap_cache_find_sid2gid(sid, gid, &expired)) { + DEBUG(10, ("idmap_cache_find_sid2gid found %d%s\n", + (int)(*gid), expired ? " (expired)": "")); + if (expired && idmap_is_online()) { + DEBUG(10, ("revalidating expired entry\n")); + goto backend; + } + if ((*gid) == -1) { + DEBUG(10, ("Returning negative cache entry\n")); + return NT_STATUS_NONE_MAPPED; + } + DEBUG(10, ("Returning positive cache entry\n")); + return NT_STATUS_OK; + } + +backend: map.sid = sid; map.xid.type = ID_TYPE_GID; - ret = idmap_backends_sid_to_unixid(&map); - if ( ! NT_STATUS_IS_OK(ret)) { - DEBUG(10, ("error mapping sid [%s] to gid\n", - sid_string_dbg(sid))); - return ret; + ret = idmap_backends_sid_to_unixid(domname, &map); + if (NT_STATUS_IS_OK(ret) && (map.status == ID_MAPPED)) { + if (map.xid.type != ID_TYPE_GID) { + DEBUG(10, ("sid [%s] not mapped to a gid " + "[%u,%u,%u]\n", + sid_string_dbg(sid), + map.status, + map.xid.type, + map.xid.id)); + idmap_cache_set_sid2gid(sid, -1); + return NT_STATUS_NONE_MAPPED; + } + goto done; } - if ((map.status != ID_MAPPED) || (map.xid.type != ID_TYPE_GID)) { - DEBUG(10, ("sid [%s] not mapped to a gid [%u,%u]\n", - sid_string_dbg(sid), - map.status, - map.xid.type)); - return NT_STATUS_NONE_MAPPED; + ret = idmap_new_mapping(sid, ID_TYPE_GID, &map.xid); + + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(10, ("idmap_new_mapping failed: %s\n", + nt_errstr(ret))); + idmap_cache_set_sid2gid(sid, -1); + return ret; } +done: *gid = map.xid.id; - + idmap_cache_set_sid2gid(sid, *gid); return NT_STATUS_OK; } diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c index 08cf8ba00a..ec20d8c195 100644 --- a/source3/winbindd/winbindd.c +++ b/source3/winbindd/winbindd.c @@ -1144,12 +1144,6 @@ int main(int argc, char **argv, char **envp) namecache_enable(); - /* Winbind daemon initialisation */ - - if ( ! NT_STATUS_IS_OK(idmap_init_cache()) ) { - DEBUG(1, ("Could not init idmap cache!\n")); - } - /* Unblock all signals we are interested in as they may have been blocked by the parent process. */ diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h index f6f269ee6d..fe0c076209 100644 --- a/source3/winbindd/winbindd.h +++ b/source3/winbindd/winbindd.h @@ -196,6 +196,13 @@ struct winbindd_domain { void *private_data; + /* + * idmap config settings, used to tell the idmap child which + * special domain config to use for a mapping + */ + bool have_idmap_config; + uint32_t id_range_low, id_range_high; + /* A working DC */ fstring dcname; struct sockaddr_storage dcaddr; diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c index f2be6d692c..1e8325f983 100644 --- a/source3/winbindd/winbindd_dual.c +++ b/source3/winbindd/winbindd_dual.c @@ -1033,6 +1033,8 @@ static bool fork_domain_child(struct winbindd_child *child) /* Child */ + DEBUG(10, ("Child process %d\n", (int)sys_getpid())); + /* Stop zombies in children */ CatchChild(); diff --git a/source3/winbindd/winbindd_group.c b/source3/winbindd/winbindd_group.c index 69e3a6a555..21ee8951b5 100644 --- a/source3/winbindd/winbindd_group.c +++ b/source3/winbindd/winbindd_group.c @@ -231,7 +231,8 @@ static bool fill_grent_mem_domusers( TALLOC_CTX *mem_ctx, if (sys_getpeereid(state->sock, &ret_uid)==0) { /* We know who's asking - look up their SID if it's one we've mapped before. */ - status = idmap_uid_to_sid(&querying_user_sid, ret_uid); + status = idmap_uid_to_sid(domain->name, + &querying_user_sid, ret_uid); if (NT_STATUS_IS_OK(status)) { pquerying_user_sid = &querying_user_sid; DEBUG(10,("fill_grent_mem_domain_users: " @@ -1224,7 +1225,8 @@ void winbindd_getgrent(struct winbindd_cli_state *state) sid_copy(&group_sid, &domain->sid); sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid); - if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid))) { + if (!NT_STATUS_IS_OK(idmap_sid_to_gid(domain->name, &group_sid, + &group_gid))) { union unid_t id; enum lsa_SidType type; diff --git a/source3/winbindd/winbindd_idmap.c b/source3/winbindd/winbindd_idmap.c index 41782ff0d1..d8c67dc21c 100644 --- a/source3/winbindd/winbindd_idmap.c +++ b/source3/winbindd/winbindd_idmap.c @@ -197,8 +197,28 @@ void winbindd_sid2uid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid, void *private_data) { struct winbindd_request request; + struct winbindd_domain *domain; + ZERO_STRUCT(request); request.cmd = WINBINDD_DUAL_SID2UID; + + domain = find_domain_from_sid(sid); + + if (domain != NULL) { + DEBUG(10, ("winbindd_sid2uid_async found domain %s, " + "have_idmap_config = %d\n", domain->name, + (int)domain->have_idmap_config)); + + } + else { + DEBUG(10, ("winbindd_sid2uid_async did not find a domain for " + "%s\n", sid_string_dbg(sid))); + } + + if ((domain != NULL) && (domain->have_idmap_config)) { + fstrcpy(request.domain_name, domain->name); + } + sid_to_fstring(request.data.dual_sid2id.sid, sid); do_async(mem_ctx, idmap_child(), &request, winbindd_sid2uid_recv, (void *)cont, private_data); @@ -219,9 +239,12 @@ enum winbindd_result winbindd_dual_sid2uid(struct winbindd_domain *domain, return WINBINDD_ERROR; } - /* Find uid for this sid and return it, possibly ask the slow remote idmap */ + result = idmap_sid_to_uid(state->request.domain_name, &sid, + &state->response.data.uid); - result = idmap_sid_to_uid(&sid, &(state->response.data.uid)); + DEBUG(10, ("winbindd_dual_sid2uid: 0x%08x - %s - %u\n", + NT_STATUS_V(result), sid_string_dbg(&sid), + state->response.data.uid)); return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; } @@ -253,8 +276,16 @@ void winbindd_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid, void *private_data) { struct winbindd_request request; + struct winbindd_domain *domain; + ZERO_STRUCT(request); request.cmd = WINBINDD_DUAL_SID2GID; + + domain = find_domain_from_sid(sid); + if ((domain != NULL) && (domain->have_idmap_config)) { + fstrcpy(request.domain_name, domain->name); + } + sid_to_fstring(request.data.dual_sid2id.sid, sid); DEBUG(7,("winbindd_sid2gid_async: Resolving %s to a gid\n", @@ -281,7 +312,8 @@ enum winbindd_result winbindd_dual_sid2gid(struct winbindd_domain *domain, /* Find gid for this sid and return it, possibly ask the slow remote idmap */ - result = idmap_sid_to_gid(&sid, &state->response.data.gid); + result = idmap_sid_to_gid(state->request.domain_name, &sid, + &state->response.data.gid); DEBUG(10, ("winbindd_dual_sid2gid: 0x%08x - %s - %u\n", NT_STATUS_V(result), sid_string_dbg(&sid), @@ -319,11 +351,21 @@ void winbindd_uid2sid_async(TALLOC_CTX *mem_ctx, uid_t uid, void (*cont)(void *private_data, bool success, const char *sid), void *private_data) { + struct winbindd_domain *domain; struct winbindd_request request; ZERO_STRUCT(request); request.cmd = WINBINDD_DUAL_UID2SID; request.data.uid = uid; + + for (domain = domain_list(); domain != NULL; domain = domain->next) { + if (domain->have_idmap_config + && (uid >= domain->id_range_low) + && (uid <= domain->id_range_high)) { + fstrcpy(request.domain_name, domain->name); + } + } + do_async(mem_ctx, idmap_child(), &request, winbindd_uid2sid_recv, (void *)cont, private_data); } @@ -339,7 +381,8 @@ enum winbindd_result winbindd_dual_uid2sid(struct winbindd_domain *domain, (unsigned long) state->request.data.uid)); /* Find sid for this uid and return it, possibly ask the slow remote idmap */ - result = idmap_uid_to_sid(&sid, state->request.data.uid); + result = idmap_uid_to_sid(state->request.domain_name, &sid, + state->request.data.uid); if (NT_STATUS_IS_OK(result)) { sid_to_fstring(state->response.data.sid.sid, &sid); @@ -376,11 +419,21 @@ void winbindd_gid2sid_async(TALLOC_CTX *mem_ctx, gid_t gid, void (*cont)(void *private_data, bool success, const char *sid), void *private_data) { + struct winbindd_domain *domain; struct winbindd_request request; ZERO_STRUCT(request); request.cmd = WINBINDD_DUAL_GID2SID; request.data.gid = gid; + + for (domain = domain_list(); domain != NULL; domain = domain->next) { + if (domain->have_idmap_config + && (gid >= domain->id_range_low) + && (gid <= domain->id_range_high)) { + fstrcpy(request.domain_name, domain->name); + } + } + do_async(mem_ctx, idmap_child(), &request, winbindd_gid2sid_recv, (void *)cont, private_data); } @@ -396,7 +449,8 @@ enum winbindd_result winbindd_dual_gid2sid(struct winbindd_domain *domain, (unsigned long) state->request.data.gid)); /* Find sid for this gid and return it, possibly ask the slow remote idmap */ - result = idmap_gid_to_sid(&sid, state->request.data.gid); + result = idmap_gid_to_sid(state->request.domain_name, &sid, + state->request.data.gid); if (NT_STATUS_IS_OK(result)) { sid_to_fstring(state->response.data.sid.sid, &sid); diff --git a/source3/winbindd/winbindd_sid.c b/source3/winbindd/winbindd_sid.c index 5f5972fb05..274786fa63 100644 --- a/source3/winbindd/winbindd_sid.c +++ b/source3/winbindd/winbindd_sid.c @@ -166,12 +166,10 @@ static void sid2uid_recv(void *private_data, bool success, uid_t uid) if (!success) { DEBUG(5, ("Could not convert sid %s\n", state->request.data.sid)); - idmap_cache_set_sid2uid(&sid, -1); request_error(state); return; } - idmap_cache_set_sid2uid(&sid, uid); state->response.data.uid = uid; request_ok(state); } @@ -209,6 +207,10 @@ static void sid2uid_lookupsid_recv( void *private_data, bool success, return; fail: + /* + * We have to set the cache ourselves here, the child which is + * normally responsible was not queried yet. + */ idmap_cache_set_sid2uid(&sid, -1); request_error(state); return; @@ -273,12 +275,10 @@ static void sid2gid_recv(void *private_data, bool success, gid_t gid) if (!success) { DEBUG(5, ("Could not convert sid %s\n", state->request.data.sid)); - idmap_cache_set_sid2gid(&sid, -1); request_error(state); return; } - idmap_cache_set_sid2gid(&sid, gid); state->response.data.gid = gid; request_ok(state); } @@ -319,6 +319,10 @@ static void sid2gid_lookupsid_recv( void *private_data, bool success, return; fail: + /* + * We have to set the cache ourselves here, the child which is + * normally responsible was not queried yet. + */ idmap_cache_set_sid2gid(&sid, -1); request_error(state); return; @@ -516,7 +520,7 @@ static void gid2sid_recv(void *private_data, bool success, const char *sidstr) return; } DEBUG(10,("gid2sid: gid %lu has sid %s\n", - (unsigned long)(state->request.data.gid), sid)); + (unsigned long)(state->request.data.gid), sidstr)); idmap_cache_set_sid2gid(&sid, state->request.data.gid); fstrcpy(state->response.data.sid.sid, sidstr); diff --git a/source3/winbindd/winbindd_user.c b/source3/winbindd/winbindd_user.c index 00e53eff74..3b6dfdda1c 100644 --- a/source3/winbindd/winbindd_user.c +++ b/source3/winbindd/winbindd_user.c @@ -79,7 +79,8 @@ static bool winbindd_fill_pwent(char *dom_name, char *user_name, /* Resolve the uid number */ - if (!NT_STATUS_IS_OK(idmap_sid_to_uid(user_sid, &pw->pw_uid))) { + if (!NT_STATUS_IS_OK(idmap_sid_to_uid(dom_name, user_sid, + &pw->pw_uid))) { DEBUG(1, ("error getting user id for sid %s\n", sid_string_dbg(user_sid))); return False; @@ -87,7 +88,8 @@ static bool winbindd_fill_pwent(char *dom_name, char *user_name, /* Resolve the gid number */ - if (!NT_STATUS_IS_OK(idmap_sid_to_gid(group_sid, &pw->pw_gid))) { + if (!NT_STATUS_IS_OK(idmap_sid_to_gid(dom_name, group_sid, + &pw->pw_gid))) { DEBUG(1, ("error getting group id for sid %s\n", sid_string_dbg(group_sid))); return False; diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c index a35ba7bc06..f1da5780aa 100644 --- a/source3/winbindd/winbindd_util.c +++ b/source3/winbindd/winbindd_util.c @@ -109,6 +109,8 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const { struct winbindd_domain *domain; const char *alternative_name = NULL; + char *idmap_config_option; + const char *param; /* ignore alt_name if we are not in an AD domain */ @@ -181,12 +183,44 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const if (sid) { sid_copy(&domain->sid, sid); } + /* Link to domain list */ DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *); wcache_tdc_add_domain( domain ); + idmap_config_option = talloc_asprintf(talloc_tos(), "idmap config %s", + domain->name); + if (idmap_config_option == NULL) { + DEBUG(0, ("talloc failed, not looking for idmap config\n")); + goto done; + } + + param = lp_parm_const_string(-1, idmap_config_option, "range", NULL); + + DEBUG(10, ("%s : range = %s\n", idmap_config_option, + param ? param : "not defined")); + + if (param != NULL) { + unsigned low_id, high_id; + if (sscanf(param, "%u - %u", &low_id, &high_id) != 2) { + DEBUG(1, ("invalid range syntax in %s: %s\n", + idmap_config_option, param)); + goto done; + } + if (low_id > high_id) { + DEBUG(1, ("invalid range in %s: %s\n", + idmap_config_option, param)); + goto done; + } + domain->have_idmap_config = true; + domain->id_range_low = low_id; + domain->id_range_high = high_id; + } + +done: + DEBUG(2,("Added domain %s %s %s\n", domain->name, domain->alt_name, &domain->sid?sid_string_dbg(&domain->sid):"")); |