s3-talloc Change TALLOC_ARRAY() to talloc_array()
[samba.git] / source3 / winbindd / idmap.c
index 3e7be8cb7abcb9efdb1f9bd375b2844337b67e5f..6ae10115b7813b4a1497faddac72cbedede3790c 100644 (file)
@@ -5,6 +5,7 @@
    Copyright (C) Jim McDonough <jmcd@us.ibm.com>       2003
    Copyright (C) Simo Sorce 2003-2007
    Copyright (C) Jeremy Allison 2006
+   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
 
 #include "includes.h"
 #include "winbindd.h"
+#include "idmap.h"
+#include "passdb/machine_sid.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_IDMAP
 
 static_decl_idmap;
 
+static void idmap_init(void)
+{
+       static bool initialized;
+
+       if (initialized) {
+               return;
+       }
+
+       DEBUG(10, ("idmap_init(): calling static_init_idmap\n"));
+
+       static_init_idmap;
+
+       initialized = true;
+}
+
 /**
  * Pointer to the backend methods. Modules register themselves here via
  * smb_register_idmap.
@@ -40,27 +58,6 @@ struct idmap_backend {
 };
 static struct idmap_backend *backends = NULL;
 
-/**
- * Pointer to the alloc backend methods. Modules register themselves here via
- * smb_register_idmap_alloc.
- */
-struct idmap_alloc_backend {
-       const char *name;
-       struct idmap_alloc_methods *methods;
-       struct idmap_alloc_backend *prev, *next;
-};
-static struct idmap_alloc_backend *alloc_backends = NULL;
-
-/**
- * The idmap alloc context that is configured via "idmap alloc
- * backend". Defaults to "idmap backend" in case the module (tdb, ldap) also
- * provides alloc methods.
- */
-struct idmap_alloc_context {
-       struct idmap_alloc_methods *methods;
-};
-static struct idmap_alloc_context *idmap_alloc_ctx = NULL;
-
 /**
  * Default idmap domain configured via "idmap backend".
  */
@@ -94,19 +91,6 @@ static struct idmap_methods *get_methods(const char *name)
        return NULL;
 }
 
