idmap_autorid: factor out domain range adding code into a separate function
authorMichael Adam <obnox@samba.org>
Fri, 30 Aug 2013 13:19:28 +0000 (18:49 +0530)
committerMichael Adam <obnox@samba.org>
Tue, 1 Oct 2013 22:06:22 +0000 (00:06 +0200)
This also adds a new mode to the new idmap_autorid_addrange() function
that allows to set a provided range if the range is available, instead
of the original only mode of automatically allocating a new range
by incrementing the HWM counter.

Pair-Programmed-With: Atul Kulkarni <atul.kulkarni@in.ibm.com>

Signed-off-by: Michael Adam <obnox@samba.org>
Signed-off-by: Atul Kulkarni <atul.kulkarni@in.ibm.com>
Reviewed-by: Volker Lendecke <vl@samba.org>
source3/winbindd/idmap_autorid_tdb.c

index 02ddbaf51ada0340f5c01f69d262b814f18ed273..e5fccae551db2954cbcccc2b80d7741e9ef19036 100644 (file)
@@ -24,6 +24,7 @@
  */
 
 #include "idmap_autorid_tdb.h"
+#include "../libcli/security/dom_sid.h"
 
 /**
  * Build the database keystring for getting a range
@@ -41,32 +42,87 @@ static void idmap_autorid_build_keystr(const char *domsid,
        }
 }
 
-static NTSTATUS idmap_autorid_get_domainrange_action(struct db_context *db,
+static bool idmap_autorid_validate_sid(const char *sid)
+{
+       struct dom_sid ignore;
+       if (sid == NULL) {
+               return false;
+       }
+
+       if (strcmp(sid, ALLOC_RANGE) == 0) {
+               return true;
+       }
+
+       return dom_sid_parse(sid, &ignore);
+}
+
+struct idmap_autorid_addrange_ctx {
+       struct autorid_range_config *range;
+       bool acquire;
+};
+
+static NTSTATUS idmap_autorid_addrange_action(struct db_context *db,
                                              void *private_data)
 {
+       struct idmap_autorid_addrange_ctx *ctx;
+       uint32_t requested_rangenum, stored_rangenum;
+       struct autorid_range_config *range;
+       bool acquire;
        NTSTATUS ret;
-       uint32_t rangenum, hwm;
+       uint32_t hwm;
        char *numstr;
-       struct autorid_range_config *range;
        struct autorid_global_config *globalcfg;
        fstring keystr;
+       uint32_t increment;
+
+       ctx = (struct idmap_autorid_addrange_ctx *)private_data;
+       range = ctx->range;
+       acquire = ctx->acquire;
+       requested_rangenum = range->rangenum;
+
+       if (db == NULL) {
+               DEBUG(3, ("Invalid database argument: NULL"));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (range == NULL) {
+               DEBUG(3, ("Invalid range argument: NULL"));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       DEBUG(10, ("Adding new range for domain %s "
+                  "(domain_range_index=%"PRIu32")\n",
+                  range->domsid, range->domain_range_index));
 
-       range = (struct autorid_range_config *)private_data;
+       if (!idmap_autorid_validate_sid(range->domsid)) {
+               DEBUG(3, ("Invalid SID: %s\n", range->domsid));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
 
        idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
                                   keystr);
 
-       ret = dbwrap_fetch_uint32_bystring(db, keystr,
-                                          &(range->rangenum));
+       ret = dbwrap_fetch_uint32_bystring(db, keystr, &stored_rangenum);
 
        if (NT_STATUS_IS_OK(ret)) {
                /* entry is already present*/
-               return ret;
-       }
+               if (acquire) {
+                       DEBUG(10, ("domain range already allocated - "
+                                  "Not adding!\n"));
+                       return NT_STATUS_OK;
+               }
 
-       DEBUG(10, ("Acquiring new range for domain %s "
-                  "(domain_range_index=%"PRIu32")\n",
-                  range->domsid, range->domain_range_index));
+               if (stored_rangenum != requested_rangenum) {
+                       DEBUG(1, ("Error: requested rangenumber (%u) differs "
+                                 "from stored one (%u).\n",
+                                 requested_rangenum, stored_rangenum));
+                       return NT_STATUS_UNSUCCESSFUL;
+               }
+
+               DEBUG(10, ("Note: stored range agrees with requested "
+                          "one - ok\n"));
+               return NT_STATUS_OK;
+       }
 
        /* fetch the current HWM */
        ret = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
