Deprecated but still supported "idmap backend" actually is broken

Dmitry Butskoy buc at odusz.so-cdu.ru
Fri Oct 12 15:04:25 GMT 2007


simo wrote:
> I am still building packages to test but if you want to give it a try
> you'll find attached my first take
>   

The patch should be fixed a little.

When we change the idmap dom name from the "default domain" to the name 
of the actual primary domain (lp_workgroup()), it leads the "trusted 
domains only" feature no more work. (IOW the case of idmap_nss "hidden" 
backend).

Consider a case, when we:
- do not specify any idmap backends or idmap domains at all;
- and specify "winbind trusted domains only = yes" (for UNIX accounts 
comes from UNIX NSS).

Consider (new, patched) "nsswitch/idmap.c:idmap_init()" again:

> NTSTATUS idmap_init(void)
> {
>     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;
>
>     ret = idmap_init_cache();
>     if (!NT_STATUS_IS_OK(ret))
>         return ret;
>
>     if (NT_STATUS_IS_OK(idmap_init_status))
>         return NT_STATUS_OK;
>
>     static_init_idmap;
>
>     dom_list = lp_idmap_domains();
NULL
>
>     if ( lp_idmap_backend() ) {
false
>                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 excusive!\n"));
>             DEBUGADD(0,("idmap backend option will be IGNORED!\n"));
>         } else {
>             compat = 1;
>
>             compat_backend = talloc_strdup(idmap_ctx, *compat_list);
>             if (compat_backend == NULL) {
>                 ret = NT_STATUS_NO_MEMORY;
>                 goto done;
>             }
>
>             /* 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"o
>                       "Please replace 'idmap_%s' by '%s' in"
>                       " %s\n", q, q, dyn_CONFIGFILE));
>                 compat_backend = talloc_strdup(idmap_ctx, q);
>             } else {
>                 compat_backend = talloc_strdup(idmap_ctx,
>                                 *compat_list);
>             }
>
>             /* separate the backend and module arguements */
>             if ((p = strchr(compat_backend, ':')) != NULL) {
>                 *p = '\0';
>                 compat_params = p + 1;
>             }
>         }
>     } else if ( !dom_list ) {
yes
>         /* 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;
>     }
>
>     if ( ! dom_list) {
yes, again...
>         /* generate a list with our main domain */
>         char ** dl;
>
>         dl = talloc_array(idmap_ctx, char *, 2);
>         if (dl == NULL) {
>             ret = NT_STATUS_NO_MEMORY;
>             goto done;
>         }
>         dl[0] = talloc_strdup(dl, lp_workgroup());
>         if (dl[0] == NULL) {Consider (new, patched)
>             ret = NT_STATUS_NO_MEMORY;
>             goto done;
>         }
>
>         /* terminate */
>         dl[1] = NULL;
>
>         dom_list = dl;
>         default_domain = dl[0];
...and now default_domain == lp_workgroup()
>     }
>
>     /***************************
>      * initialize idmap domains
>      */
>     DEBUG(1, ("Initializing idmap domains\n"));
>
>     for (i = 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 invalid domain %s\n",
>                  dom_list[i]));
>             continue;
>         }
>
>         if (strequal(dom_list[i], lp_workgroup())) {
>             pri_dom_is_in_list = True;
yes, it is True now, but was False before the patch applied (when 
dom_list[i] was "default domain")
>         }
>         /* 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 {
>             char *backend = lp_parm_const_string(-1, config_option,
>                                  "backend", "tdb");
>             parm_backend = talloc_strdup(idmap_ctx,    backend);
>         }
>         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);
>
>         if (compat_params) {
>             dom->params = talloc_strdup(dom, compat_params);
>             IDMAP_CHECK_ALLOC(dom->params);
>         } else {
>             dom->params = NULL;
>         }
>
>         /* 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[i] = dom;
>
>         /* save default domain position for future uses */
>         if (dom->default_domain) {
>             def_dom_num = i;
>         }
>
>         DEBUG(10, ("Domain %s - Backend %s - %sdefault - %sreadonly\n",
>                 dom->name, parm_backend,
>                 dom->default_domain?"":"not ",
>                 dom->readonly?"":"not "));
>
>         talloc_free(config_option);
>     }
>
>     /* save the number of domains we have */
>     num_domains = i;
>
>     /* automatically add idmap_nss backend if needed */
>     if ((lp_server_role() == ROLE_DOMAIN_MEMBER) &&
>         ( ! pri_dom_is_in_list) &&
Oops! Before the patch "( ! pri_dom_is_in_list)" was True (then 
idmap_nss inited etc.), now it is False!
>         lp_winbind_trusted_domains_only()) {
>
>         dom = TALLOC_ZERO_P(idmap_ctx, struct idmap_domain);
>         IDMAP_CHECK_ALLOC(dom);
>
>         dom->name = talloc_strdup(dom, lp_workgroup());
>         IDMAP_CHECK_ALLOC(dom->name);
>
>         dom->default_domain = False;
>         dom->readonly = True;
>
>         /* get the backend methods for passdb */
>         dom->methods = get_methods(backends, "nss");
[snip]

IOW, now by default (when both "idmap backend" and "idmap domains" are 
empty), the "pri_dom_is_in_list" is always True, which prevents the 
using of "winbind trusted domains only = yes" feature...


~buc






More information about the samba-technical mailing list