s3:winbindd/autorid multiple range support
authorAbhidnya Joshi <achirmul@in.ibm.com>
Wed, 10 Apr 2013 10:56:07 +0000 (16:26 +0530)
committerChristian Ambach <ambi@samba.org>
Mon, 6 May 2013 14:33:39 +0000 (16:33 +0200)
when a mapping request for a RID comes in that is larger
than the rangesize, allocate an extension range to be able
to map this one

This is especially important for large installations which
might have large RIDs being used in a trusted domain that
the administrator was not aware of when planning for autorid
usage and so those objects could not be mapped up to now.
As it is not possible to change the rangesize after the first
start of autorid, this would lead to big trouble.

Signed-off-by: Abhidnya Joshi <achirmul@in.ibm.com>
Reviewed-by: Christian Ambach <ambi@samba.org>
Reviewed-by: Michael Adam <obnox@samba.org>
source3/winbindd/idmap_autorid.c

index 07479168c71530c811f76fa3031f5f2307f2faee..87833ba18c07883acd335192fbee826926a0c7d8 100644 (file)
@@ -51,7 +51,9 @@ struct autorid_global_config {
 
 struct autorid_domain_config {
        fstring sid;
+       fstring keystr;
        uint32_t domainnum;
+       uint32_t multiplier;
        struct autorid_global_config *globalcfg;
 };
 
@@ -68,14 +70,15 @@ static NTSTATUS idmap_autorid_get_domainrange_action(struct db_context *db,
 
        cfg = (struct autorid_domain_config *)private_data;
 
-       ret = dbwrap_fetch_uint32_bystring(db, cfg->sid, &(cfg->domainnum));
+       ret = dbwrap_fetch_uint32_bystring(db, cfg->keystr, &(cfg->domainnum));
 
        if (NT_STATUS_IS_OK(ret)) {
                /* entry is already present*/
                return ret;
        }
 
-       DEBUG(10, ("Acquiring new range for domain %s\n", cfg->sid));
+       DEBUG(10, ("Acquiring new range for domain %s (multiplier=%"PRIu32")\n",
+                  cfg->sid, cfg->multiplier));
 
        /* fetch the current HWM */
        ret = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
@@ -102,7 +105,7 @@ 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, cfg->sid, domainnum);
+       ret = dbwrap_store_uint32_bystring(db, cfg->keystr, domainnum);
        if (!NT_STATUS_IS_OK(ret)) {
                DEBUG(1, ("Fatal error while storing new "
                          "domain->range assignment!\n"));
@@ -116,7 +119,7 @@ static NTSTATUS idmap_autorid_get_domainrange_action(struct db_context *db,
        }
 
        ret = dbwrap_store_bystring(db, numstr,
-                       string_term_tdb_data(cfg->sid), TDB_INSERT);
+                       string_term_tdb_data(cfg->keystr), TDB_INSERT);
 
        talloc_free(numstr);
        if (!NT_STATUS_IS_OK(ret)) {
@@ -124,8 +127,9 @@ static NTSTATUS idmap_autorid_get_domainrange_action(struct db_context *db,
                          "new domain->range assignment!\n"));
                goto error;
        }
-       DEBUG(5, ("Acquired new range #%d for domain %s\n",
-                 domainnum, cfg->sid));
+       DEBUG(5, ("Acquired new range #%d for domain %s "
+                 "(multiplier=%"PRIu32")\n", domainnum, cfg->keystr,
+                 cfg->multiplier));
 
        cfg->domainnum = domainnum;
 