@@ -79,20 +135,45 @@ static NTSTATUS idmap_autorid_get_domainrange_action(struct db_context *db,
 
        ret = idmap_autorid_loadconfig(db, talloc_tos(), &globalcfg);
        if (!NT_STATUS_IS_OK(ret)) {
-               return ret;
+               DEBUG(1, ("Fatal error while fetching configuration: %s\n",
+                         nt_errstr(ret)));
+               goto error;
+       }
+
+       if (acquire) {
+               /*
+                * automatically acquire the next range
+                */
+               requested_rangenum = hwm;
+       } else {
+               /*
+                * set a specified range
+                */
+
+               if (requested_rangenum < hwm) {
+                       DEBUG(3, ("Invalid range %u requested: Range may not "
+                                 "be smaller than %u (current HWM)\n",
+                                 requested_rangenum, hwm));
+                       ret = NT_STATUS_INVALID_PARAMETER;
+                       goto error;
+               }
        }
 
-       /* do we have a range left? */
-       if (hwm >= globalcfg->maxranges) {
-               DEBUG(1, ("No more domain ranges available!\n"));
-               talloc_free(globalcfg);
+       if (requested_rangenum >= globalcfg->maxranges) {
+               DEBUG(1, ("Not enough ranges available: New range %u must be "
+                         "smaller than configured maximum number of ranges "
+                         "(%u).\n",
+                         requested_rangenum, globalcfg->maxranges));
                ret = NT_STATUS_NO_MEMORY;
                goto error;
        }
        TALLOC_FREE(globalcfg);
 
+       /* HWM always contains current max range + 1 */
+       increment = requested_rangenum + 1 - hwm;
+
        /* increase the HWM */
-       ret = dbwrap_change_uint32_atomic_bystring(db, HWM, &rangenum, 1);
+       ret = dbwrap_change_uint32_atomic_bystring(db, HWM, &hwm, increment);
        if (!NT_STATUS_IS_OK(ret)) {
                DEBUG(1, ("Fatal error while fetching a new "
                          "domain range value!\n"));
@@ -100,14 +181,14 @@ static NTSTATUS idmap_autorid_get_domainrange_action(struct db_context *db,
        }
 
        /* store away the new mapping in both directions */
-       ret = dbwrap_store_uint32_bystring(db, keystr, rangenum);
+       ret = dbwrap_store_uint32_bystring(db, keystr, requested_rangenum);
        if (!NT_STATUS_IS_OK(ret)) {
                DEBUG(1, ("Fatal error while storing new "
                          "domain->range assignment!\n"));
                goto error;
        }
 
-       numstr = talloc_asprintf(db, "%u", rangenum);
+       numstr = talloc_asprintf(db, "%u", requested_rangenum);
        if (!numstr) {
                ret = NT_STATUS_NO_MEMORY;
                goto error;
@@ -123,10 +204,10 @@ static NTSTATUS idmap_autorid_get_domainrange_action(struct db_context *db,
                goto error;
        }
        DEBUG(5, ("Acquired new range #%d for domain %s "
-                 "(domain_range_index=%"PRIu32")\n", rangenum, keystr,
+                 "(domain_range_index=%"PRIu32")\n", requested_rangenum, keystr,
                  range->domain_range_index));
 
-       range->rangenum = rangenum;
+       range->rangenum = requested_rangenum;
 
        range->low_id = globalcfg->minvalue
                      + range->rangenum * globalcfg->rangesize;
@@ -135,7 +216,20 @@ static NTSTATUS idmap_autorid_get_domainrange_action(struct db_context *db,
 
 error:
        return ret;
+}
+
+static NTSTATUS idmap_autorid_addrange(struct db_context *db,
+                                      struct autorid_range_config *range,
+                                      bool acquire)
+{
+       NTSTATUS status;
+       struct idmap_autorid_addrange_ctx ctx;
 
+       ctx.acquire = acquire;
+       ctx.range = range;
+
+       status = dbwrap_trans_do(db, idmap_autorid_addrange_action, &ctx);
+       return status;
 }
 
 static NTSTATUS idmap_autorid_getrange_int(struct db_context *db,
@@ -216,8 +310,8 @@ NTSTATUS idmap_autorid_get_domainrange(struct db_context *db,
                if (read_only) {
                        return NT_STATUS_NOT_FOUND;
                }
-               ret = dbwrap_trans_do(db,
-                             idmap_autorid_get_domainrange_action, range);
+
+               ret = idmap_autorid_addrange(db, range, true);
        }
 
        DEBUG(10, ("Using range #%d for domain %s "