ctdb-protocol: Fix marshalling for ctdb_reply_control
[samba.git] / source3 / winbindd / idmap_autorid_tdb.c
index bbfa5b04b63baf5c5211e9b7b2ecf17170613d4f..a95702e619e15aa25748ef8bd383791ba021d542 100644 (file)
@@ -88,7 +88,7 @@ static NTSTATUS idmap_autorid_addrange_action(struct db_context *db,
        NTSTATUS ret;
        uint32_t hwm;
        char *numstr;
-       struct autorid_global_config *globalcfg;
+       struct autorid_global_config globalcfg = {0};
        fstring keystr;
        uint32_t increment;
        TALLOC_CTX *mem_ctx = NULL;
@@ -127,6 +127,21 @@ static NTSTATUS idmap_autorid_addrange_action(struct db_context *db,
                if (acquire) {
                        DEBUG(10, ("domain range already allocated - "
                                   "Not adding!\n"));
+
+                       ret = idmap_autorid_loadconfig(db, &globalcfg);
+                       if (!NT_STATUS_IS_OK(ret)) {
+                               DEBUG(1, ("Fatal error while fetching "
+                                         "configuration: %s\n",
+                                         nt_errstr(ret)));
+                               goto error;
+                       }
+
+                       range->rangenum = stored_rangenum;
+                       range->low_id = globalcfg.minvalue
+                               + range->rangenum * globalcfg.rangesize;
+                       range->high_id =
+                               range->low_id  + globalcfg.rangesize - 1;
+
                        return NT_STATUS_OK;
                }
 
@@ -152,7 +167,7 @@ static NTSTATUS idmap_autorid_addrange_action(struct db_context *db,
 
        mem_ctx = talloc_stackframe();
 
-       ret = idmap_autorid_loadconfig(db, mem_ctx, &globalcfg);
+       ret = idmap_autorid_loadconfig(db, &globalcfg);
        if (!NT_STATUS_IS_OK(ret)) {
                DEBUG(1, ("Fatal error while fetching configuration: %s\n",
                          nt_errstr(ret)));
@@ -166,35 +181,43 @@ static NTSTATUS idmap_autorid_addrange_action(struct db_context *db,
                requested_rangenum = hwm;
        }
 
-       if (requested_rangenum >= globalcfg->maxranges) {
+       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));
+                         requested_rangenum, globalcfg.maxranges));
                ret = NT_STATUS_NO_MEMORY;
                goto error;
        }
 
