2 * idmap_autorid_tdb: This file contains common code used by
3 * idmap_autorid and net idmap autorid utilities. The common
4 * code provides functions for performing various operations
7 * Copyright (C) Christian Ambach, 2010-2012
8 * Copyright (C) Atul Kulkarni, 2013
9 * Copyright (C) Michael Adam, 2012-2013
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <http://www.gnu.org/licenses/>.
26 #include "idmap_autorid.h"
28 static NTSTATUS idmap_autorid_get_domainrange_action(struct db_context *db,
32 uint32_t rangenum, hwm;
34 struct autorid_range_config *range;
36 range = (struct autorid_range_config *)private_data;
38 ret = dbwrap_fetch_uint32_bystring(db, range->keystr,
41 if (NT_STATUS_IS_OK(ret)) {
42 /* entry is already present*/
46 DEBUG(10, ("Acquiring new range for domain %s "
47 "(domain_range_index=%"PRIu32")\n",
48 range->domsid, range->domain_range_index));
50 /* fetch the current HWM */
51 ret = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
52 if (!NT_STATUS_IS_OK(ret)) {
53 DEBUG(1, ("Fatal error while fetching current "
54 "HWM value: %s\n", nt_errstr(ret)));
55 ret = NT_STATUS_INTERNAL_ERROR;
59 /* do we have a range left? */
60 if (hwm >= range->globalcfg->maxranges) {
61 DEBUG(1, ("No more domain ranges available!\n"));
62 ret = NT_STATUS_NO_MEMORY;
66 /* increase the HWM */
67 ret = dbwrap_change_uint32_atomic_bystring(db, HWM, &rangenum, 1);
68 if (!NT_STATUS_IS_OK(ret)) {
69 DEBUG(1, ("Fatal error while fetching a new "
70 "domain range value!\n"));
74 /* store away the new mapping in both directions */
75 ret = dbwrap_store_uint32_bystring(db, range->keystr, rangenum);
76 if (!NT_STATUS_IS_OK(ret)) {
77 DEBUG(1, ("Fatal error while storing new "
78 "domain->range assignment!\n"));
82 numstr = talloc_asprintf(db, "%u", rangenum);
84 ret = NT_STATUS_NO_MEMORY;
88 ret = dbwrap_store_bystring(db, numstr,
89 string_term_tdb_data(range->keystr), TDB_INSERT);
92 if (!NT_STATUS_IS_OK(ret)) {
93 DEBUG(1, ("Fatal error while storing "
94 "new domain->range assignment!\n"));
97 DEBUG(5, ("Acquired new range #%d for domain %s "
98 "(domain_range_index=%"PRIu32")\n", rangenum, range->keystr,
99 range->domain_range_index));
101 range->rangenum = rangenum;
110 NTSTATUS idmap_autorid_get_domainrange(struct db_context *db,
111 struct autorid_range_config *range,
117 * try to find mapping without locking the database,
118 * if it is not found create a mapping in a transaction unless
119 * read-only mode has been set
121 if (range->domain_range_index > 0) {
122 snprintf(range->keystr, FSTRING_LEN, "%s#%"PRIu32,
123 range->domsid, range->domain_range_index);
125 fstrcpy(range->keystr, range->domsid);
128 ret = dbwrap_fetch_uint32_bystring(db, range->keystr,
131 if (!NT_STATUS_IS_OK(ret)) {
133 return NT_STATUS_NOT_FOUND;
135 ret = dbwrap_trans_do(db,
136 idmap_autorid_get_domainrange_action, range);
139 range->low_id = range->globalcfg->minvalue
140 + range->rangenum * range->globalcfg->rangesize;
142 DEBUG(10, ("Using range #%d for domain %s "
143 "(domain_range_index=%"PRIu32", low_id=%"PRIu32")\n",
144 range->rangenum, range->domsid, range->domain_range_index,
150 /* initialize the given HWM to 0 if it does not exist yet */
151 NTSTATUS idmap_autorid_init_hwm(struct db_context *db, const char *hwm)
156 status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
157 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
158 status = dbwrap_trans_store_int32_bystring(db, hwm, 0);
159 if (!NT_STATUS_IS_OK(status)) {
161 ("Unable to initialise HWM (%s) in autorid "
162 "database: %s\n", hwm, nt_errstr(status)));
163 return NT_STATUS_INTERNAL_DB_ERROR;
165 } else if (!NT_STATUS_IS_OK(status)) {
166 DEBUG(0, ("unable to fetch HWM (%s) from autorid "
167 "database: %s\n", hwm, nt_errstr(status)));
175 * open and initialize the database which stores the ranges for the domains
177 NTSTATUS idmap_autorid_db_init(const char *path,
179 struct db_context **db)
184 /* its already open */
188 /* Open idmap repository */
189 *db = db_open(mem_ctx, path, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644,
190 DBWRAP_LOCK_ORDER_1);
193 DEBUG(0, ("Unable to open idmap_autorid database '%s'\n", path));
194 return NT_STATUS_UNSUCCESSFUL;
197 /* Initialize high water mark for the currently used range to 0 */
199 status = idmap_autorid_init_hwm(*db, HWM);
200 NT_STATUS_NOT_OK_RETURN(status);
202 status = idmap_autorid_init_hwm(*db, ALLOC_HWM_UID);
203 NT_STATUS_NOT_OK_RETURN(status);
205 status = idmap_autorid_init_hwm(*db, ALLOC_HWM_GID);
210 struct idmap_autorid_fetch_config_state {
216 static void idmap_autorid_config_parser(TDB_DATA key, TDB_DATA value,
219 struct idmap_autorid_fetch_config_state *state;
221 state = (struct idmap_autorid_fetch_config_state *)private_data;
223 state->configstr = talloc_zero_array(state->mem_ctx, char, value.dsize+1);
224 if (state->configstr == NULL) {
225 state->status = NT_STATUS_NO_MEMORY;
229 memcpy(state->configstr, value.dptr, value.dsize);
230 state->status = NT_STATUS_OK;
233 NTSTATUS idmap_autorid_getconfigstr(struct db_context *db, TALLOC_CTX *mem_ctx,
238 struct idmap_autorid_fetch_config_state state;
240 if (result == NULL) {
241 return NT_STATUS_INVALID_PARAMETER;
244 key = string_term_tdb_data(CONFIGKEY);
246 if (!dbwrap_exists(db, key)) {
247 DEBUG(1, ("Error: CONFIG entry does not exist\n"));
248 return NT_STATUS_NOT_FOUND;
251 state.mem_ctx = mem_ctx;
252 state.configstr = NULL;
253 state.status = NT_STATUS_OK;
255 status = dbwrap_parse_record(db, key, idmap_autorid_config_parser,
257 if (!NT_STATUS_IS_OK(status)) {
258 DEBUG(1, ("Error while retrieving config: %s\n",
263 if (!NT_STATUS_IS_OK(state.status)) {
264 DEBUG(1, ("Error while retrieving config: %s\n",
265 nt_errstr(state.status)));
269 DEBUG(5, ("found CONFIG: %s\n", state.configstr));
271 *result = state.configstr;
275 bool idmap_autorid_parse_configstr(const char *configstr,
276 struct autorid_global_config *cfg)
278 const char *confnames[] = { [0] = "minvalue",
281 char *str1, *saveptr1;
282 const char *delim = " ";
283 const char *subdelim = ":";
287 if (cfg == NULL || configstr == NULL) {
291 if (strlen(configstr) < 34) {
292 DEBUG(0, ("less than expected length for config: '%s'\n",
297 DEBUG(5, ("config for parsing: %s\n", configstr));
299 for (j = 0, str1 = discard_const_p(char, configstr); ; j++, str1 = NULL)
302 char *token, *str2, *saveptr2;
304 token = strtok_r(str1, delim, &saveptr1);
309 if (strncmp(token, confnames[j], strlen(confnames[j]))) {
310 DEBUG(0, ("expected %s but received '%s'\n",
311 confnames[j], token));
315 for (k=0, str2 = token; ; k++, str2 = NULL) {
319 pp = strtok_r(str2, subdelim, &saveptr2);
325 DEBUG(0, ("more than expected tokens in %s\n",
330 vp = strtok_r(NULL, subdelim, &saveptr2);
332 DEBUG(0, ("error while looking"
333 " for a value of %s\n", pp));
338 DEBUG(0, ("value specified for '%s' "
339 "can't be negative\n", confnames[j]));
345 cfg->minvalue = strtoul(vp, &e, 10);
348 cfg->rangesize = strtoul(vp, &e, 10);
351 cfg->maxranges = strtoul(vp, &e, 10);
355 if (errno == ERANGE || vp == e || (e && *e != '\0')) {
356 DEBUG(0, ("invalid value specified for '%s'\n",
363 if (cfg->rangesize == 0 || cfg->maxranges == 0) {
364 DEBUG(0, ("%s and %s both must be greater than 0\n",
365 confnames[1], confnames[2]));
375 NTSTATUS idmap_autorid_loadconfig(struct db_context *db,
377 struct autorid_global_config **result)
379 struct autorid_global_config *cfg;
382 char *configstr = NULL;
384 if (result == NULL) {
385 return NT_STATUS_INVALID_PARAMETER;
388 status = idmap_autorid_getconfigstr(db, mem_ctx, &configstr);
389 if (!NT_STATUS_IS_OK(status)) {
393 cfg = talloc_zero(mem_ctx, struct autorid_global_config);
395 return NT_STATUS_NO_MEMORY;
398 ok = idmap_autorid_parse_configstr(configstr, cfg);
401 return NT_STATUS_INVALID_PARAMETER;
404 DEBUG(10, ("Loaded previously stored configuration "
405 "minvalue:%d rangesize:%d\n",
406 cfg->minvalue, cfg->rangesize));
413 NTSTATUS idmap_autorid_saveconfig(struct db_context *db,
414 struct autorid_global_config *cfg)
417 struct autorid_global_config *storedconfig = NULL;
418 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
423 if (db == NULL || cfg == NULL) {
427 DEBUG(10, ("New configuration provided for storing is "
428 "minvalue:%d rangesize:%d maxranges:%d\n",
429 cfg->minvalue, cfg->rangesize, cfg->maxranges));
431 if (cfg->rangesize < 2000) {
432 DEBUG(1, ("autorid rangesize must be at least 2000\n"));
436 if (cfg->maxranges == 0) {
437 DEBUG(1, ("An autorid maxranges value of 0 is invalid. "
438 "Must have at least one range available.\n"));
442 status = idmap_autorid_loadconfig(db, talloc_tos(), &storedconfig);
443 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
444 DEBUG(5, ("No configuration found. Storing initial "
445 "configuration.\n"));
446 } else if (!NT_STATUS_IS_OK(status)) {
450 /* did the minimum value or rangesize change? */
452 ((storedconfig->minvalue != cfg->minvalue) ||
453 (storedconfig->rangesize != cfg->rangesize)))
455 DEBUG(1, ("New configuration values for rangesize or "
456 "minimum uid value conflict with previously "
457 "used values! Not storing new config.\n"));
458 talloc_free(storedconfig);
459 status = NT_STATUS_INVALID_PARAMETER;
463 talloc_free(storedconfig);
465 status = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
466 if (!NT_STATUS_IS_OK(status)) {
467 DEBUG(1, ("Fatal error while fetching current "
468 "HWM value: %s\n", nt_errstr(status)));
469 status = NT_STATUS_INTERNAL_ERROR;
474 * has the highest uid value been reduced to setting that is not
475 * sufficient any more for already existing ranges?
477 if (hwm > cfg->maxranges) {
478 DEBUG(1, ("New upper uid limit is too low to cover "
479 "existing mappings! Not storing new config."));
480 status = NT_STATUS_INVALID_PARAMETER;
485 talloc_asprintf(talloc_tos(),
486 "minvalue:%u rangesize:%u maxranges:%u",
487 cfg->minvalue, cfg->rangesize, cfg->maxranges);
490 return NT_STATUS_NO_MEMORY;
493 data = string_tdb_data(cfgstr);
495 status = dbwrap_trans_store_bystring(db, CONFIGKEY, data, TDB_REPLACE);