@@ -146,7 +150,14 @@ static NTSTATUS idmap_autorid_get_domainrange(struct autorid_domain_config *dom,
         * if it is not found create a mapping in a transaction unless
         * read-only mode has been set
         */
-       ret = dbwrap_fetch_uint32_bystring(autorid_db, dom->sid,
+       if (dom->multiplier > 0) {
+               snprintf(dom->keystr, FSTRING_LEN, "%s#%"PRIu32, dom->sid,
+                       dom->multiplier);
+       } else {
+               fstrcpy(dom->keystr, dom->sid);
+       }
+
+       ret = dbwrap_fetch_uint32_bystring(autorid_db, dom->keystr,
                                           &(dom->domainnum));
 
        if (!NT_STATUS_IS_OK(ret)) {
@@ -157,8 +168,8 @@ static NTSTATUS idmap_autorid_get_domainrange(struct autorid_domain_config *dom,
                              idmap_autorid_get_domainrange_action, dom);
        }
 
-       DEBUG(10, ("Using range #%d for domain %s\n", dom->domainnum,
-                  dom->sid));
+       DEBUG(10, ("Using range #%d for domain %s (multiplier=%"PRIu32")\n",
+                  dom->domainnum, dom->sid, dom->multiplier));
 
        return ret;
 }
@@ -244,11 +255,13 @@ static NTSTATUS idmap_autorid_id_to_sid(struct autorid_global_config *cfg,
                                        struct id_map *map)
 {
        uint32_t range;
+       uint32_t multiplier = 0;
        TDB_DATA data = tdb_null;
        char *keystr;
        struct dom_sid sid;
        NTSTATUS status;
        bool ok;
+       const char *q = NULL;
 
        /* can this be one of our ids? */
        if (map->xid.id < cfg->minvalue) {
@@ -298,16 +311,23 @@ static NTSTATUS idmap_autorid_id_to_sid(struct autorid_global_config *cfg,
                return idmap_autorid_map_id_to_sid(dom, map);
        }
 
-       ok = string_to_sid(&sid, (const char *)data.dptr);
+       ok = dom_sid_parse_endp((const char *)data.dptr, &sid, &q);
        TALLOC_FREE(data.dptr);
        if (!ok) {
                map->status = ID_UNKNOWN;
                return NT_STATUS_OK;
        }
+       if (q != NULL)
+               if (sscanf(q+1, "%"SCNu32, &multiplier) != 1) {
+                       DEBUG(10, ("Multiplier not found! "
+                                  "ignoring mapping request\n"));
+                       map->status = ID_UNKNOWN;
+                       return NT_STATUS_OK;
+               }
 
        sid_compose(map->sid, &sid,
                    (map->xid.id - cfg->minvalue -
-                    range * cfg->rangesize));
+                    range * cfg->rangesize + (cfg->rangesize * multiplier)));
 
        /* We **really** should have some way of validating
           the SID exists and is the correct type here.  But
@@ -331,15 +351,9 @@ static NTSTATUS idmap_autorid_sid_to_id(struct autorid_global_config *global,
 
        sid_peek_rid(map->sid, &rid);
 
-       /* if the rid is higher than the size of the range, we cannot map it */
-       if (rid >= global->rangesize) {
-               map->status = ID_UNKNOWN;
-               DEBUG(2, ("RID %d is larger then size of range (%d), "
-                         "user cannot be mapped\n", rid, global->rangesize));
-               return NT_STATUS_UNSUCCESSFUL;
-       }
        map->xid.id = global->minvalue +
-           (global->rangesize * domain->domainnum)+rid;
+           (global->rangesize * domain->domainnum) + rid -
+           (global->rangesize * domain->multiplier);
        map->xid.type = ID_TYPE_BOTH;
 
        /* We **really** should have some way of validating
@@ -563,6 +577,9 @@ static NTSTATUS idmap_autorid_sids_to_unixids(struct idmap_domain *dom,
                domaincfg.globalcfg = global;
                sid_to_fstring(domaincfg.sid, &domainsid);
 
+               /* Calculate multiplier for multi-range support */
+               domaincfg.multiplier = rid / (global->rangesize);
+
                ret = idmap_autorid_get_domainrange(&domaincfg, dom->read_only);
 
                /* read-only mode and a new domain range would be required? */