-static struct idmap_alloc_methods *get_alloc_methods(const char *name)
-{
-       struct idmap_alloc_backend *b;
-
-       for (b = alloc_backends; b; b = b->next) {
-               if (strequal(b->name, name)) {
-                       return b->methods;
-               }
-       }
-
-       return NULL;
-}
-
 bool idmap_is_offline(void)
 {
        return ( lp_winbind_offline_logon() &&
@@ -170,120 +154,23 @@ NTSTATUS smb_register_idmap(int version, const char *name,
        return NT_STATUS_OK;
 }
 
-/**********************************************************************
- Allow a module to register itself as an alloc method.
-**********************************************************************/
-
-NTSTATUS smb_register_idmap_alloc(int version, const char *name,
-                                 struct idmap_alloc_methods *methods)
-{
-       struct idmap_alloc_methods *test;
-       struct idmap_alloc_backend *entry;
-
-       if ((version != SMB_IDMAP_INTERFACE_VERSION)) {
-               DEBUG(0, ("Failed to register idmap alloc module.\n"
-                         "The module was compiled against "
-                         "SMB_IDMAP_INTERFACE_VERSION %d,\n"
-                         "current SMB_IDMAP_INTERFACE_VERSION is %d.\n"
-                         "Please recompile against the current version "
-                         "of samba!\n",
-                         version, SMB_IDMAP_INTERFACE_VERSION));
-               return NT_STATUS_OBJECT_TYPE_MISMATCH;
-       }
-
-       if (!name || !name[0] || !methods) {
-               DEBUG(0,("Called with NULL pointer or empty name!\n"));
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-       test = get_alloc_methods(name);
-       if (test) {
-               DEBUG(0,("idmap_alloc module %s already registered!\n", name));
-               return NT_STATUS_OBJECT_NAME_COLLISION;
-       }
-
-       entry = talloc(NULL, struct idmap_alloc_backend);
-       if ( ! entry) {
-               DEBUG(0,("Out of memory!\n"));
-               return NT_STATUS_NO_MEMORY;
-       }
-       entry->name = talloc_strdup(entry, name);
-       if ( ! entry->name) {
-               DEBUG(0,("Out of memory!\n"));
-               return NT_STATUS_NO_MEMORY;
-       }
-       entry->methods = methods;
-
-       DLIST_ADD(alloc_backends, entry);
-       DEBUG(5, ("Successfully added idmap alloc backend '%s'\n", name));
-       return NT_STATUS_OK;
-}
-
-static int close_domain_destructor(struct idmap_domain *dom)
-{
-       NTSTATUS ret;
-
-       ret = dom->methods->close_fn(dom);
-       if (!NT_STATUS_IS_OK(ret)) {
-               DEBUG(3, ("Failed to close idmap domain [%s]!\n", dom->name));
-       }
-
-       return 0;
-}
-
-static bool parse_idmap_module(TALLOC_CTX *mem_ctx, const char *param,
-                              char **pmodulename, char **pargs)
-{
-       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));
-       }
-
-       modulename = talloc_strdup(mem_ctx, param);
-       if (modulename == NULL) {
-               return false;
-       }
-
-       args = strchr(modulename, ':');
-       if (args == NULL) {
-               *pmodulename = modulename;
-               *pargs = NULL;
-               return true;
-       }
-
-       *args = '\0';
-
-       args = talloc_strdup(mem_ctx, args+1);
-       if (args == NULL) {
-               TALLOC_FREE(modulename);
-               return false;
-       }
-
-       *pmodulename = modulename;
-       *pargs = args;
-       return true;
-}
-
 /**
  * Initialize a domain structure
  * @param[in] mem_ctx          memory context for the result
  * @param[in] domainname       which domain is this for
  * @param[in] modulename       which backend module
- * @param[in] params           parameter to pass to the init function
+ * @param[in] check_range      whether range checking should be done
  * @result The initialized structure
  */
 static struct idmap_domain *idmap_init_domain(TALLOC_CTX *mem_ctx,
                                              const char *domainname,
                                              const char *modulename,
-                                             const char *params)
+                                             bool check_range)
 {
        struct idmap_domain *result;
        NTSTATUS status;
+       char *config_option = NULL;
+       const char *range;
 
        result = talloc_zero(mem_ctx, struct idmap_domain);
        if (result == NULL) {
@@ -297,6 +184,47 @@ static struct idmap_domain *idmap_init_domain(TALLOC_CTX *mem_ctx,
                goto fail;
        }
 
+       /*
+        * load ranges and read only information from the config
+        */
+
+       config_option = talloc_asprintf(result, "idmap config %s",
+                                       result->name);
+       if (config_option == NULL) {
+               DEBUG(0, ("Out of memory!\n"));
+               goto fail;
+       }
+
+       range = lp_parm_const_string(-1, config_option, "range", NULL);
+       if (range == NULL) {
+               DEBUG(1, ("idmap range not specified for domain %s\n",
+                         result->name));
+               if (check_range) {
+                       goto fail;
+               }
+       } else if (sscanf(range, "%u - %u", &result->low_id,
+                         &result->high_id) != 2)
+       {
+               DEBUG(1, ("invalid range '%s' specified for domain "
+                         "'%s'\n", range, result->name));
+               if (check_range) {
+                       goto fail;
+               }
+       }
+
+       result->read_only = lp_parm_bool(-1, config_option, "read only", false);
+
+       talloc_free(config_option);
+
+       if (result->low_id > result->high_id) {
+               DEBUG(1, ("Error: invalid idmap range detected: %lu - %lu\n",
+                         (unsigned long)result->low_id,
+                         (unsigned long)result->high_id));
+               if (check_range) {
+                       goto fail;
+               }
+       }
+
        result->methods = get_methods(modulename);
        if (result->methods == NULL) {
                DEBUG(3, ("idmap backend %s not found\n", modulename));
@@ -315,61 +243,16 @@ static struct idmap_domain *idmap_init_domain(TALLOC_CTX *mem_ctx,
                goto fail;
        }
 
-       status = result->methods->init(result, params);
+       status = result->methods->init(result);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("idmap initialization returned %s\n",
                          nt_errstr(status)));
                goto fail;
        }
 
-       talloc_set_destructor(result, close_domain_destructor);
-
-       return result;
-
-fail:
-       TALLOC_FREE(result);
-       return NULL;
-}
-
-/**
- * Initialize the default domain structure
- * @param[in] mem_ctx          memory context for the result
- * @result The default domain structure
- *
- * This routine takes the module name from the "idmap backend" parameter,
- * passing a possible parameter like ldap:ldap://ldap-url/ to the module.
- */
-
-static struct idmap_domain *idmap_init_default_domain(TALLOC_CTX *mem_ctx)
-{
-       struct idmap_domain *result;
-       char *modulename;
-       char *params;
-
-       DEBUG(10, ("idmap_init_default_domain: calling static_init_idmap\n"));
-
-       static_init_idmap;
-
-       if (!parse_idmap_module(talloc_tos(), lp_idmap_backend(), &modulename,
-                               &params)) {
-               DEBUG(1, ("parse_idmap_module failed\n"));
-               return NULL;
-       }
-
-       DEBUG(3, ("idmap_init: using '%s' as remote backend\n", modulename));
-
-       result = idmap_init_domain(mem_ctx, "*", modulename, params);
-       if (result == NULL) {
-               goto fail;
-       }
-
-       TALLOC_FREE(modulename);
-       TALLOC_FREE(params);
        return result;
 
 fail:
-       TALLOC_FREE(modulename);
-       TALLOC_FREE(params);
        TALLOC_FREE(result);
        return NULL;
 }