-       if (requested_rangenum < hwm) {
-               /*
-                * Set a specified range below the HWM:
-                * We need to check that it is not yet taken.
-                */
+       /*
+        * Check that it is not yet taken.
+        * If the range is requested and < HWM, we need
+        * to check anyways, and otherwise, we also better
+        * check in order to prevent further corruption
+        * in case the db has been externally modified.
+        */
 
-               numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
-               if (!numstr) {
-                       ret = NT_STATUS_NO_MEMORY;
-                       goto error;
-               }
+       numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
+       if (!numstr) {
+               DEBUG(1, ("Talloc failed!\n"));
+               ret = NT_STATUS_NO_MEMORY;
+               goto error;
+       }
+
+       if (dbwrap_exists(db, string_term_tdb_data(numstr))) {
+               DEBUG(1, ("Requested range '%s' is already in use.\n", numstr));
 
-               if (dbwrap_exists(db, string_term_tdb_data(numstr))) {
-                       DEBUG(1, ("Requested range already in use.\n"));
+               if (requested_rangenum < hwm) {
                        ret = NT_STATUS_INVALID_PARAMETER;
-                       goto error;
+               } else {
+                       ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
 
-               TALLOC_FREE(numstr);
-       } else {
+               goto error;
+       }
+
+       if (requested_rangenum >= hwm) {
                /*
                 * requested or automatic range >= HWM:
                 * increment the HWM.
@@ -239,14 +262,18 @@ static NTSTATUS idmap_autorid_addrange_action(struct db_context *db,
                          "domain->range assignment: %s\n", nt_errstr(ret)));
                goto error;
        }
-       DEBUG(5, ("Acquired new range #%d for domain %s "
-                 "(domain_range_index=%"PRIu32")\n", requested_rangenum, keystr,
+
+       DEBUG(5, ("%s new range #%d for domain %s "
+                 "(domain_range_index=%"PRIu32")\n",
+                 (acquire?"Acquired":"Stored"),
+                 requested_rangenum, keystr,
                  range->domain_range_index));
 
        range->rangenum = requested_rangenum;
 
-       range->low_id = globalcfg->minvalue
-                     + range->rangenum * globalcfg->rangesize;
+       range->low_id = globalcfg.minvalue
+                     + range->rangenum * globalcfg.rangesize;
+       range->high_id = range->low_id  + globalcfg.rangesize - 1;
 
        ret = NT_STATUS_OK;
 
@@ -286,8 +313,8 @@ NTSTATUS idmap_autorid_setrange(struct db_context *db,
        return status;
 }
 
-static NTSTATUS idmap_autorid_acquire_range(struct db_context *db,
-                                           struct autorid_range_config *range)
+NTSTATUS idmap_autorid_acquire_range(struct db_context *db,
+                                    struct autorid_range_config *range)
 {
        return idmap_autorid_addrange(db, range, true);
 }
@@ -296,7 +323,7 @@ static NTSTATUS idmap_autorid_getrange_int(struct db_context *db,
                                           struct autorid_range_config *range)
 {
        NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
-       struct autorid_global_config *globalcfg = NULL;
+       struct autorid_global_config globalcfg = {0};
        fstring keystr;
 
        if (db == NULL || range == NULL) {
@@ -304,26 +331,31 @@ static NTSTATUS idmap_autorid_getrange_int(struct db_context *db,
                goto done;
        }
 
+       if (!idmap_autorid_validate_sid(range->domsid)) {
+               DEBUG(3, ("Invalid SID: '%s'\n", range->domsid));
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto done;
+       }
+
        idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
                                   keystr);
 
        DEBUG(10, ("reading domain range for key %s\n", keystr));
        status = dbwrap_fetch_uint32_bystring(db, keystr, &(range->rangenum));
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Failed to read database for key '%s': %s\n",
+               DEBUG(1, ("Failed to read database record for key '%s': %s\n",
                          keystr, nt_errstr(status)));
                goto done;
        }
 
-       status = idmap_autorid_loadconfig(db, talloc_tos(), &globalcfg);
+       status = idmap_autorid_loadconfig(db, &globalcfg);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("Failed to read global configuration"));
                goto done;
        }
-       range->low_id = globalcfg->minvalue
-                     + range->rangenum * globalcfg->rangesize;
-
-       TALLOC_FREE(globalcfg);
+       range->low_id = globalcfg.minvalue
+                     + range->rangenum * globalcfg.rangesize;
+       range->high_id = range->low_id  + globalcfg.rangesize - 1;
 done:
        return status;
 }
@@ -367,7 +399,11 @@ NTSTATUS idmap_autorid_get_domainrange(struct db_context *db,
 
        ret = idmap_autorid_getrange_int(db, range);
        if (!NT_STATUS_IS_OK(ret)) {
+               DEBUG(10, ("Failed to read range config for '%s': %s\n",
+                          range->domsid, nt_errstr(ret)));
                if (read_only) {
+                       DEBUG(10, ("Not allocating new range for '%s' because "
+                                  "read-only is enabled.\n", range->domsid));
                        return NT_STATUS_NOT_FOUND;
                }
 
@@ -383,26 +419,64 @@ NTSTATUS idmap_autorid_get_domainrange(struct db_context *db,
 }
 
 /* initialize the given HWM to 0 if it does not exist yet */
+static NTSTATUS idmap_autorid_init_hwm_action(struct db_context *db,
+                                             void *private_data)
+{
+       NTSTATUS status;
+       uint32_t hwmval;
+       const char *hwm;
+
+       hwm = (char *)private_data;
+
+       status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
+       if (NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("HWM (%s) already initialized in autorid database "
+                         "(value %"PRIu32").\n", hwm, hwmval));
+               return NT_STATUS_OK;
+       }
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+               DEBUG(0, ("Error fetching HWM (%s) from autorid "
+                         "database: %s\n", hwm, nt_errstr(status)));
+               return status;
+       }
+
+       status = dbwrap_trans_store_uint32_bystring(db, hwm, 0);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("Error storing HWM (%s) in autorid database: %s\n",
+                         hwm, nt_errstr(status)));
+               return status;
+       }
+
+       return NT_STATUS_OK;
+}
+
 NTSTATUS idmap_autorid_init_hwm(struct db_context *db, const char *hwm)
 {
        NTSTATUS status;
        uint32_t hwmval;
 
        status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
-       if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND))  {
-               status = dbwrap_trans_store_int32_bystring(db, hwm, 0);
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(0,
-                             ("Unable to initialise HWM (%s) in autorid "
-                              "database: %s\n", hwm, nt_errstr(status)));
-                       return NT_STATUS_INTERNAL_DB_ERROR;
-               }
-       } else if (!NT_STATUS_IS_OK(status)) {
+       if (NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("HWM (%s) already initialized in autorid database "
+                         "(value %"PRIu32").\n", hwm, hwmval));
+               return NT_STATUS_OK;
+       }
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
                DEBUG(0, ("unable to fetch HWM (%s) from autorid "
                          "database: %s\n", hwm,  nt_errstr(status)));
                return status;
        }
 
