s3:idmap:autorid prevent fatal configuration changes
authorChristian Ambach <christian.ambach@de.ibm.com>
Wed, 16 Feb 2011 18:05:21 +0000 (19:05 +0100)
committerVolker Lendecke <vl@samba.org>
Wed, 23 Feb 2011 14:59:11 +0000 (15:59 +0100)
as the autorid module relies on a stable minimum uid/gid value
and rangesize, it now saves the values used at first successful start
and refuses to work if these values get changed in smb.conf later.
Changing the values after the first mapping was done will result
in unpredictable behaviour.
Another check covers the maximum uid value. If this gets decreased
later and domain range mappings already exist that would result
in uid values higher than the new uid value, initialization will
be aborted

source3/winbindd/idmap_autorid.c

index 6485d7897bdf52538bb808314e8f20df8f530d55..2b40a998e330c2c4a1fa5088a361fd4e182dd0e0 100644 (file)
@@ -5,7 +5,7 @@
  *  based on the idmap_rid module, but this module defines the ranges
  *  for the domains by automatically allocating a range for each domain
  *
- *  Copyright (C) Christian Ambach, 2010
+ *  Copyright (C) Christian Ambach, 2010-2011
  *
  *  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
@@ -32,6 +32,8 @@
 #define DBGC_CLASS DBGC_IDMAP
 
 #define HWM "NEXT RANGE"
+#define CONFIGKEY "CONFIG"
+
 struct autorid_global_config {
        uint32_t minvalue;
        uint32_t rangesize;
@@ -388,11 +390,74 @@ static NTSTATUS idmap_autorid_db_init(void)
        return NT_STATUS_OK;
 }
 
+static struct autorid_global_config *idmap_autorid_loadconfig(TALLOC_CTX * ctx)
+{
+
+       TDB_DATA data;
+       struct autorid_global_config *cfg;
+
+       data = dbwrap_fetch_bystring(autorid_db, ctx, CONFIGKEY);
+
+       if (!data.dptr) {
+               DEBUG(10, ("No saved config found\n"));
+               return NULL;
+       }
+
+       cfg = TALLOC_ZERO_P(ctx, struct autorid_global_config);
+       if (!cfg) {
+               return NULL;
+       }
+
+       if (sscanf
+           ((char *)data.dptr, "minvalue:%lu rangesize:%lu maxranges:%lu",
+            (unsigned long *)&cfg->minvalue, (unsigned long *)&cfg->rangesize,
+            (unsigned long *)&cfg->maxranges) != 3) {
+               DEBUG(1,
+                     ("Found invalid configuration data"
+                      "creating new config\n"));
+               return NULL;
+       }
+
+       DEBUG(10, ("Loaded previously stored configuration "
+                  "minvalue:%d rangesize:%d\n",
+                  cfg->minvalue, cfg->rangesize));
+
+       return cfg;
+
+}
+
+static NTSTATUS idmap_autorid_saveconfig(struct autorid_global_config *cfg)
+{
+
+       NTSTATUS status;
+       TDB_DATA data;
+       char *cfgstr;
+
+       cfgstr =
+           talloc_asprintf(talloc_tos(),
+                           "minvalue:%u rangesize:%u maxranges:%u",
+                           cfg->minvalue, cfg->rangesize, cfg->maxranges);
+
+       if (!cfgstr) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       data = string_tdb_data(cfgstr);
+
+       status = dbwrap_trans_store_bystring(autorid_db, CONFIGKEY,
+                                            data, TDB_REPLACE);
+
+       talloc_free(cfgstr);
+
+       return status;
+}
+
 static NTSTATUS idmap_autorid_initialize(struct idmap_domain *dom,
                                         const char *params)
 {
-       struct autorid_global_config *config;
+       struct autorid_global_config *config, *storedconfig;
        NTSTATUS status;
+       uint32_t hwm;
 
        config = TALLOC_ZERO_P(dom, struct autorid_global_config);
        if (!config) {
@@ -433,6 +498,49 @@ static NTSTATUS idmap_autorid_initialize(struct idmap_domain *dom,
                          config->maxranges));
        }
 
+       DEBUG(10, ("Current configuration in config is "
+                  "minvalue:%d rangesize:%d maxranges:%d\n",
+                  config->minvalue, config->rangesize, config->maxranges));
+
+       /* read previously stored config and current HWM */
+       storedconfig = idmap_autorid_loadconfig(talloc_tos());
+
+       if (!dbwrap_fetch_uint32(autorid_db, HWM, &hwm)) {
+               DEBUG(1, ("Fatal error while fetching current "
+                         "HWM value!\n"));
+               status = NT_STATUS_INTERNAL_ERROR;
+               goto error;
+       }
+
+       /* did the minimum value or rangesize change? */
+       if (storedconfig &&
+           ((storedconfig->minvalue != config->minvalue) ||
+            (storedconfig->rangesize != config->rangesize))) {
+               DEBUG(1, ("New configuration values for rangesize or "
+                         "minimum uid value conflict with previously "
+                         "used values! Aborting initialization\n"));
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto error;
+       }
+
+       /*
+        * has the highest uid value been reduced to setting that is not
+        * sufficient any more for already existing ranges?
+        */
+       if (hwm > config->maxranges) {
+               DEBUG(1, ("New upper uid limit is too low to cover "
+                         "existing mappings! Aborting initialization\n"));
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto error;
+       }
+
+       status = idmap_autorid_saveconfig(config);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Failed to store configuration data!\n"));
+               goto error;
+       }
+
        DEBUG(5, ("%d domain ranges with a size of %d are available\n",
                  config->maxranges, config->rangesize));
 
@@ -446,6 +554,8 @@ static NTSTATUS idmap_autorid_initialize(struct idmap_domain *dom,
 
       error:
        talloc_free(config);
+       talloc_free(storedconfig);
+
        return status;
 }