@@ -391,6 +274,8 @@ static struct idmap_domain *idmap_init_named_domain(TALLOC_CTX *mem_ctx,
        char *config_option;
        const char *backend;
 
+       idmap_init();
+
        config_option = talloc_asprintf(talloc_tos(), "idmap config %s",
                                        domname);
        if (config_option == NULL) {
@@ -404,7 +289,7 @@ static struct idmap_domain *idmap_init_named_domain(TALLOC_CTX *mem_ctx,
                goto fail;
        }
 
-       result = idmap_init_domain(mem_ctx, domname, backend, NULL);
+       result = idmap_init_domain(mem_ctx, domname, backend, true);
        if (result == NULL) {
                goto fail;
        }
@@ -418,6 +303,20 @@ fail:
        return NULL;
 }
 
+/**
+ * Initialize the default domain structure
+ * @param[in] mem_ctx          memory context for the result
+ * @result The default domain structure
+ *
+ * This routine takes the module name from the "idmap backend" parameter,
+ * passing a possible parameter like ldap:ldap://ldap-url/ to the module.
+ */
+
+static struct idmap_domain *idmap_init_default_domain(TALLOC_CTX *mem_ctx)
+{
+       return idmap_init_named_domain(mem_ctx, "*");
+}
+
 /**
  * Initialize the passdb domain structure
  * @param[in] mem_ctx          memory context for the result
@@ -428,12 +327,24 @@ fail:
 
 static struct idmap_domain *idmap_init_passdb_domain(TALLOC_CTX *mem_ctx)
 {
+       idmap_init();
+
+       /*
+        * 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;
+       }
+
        if (passdb_idmap_domain != NULL) {
                return passdb_idmap_domain;
        }
 
        passdb_idmap_domain = idmap_init_domain(NULL, get_global_sam_name(),
-                                               "passdb", NULL);
+                                               "passdb", false);
        if (passdb_idmap_domain == NULL) {
                DEBUG(1, ("Could not init passdb idmap domain\n"));
        }
@@ -456,7 +367,7 @@ static struct idmap_domain *idmap_init_passdb_domain(TALLOC_CTX *mem_ctx)
  * add_trusted_domain.
  */
 
-static struct idmap_domain *idmap_find_domain(const char *domname)
+struct idmap_domain *idmap_find_domain(const char *domname)
 {
        struct idmap_domain *result;
        int i;
@@ -464,6 +375,8 @@ static struct idmap_domain *idmap_find_domain(const char *domname)
        DEBUG(10, ("idmap_find_domain called for domain '%s'\n",
                   domname?domname:"NULL"));
 
+       idmap_init();
+
        /*
         * Always init the default domain, we can't go without one
         */
@@ -488,7 +401,7 @@ static struct idmap_domain *idmap_find_domain(const char *domname)
                /*
                 * talloc context for all idmap domains
                 */
-               idmap_domains = TALLOC_ARRAY(NULL, struct idmap_domain *, 1);
+               idmap_domains = talloc_array(NULL, struct idmap_domain *, 1);
        }
 
        if (idmap_domains == NULL) {
@@ -511,216 +424,47 @@ static struct idmap_domain *idmap_find_domain(const char *domname)
 
 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;
 }
 
-/**
- * Initialize the idmap alloc backend
- * @param[out] ctx             Where to put the alloc_ctx?
- * @result Did it work fine?
- *
- * This routine first looks at "idmap alloc backend" and if that is not
- * defined, it uses "idmap backend" for the module name.
- */
-static NTSTATUS idmap_alloc_init(struct idmap_alloc_context **ctx)
-{
-       const char *backend;
-       char *modulename, *params;
-       NTSTATUS ret = NT_STATUS_NO_MEMORY;;
-
-       if (idmap_alloc_ctx != NULL) {
-               *ctx = idmap_alloc_ctx;
-               return NT_STATUS_OK;
-       }
-
-       idmap_alloc_ctx = talloc(NULL, struct idmap_alloc_context);
-       if (idmap_alloc_ctx == NULL) {
-               DEBUG(0, ("talloc failed\n"));
-               goto fail;
-       }
-
-       backend = lp_idmap_alloc_backend();
-       if ((backend == NULL) || (backend[0] == '\0')) {
-               backend = lp_idmap_backend();
-       }
-
-       if (backend == NULL) {
-               DEBUG(3, ("no idmap alloc backend defined\n"));
-               ret = NT_STATUS_INVALID_PARAMETER;
-               goto fail;
-       }
+/**************************************************************************
+ idmap allocator interface functions
+**************************************************************************/
 
-       if (!parse_idmap_module(idmap_alloc_ctx, backend, &modulename,
-                               &params)) {
-               DEBUG(1, ("parse_idmap_module %s failed\n", backend));
-               goto fail;
-       }
+static NTSTATUS idmap_allocate_unixid(struct unixid *id)
+{
+       struct idmap_domain *dom;
+       NTSTATUS ret;
 
-       idmap_alloc_ctx->methods = get_alloc_methods(modulename);
+       dom = idmap_find_domain(NULL);
 
-       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(modulename);
-               }
+       if (dom == NULL) {
+               return 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;
+       if (dom->methods->allocate_id == NULL) {
+               return NT_STATUS_NOT_IMPLEMENTED;
        }
 
-       ret = idmap_alloc_ctx->methods->init(params);
+       ret = dom->methods->allocate_id(dom, id);
 
-       if (!NT_STATUS_IS_OK(ret)) {
-               DEBUG(0, ("ERROR: Initialization failed for alloc "
-                         "backend, deferred!\n"));
-               goto fail;
-       }
-
-       TALLOC_FREE(modulename);
-       TALLOC_FREE(params);
-
-       *ctx = idmap_alloc_ctx;
-       return NT_STATUS_OK;
-
-fail:
-       TALLOC_FREE(idmap_alloc_ctx);
        return ret;
 }
 
-/**************************************************************************
- idmap allocator interface functions
-**************************************************************************/
 
 NTSTATUS idmap_allocate_uid(struct unixid *id)
 {
-       struct idmap_alloc_context *ctx;
-       NTSTATUS ret;
-
-       if (!NT_STATUS_IS_OK(ret = idmap_alloc_init(&ctx))) {
-               return ret;
-       }
-
        id->type = ID_TYPE_UID;
-       return ctx->methods->allocate_id(id);
+       return idmap_allocate_unixid(id);
 }
 
 NTSTATUS idmap_allocate_gid(struct unixid *id)
 {
-       struct idmap_alloc_context *ctx;
-       NTSTATUS ret;
-
-       if (!NT_STATUS_IS_OK(ret = idmap_alloc_init(&ctx))) {
-               return ret;
-       }
-
-       id->type = ID_TYPE_GID;
-       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(&ctx))) {
-               return ret;
-       }
-
-       id->type = ID_TYPE_UID;
-       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(&ctx))) {
-               return ret;
-       }
-
        id->type = ID_TYPE_GID;