+       status = dbwrap_trans_do(db, idmap_autorid_init_hwm_action,
+                                discard_const(hwm));
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("Error initializing HWM (%s) in autorid database: "
+                         "%s\n", hwm, nt_errstr(status)));
+               return NT_STATUS_INTERNAL_DB_ERROR;
+       }
+
+       DEBUG(1, ("Initialized HWM (%s) in autorid database.\n", hwm));
+
        return NT_STATUS_OK;
 }
 
@@ -541,7 +615,7 @@ static NTSTATUS idmap_autorid_delete_range_by_num_action(struct db_context *db,
        struct idmap_autorid_delete_range_by_num_ctx *ctx =
                (struct idmap_autorid_delete_range_by_num_ctx *)private_data;
        uint32_t rangenum;
-       char *keystr;
+       char *keystr = NULL;
        char *range_keystr;
        TDB_DATA val;
        NTSTATUS status;
@@ -644,15 +718,13 @@ NTSTATUS idmap_autorid_delete_range_by_num(struct db_context *db,
        return status;
 }
 
-/*
- * open and initialize the database which stores the ranges for the domains
+/**
+ * Open and possibly create the database.
  */
-NTSTATUS idmap_autorid_db_init(const char *path,
+NTSTATUS idmap_autorid_db_open(const char *path,
                               TALLOC_CTX *mem_ctx,
                               struct db_context **db)
 {
-       NTSTATUS status;
-
        if (*db != NULL) {
                /* its already open */
                return NT_STATUS_OK;
@@ -660,26 +732,55 @@ NTSTATUS idmap_autorid_db_init(const char *path,
 
        /* Open idmap repository */
        *db = db_open(mem_ctx, path, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644,
-                     DBWRAP_LOCK_ORDER_1);
+                     DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
 
        if (*db == NULL) {
                DEBUG(0, ("Unable to open idmap_autorid database '%s'\n", path));
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-       /* Initialize high water mark for the currently used range to 0 */
+       return NT_STATUS_OK;
+}
+
+/**
+ * Initialize the high watermark records in the database.
+ */
+NTSTATUS idmap_autorid_init_hwms(struct db_context *db)
+{
+       NTSTATUS status;
+
+       status = idmap_autorid_init_hwm(db, HWM);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       status = idmap_autorid_init_hwm(db, ALLOC_HWM_UID);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       status = idmap_autorid_init_hwm(db, ALLOC_HWM_GID);
 
-       status = idmap_autorid_init_hwm(*db, HWM);
-       NT_STATUS_NOT_OK_RETURN(status);
+       return status;
+}
 
-       status = idmap_autorid_init_hwm(*db, ALLOC_HWM_UID);
-       NT_STATUS_NOT_OK_RETURN(status);
+NTSTATUS idmap_autorid_db_init(const char *path,
+                              TALLOC_CTX *mem_ctx,
+                              struct db_context **db)
+{
+       NTSTATUS status;
 
-       status = idmap_autorid_init_hwm(*db, ALLOC_HWM_GID);
+       status = idmap_autorid_db_open(path, mem_ctx, db);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
 
+       status = idmap_autorid_init_hwms(*db);
        return status;
 }
 
+
+
 struct idmap_autorid_fetch_config_state {
        TALLOC_CTX *mem_ctx;
        char *configstr;
@@ -743,8 +844,8 @@ bool idmap_autorid_parse_configstr(const char *configstr,
                   "minvalue:%lu rangesize:%lu maxranges:%lu",
                   &minvalue, &rangesize, &maxranges) != 3) {
                DEBUG(1,
-                     ("Found invalid configuration data"
-                      "creating new config\n"));
+                     ("Found invalid configuration data"
+                      "Creating new config\n"));
                return false;
        }
 
@@ -756,10 +857,9 @@ bool idmap_autorid_parse_configstr(const char *configstr,
 }
 
 NTSTATUS idmap_autorid_loadconfig(struct db_context *db,
-                                 TALLOC_CTX *mem_ctx,
-                                 struct autorid_global_config **result)
+                                 struct autorid_global_config *result)
 {
-       struct autorid_global_config *cfg;
+       struct autorid_global_config cfg = {0};
        NTSTATUS status;
        bool ok;
        char *configstr = NULL;
@@ -768,25 +868,20 @@ NTSTATUS idmap_autorid_loadconfig(struct db_context *db,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       status = idmap_autorid_getconfigstr(db, mem_ctx, &configstr);
+       status = idmap_autorid_getconfigstr(db, db, &configstr);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       cfg = talloc_zero(mem_ctx, struct autorid_global_config);
-       if (cfg == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       ok = idmap_autorid_parse_configstr(configstr, cfg);
+       ok = idmap_autorid_parse_configstr(configstr, &cfg);
+       TALLOC_FREE(configstr);
        if (!ok) {
-               talloc_free(cfg);
                return NT_STATUS_INVALID_PARAMETER;
        }
 
        DEBUG(10, ("Loaded previously stored configuration "
                   "minvalue:%d rangesize:%d\n",
-                  cfg->minvalue, cfg->rangesize));
+                  cfg.minvalue, cfg.rangesize));
 
        *result = cfg;
 
@@ -797,7 +892,7 @@ NTSTATUS idmap_autorid_saveconfig(struct db_context *db,
                                  struct autorid_global_config *cfg)
 {
 
-       struct autorid_global_config *storedconfig = NULL;
+       struct autorid_global_config storedconfig = {0};
        NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
        TDB_DATA data;
        char *cfgstr;
@@ -819,18 +914,20 @@ NTSTATUS idmap_autorid_saveconfig(struct db_context *db,
                goto done;
        }
 
-       status = idmap_autorid_loadconfig(db, frame, &storedconfig);
+       status = idmap_autorid_loadconfig(db, &storedconfig);
        if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
                DEBUG(5, ("No configuration found. Storing initial "
                          "configuration.\n"));
+               storedconfig = *cfg;
        } else if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Error loading configuration: %s\n",
+                         nt_errstr(status)));
                goto done;
        }
 
        /* did the minimum value or rangesize change? */
-       if (storedconfig &&
-           ((storedconfig->minvalue != cfg->minvalue) ||
-            (storedconfig->rangesize != cfg->rangesize)))
+       if ((storedconfig.minvalue != cfg->minvalue) ||
+           (storedconfig.rangesize != cfg->rangesize))
        {
                DEBUG(1, ("New configuration values for rangesize or "
                          "minimum uid value conflict with previously "
@@ -962,6 +1059,14 @@ static int idmap_autorid_visit_domain_range(struct db_record *rec,
        }
 
        value = dbwrap_record_get_value(rec);
+
+       if (value.dsize != sizeof(uint32_t)) {
+               /* it might be a mapping of a well known sid */
+               DEBUG(10, ("value size %u != sizeof(uint32_t) for sid '%s', "
+                          "skipping.\n", (unsigned)value.dsize, vi->domsid));
+               goto done;
+       }
+
        rangenum = IVAL(value.dptr, 0);
 
        db = dbwrap_record_get_db(rec);