-       return ctx->methods->set_id_hwm(id);
-}
-
-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;
-
-       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;
-       }
-
-       sid_copy(&sid, psid);
-       map.sid = &sid;
-       map.xid.type = type;
-
-       switch (type) {
-       case ID_TYPE_UID:
-               status = idmap_allocate_uid(&map.xid);
-               break;
-       case ID_TYPE_GID:
-               status = idmap_allocate_gid(&map.xid);
-               break;
-       default:
-               status = NT_STATUS_INVALID_PARAMETER;
-               break;
-       }
-
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(3, ("Could not allocate id: %s\n", nt_errstr(status)));
-               return status;
-       }
-
-       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));
-
-       status = dom->methods->set_mapping(dom, &map);
-
-       if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
-               struct id_map *ids[2];
-               DEBUG(5, ("Mapping for %s exists - retrying to map sid\n",
-                         sid_string_dbg(map.sid)));
-               ids[0] = &map;
-               ids[1] = NULL;
-               status = dom->methods->sids_to_unixids(dom, ids);
-       }
-
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(3, ("Could not store the new mapping: %s\n",
-                         nt_errstr(status)));
-               return status;
-       }
-
-       *pxid = map.xid;
-
-       return NT_STATUS_OK;
+       return idmap_allocate_unixid(id);
 }
 
 NTSTATUS idmap_backends_unixid_to_sid(const char *domname, struct id_map *id)
@@ -741,7 +485,8 @@ NTSTATUS idmap_backends_unixid_to_sid(const char *domname, struct id_map *id)
 
        dom = idmap_init_passdb_domain(NULL);
        if ((dom != NULL)
-           && NT_STATUS_IS_OK(dom->methods->unixids_to_sids(dom, maps))) {
+           && NT_STATUS_IS_OK(dom->methods->unixids_to_sids(dom, maps))
+           && id->status == ID_MAPPED) {
                return NT_STATUS_OK;
        }
 
@@ -758,57 +503,38 @@ NTSTATUS idmap_backends_sid_to_unixid(const char *domain, struct id_map *id)
        struct idmap_domain *dom;
        struct id_map *maps[2];
 
+       DEBUG(10, ("idmap_backends_sid_to_unixid: domain = '%s', sid = [%s]\n",
+                  domain?domain:"NULL", sid_string_dbg(id->sid)));
+
        maps[0] = id;
        maps[1] = NULL;
 
        if (sid_check_is_in_builtin(id->sid)
-           || (sid_check_is_in_our_domain(id->sid))) {
+           || (sid_check_is_in_our_domain(id->sid)))
+       {
+               NTSTATUS status;
+
+               DEBUG(10, ("asking passdb...\n"));
 
                dom = idmap_init_passdb_domain(NULL);
                if (dom == NULL) {
                        return NT_STATUS_NONE_MAPPED;
                }
-               return dom->methods->sids_to_unixids(dom, maps);
-       }
+               status = dom->methods->sids_to_unixids(dom, maps);
 
-       dom = idmap_find_domain(domain);
-       if (dom == NULL) {
-               return NT_STATUS_NONE_MAPPED;
-       }
-
-       return dom->methods->sids_to_unixids(dom, maps);
-}
+               if (NT_STATUS_IS_OK(status) && id->status == ID_MAPPED) {
+                       return status;
+               }
 
-NTSTATUS idmap_set_mapping(const struct id_map *map)
-{
-       struct idmap_domain *dom;
+               DEBUG(10, ("passdb could not map.\n"));
 
-       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;
+               return NT_STATUS_NONE_MAPPED;
        }
 
-       return dom->methods->set_mapping(dom, map);
-}
-
-NTSTATUS idmap_remove_mapping(const struct id_map *map)
-{
-       struct idmap_domain *dom;
-
-       dom = idmap_find_domain(NULL);
+       dom = idmap_find_domain(domain);
        if (dom == NULL) {
-               DEBUG(3, ("no default domain, no place to write\n"));
-               return NT_STATUS_ACCESS_DENIED;
-       }
-       if (dom->methods->remove_mapping == NULL) {
-               DEBUG(3, ("default domain not writable\n"));
-               return NT_STATUS_MEDIA_WRITE_PROTECTED;
+               return NT_STATUS_NONE_MAPPED;
        }
 
-       return dom->methods->remove_mapping(dom, map);
+       return dom->methods->sids_to_unixids(dom, maps);
 }