s3:smbd: consistently use talloc_tos() memory for rpc_pipe_open_interface()
[Samba.git] / source4 / dsdb / samdb / ldb_modules / partition_metadata.c
blob3c5180b7ab7a8a35328e1611b4b08d02f96ecb5a
1 /*
2 Partitions ldb module - management of metadata.tdb for sequence number
4 Copyright (C) Amitay Isaacs <amitay@samba.org> 2011
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "dsdb/samdb/ldb_modules/partition.h"
21 #include "system/filesys.h"
23 #define LDB_METADATA_SEQ_NUM "SEQ_NUM"
27 * Read a key with uint64 value
29 static int partition_metadata_get_uint64(struct ldb_module *module,
30 const char *key, uint64_t *value,
31 uint64_t default_value)
33 struct partition_private_data *data;
34 struct tdb_context *tdb;
35 TDB_DATA tdb_key, tdb_data;
36 char *value_str;
37 TALLOC_CTX *tmp_ctx;
39 data = talloc_get_type_abort(ldb_module_get_private(module),
40 struct partition_private_data);
42 if (!data || !data->metadata || !data->metadata->db) {
43 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
44 "partition_metadata: metadata tdb not initialized");
47 tmp_ctx = talloc_new(NULL);
48 if (tmp_ctx == NULL) {
49 return ldb_module_oom(module);
52 tdb = data->metadata->db->tdb;
54 tdb_key.dptr = (uint8_t *)discard_const_p(char, key);
55 tdb_key.dsize = strlen(key);
57 tdb_data = tdb_fetch(tdb, tdb_key);
58 if (!tdb_data.dptr) {
59 if (tdb_error(tdb) == TDB_ERR_NOEXIST) {
60 *value = default_value;
61 return LDB_SUCCESS;
62 } else {
63 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
64 tdb_errorstr(tdb));
68 value_str = talloc_strndup(tmp_ctx, (char *)tdb_data.dptr, tdb_data.dsize);
69 if (value_str == NULL) {
70 SAFE_FREE(tdb_data.dptr);
71 talloc_free(tmp_ctx);
72 return ldb_module_oom(module);
75 *value = strtoull(value_str, NULL, 10);
77 SAFE_FREE(tdb_data.dptr);
78 talloc_free(tmp_ctx);
80 return LDB_SUCCESS;
85 * Write a key with uin64 value
87 static int partition_metadata_set_uint64(struct ldb_module *module,
88 const char *key, uint64_t value,
89 bool insert)
91 struct partition_private_data *data;
92 struct tdb_context *tdb;
93 TDB_DATA tdb_key, tdb_data;
94 int tdb_flag;
95 char *value_str;
96 TALLOC_CTX *tmp_ctx;
98 data = talloc_get_type_abort(ldb_module_get_private(module),
99 struct partition_private_data);
101 if (!data || !data->metadata || !data->metadata->db) {
102 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
103 "partition_metadata: metadata tdb not initialized");
106 tmp_ctx = talloc_new(NULL);
107 if (tmp_ctx == NULL) {
108 return ldb_module_oom(module);
111 tdb = data->metadata->db->tdb;
113 value_str = talloc_asprintf(tmp_ctx, "%llu", (unsigned long long)value);
114 if (value_str == NULL) {
115 talloc_free(tmp_ctx);
116 return ldb_module_oom(module);
119 tdb_key.dptr = (uint8_t *)discard_const_p(char, key);
120 tdb_key.dsize = strlen(key);
122 tdb_data.dptr = (uint8_t *)value_str;
123 tdb_data.dsize = strlen(value_str);
125 if (insert) {
126 tdb_flag = TDB_INSERT;
127 } else {
128 tdb_flag = TDB_MODIFY;
131 if (tdb_store(tdb, tdb_key, tdb_data, tdb_flag) != 0) {
132 int ret;
133 char *error_string = talloc_asprintf(tmp_ctx, "%s: tdb_store of key %s failed: %s",
134 tdb_name(tdb), key, tdb_errorstr(tdb));
135 ret = ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
136 error_string);
137 talloc_free(tmp_ctx);
138 return ret;
141 talloc_free(tmp_ctx);
143 return LDB_SUCCESS;
146 int partition_metadata_inc_schema_sequence(struct ldb_module *module)
148 struct partition_private_data *data;
149 int ret;
150 uint64_t value;
152 data = talloc_get_type_abort(ldb_module_get_private(module),
153 struct partition_private_data);
154 if (!data || !data->metadata) {
155 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
156 "partition_metadata: metadata not initialized");
159 if (data->metadata->in_transaction == 0) {
160 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
161 "partition_metadata: increment sequence number without transaction");
163 ret = partition_metadata_get_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, &value, 0);
164 if (ret != LDB_SUCCESS) {
165 return ret;
168 value++;
169 ret = partition_metadata_set_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, value, false);
170 if (ret == LDB_ERR_OPERATIONS_ERROR) {
171 /* Modify failed, let's try the add */
172 ret = partition_metadata_set_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, value, true);
174 return ret;
180 * Open sam.ldb.d/metadata.tdb.
182 static int partition_metadata_open(struct ldb_module *module, bool create)
184 struct ldb_context *ldb = ldb_module_get_ctx(module);
185 TALLOC_CTX *tmp_ctx;
186 struct partition_private_data *data;
187 struct loadparm_context *lp_ctx;
188 const char *sam_name;
189 char *filename, *dirname;
190 int open_flags;
191 struct stat statbuf;
193 data = talloc_get_type_abort(ldb_module_get_private(module),
194 struct partition_private_data);
195 if (!data || !data->metadata) {
196 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
197 "partition_metadata: metadata not initialized");
200 tmp_ctx = talloc_new(NULL);
201 if (tmp_ctx == NULL) {
202 return ldb_module_oom(module);
205 sam_name = (const char *)ldb_get_opaque(ldb, "ldb_url");
206 if (!sam_name) {
207 talloc_free(tmp_ctx);
208 return ldb_operr(ldb);
210 if (strncmp("tdb://", sam_name, 6) == 0) {
211 sam_name += 6;
213 filename = talloc_asprintf(tmp_ctx, "%s.d/metadata.tdb", sam_name);
214 if (!filename) {
215 talloc_free(tmp_ctx);
216 return ldb_oom(ldb);
219 open_flags = O_RDWR;
220 if (create) {
221 open_flags |= O_CREAT;
223 /* While provisioning, sam.ldb.d directory may not exist,
224 * so create it. Ignore errors, if it already exists. */
225 dirname = talloc_asprintf(tmp_ctx, "%s.d", sam_name);
226 if (!dirname) {
227 talloc_free(tmp_ctx);
228 return ldb_oom(ldb);
231 mkdir(dirname, 0700);
232 talloc_free(dirname);
233 } else {
234 if (stat(filename, &statbuf) != 0) {
235 talloc_free(tmp_ctx);
236 return LDB_ERR_OPERATIONS_ERROR;
240 lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
241 struct loadparm_context);
243 data->metadata->db = tdb_wrap_open(
244 data->metadata, filename, 10,
245 lpcfg_tdb_flags(lp_ctx, TDB_DEFAULT|TDB_SEQNUM), open_flags, 0660);
246 if (data->metadata->db == NULL) {
247 talloc_free(tmp_ctx);
248 if (create) {
249 ldb_asprintf_errstring(ldb, "partition_metadata: Unable to create %s: %s",
250 filename, strerror(errno));
251 } else {
252 ldb_asprintf_errstring(ldb, "partition_metadata: Unable to open %s: %s",
253 filename, strerror(errno));
255 if (errno == EACCES || errno == EPERM) {
256 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
258 return LDB_ERR_OPERATIONS_ERROR;
261 talloc_free(tmp_ctx);
262 return LDB_SUCCESS;
267 * Set the sequence number calculated from older logic (sum of primary sequence
268 * numbers for each partition) as LDB_METADATA_SEQ_NUM key.
270 static int partition_metadata_set_sequence_number(struct ldb_module *module)
272 int ret;
273 uint64_t seq_number;
275 ret = partition_sequence_number_from_partitions(module, &seq_number);
276 if (ret != LDB_SUCCESS) {
277 return ret;
280 return partition_metadata_set_uint64(module, LDB_METADATA_SEQ_NUM, seq_number, true);
285 * Initialize metadata. Load metadata.tdb.
286 * If missing, create it and fill in sequence number
288 int partition_metadata_init(struct ldb_module *module)
290 struct partition_private_data *data;
291 int ret;
293 data = talloc_get_type_abort(ldb_module_get_private(module),
294 struct partition_private_data);
296 data->metadata = talloc_zero(data, struct partition_metadata);
297 if (data->metadata == NULL) {
298 return ldb_module_oom(module);
301 ret = partition_metadata_open(module, false);
302 if (ret == LDB_SUCCESS) {
303 goto end;
306 /* metadata.tdb does not exist, create it */
307 DEBUG(2, ("partition_metadata: Migrating partition metadata: "
308 "open of metadata.tdb gave: %s\n",
309 ldb_errstring(ldb_module_get_ctx(module))));
310 ret = partition_metadata_open(module, true);
311 if (ret != LDB_SUCCESS) {
312 ldb_asprintf_errstring(ldb_module_get_ctx(module),
313 "partition_metadata: "
314 "Migrating partition metadata: "
315 "create of metadata.tdb gave: %s\n",
316 ldb_errstring(ldb_module_get_ctx(module)));
317 talloc_free(data->metadata);
318 data->metadata = NULL;
319 goto end;
322 ret = partition_metadata_set_sequence_number(module);
323 if (ret != LDB_SUCCESS) {
324 talloc_free(data->metadata);
325 data->metadata = NULL;
328 end:
329 return ret;
334 * Read the sequence number, default to 0 if LDB_METADATA_SEQ_NUM key is missing
336 int partition_metadata_sequence_number(struct ldb_module *module, uint64_t *value)
338 return partition_metadata_get_uint64(module,
339 LDB_METADATA_SEQ_NUM,
340 value,
346 * Increment the sequence number, returning the new sequence number
348 int partition_metadata_sequence_number_increment(struct ldb_module *module, uint64_t *value)
350 struct partition_private_data *data;
351 int ret;
353 data = talloc_get_type_abort(ldb_module_get_private(module),
354 struct partition_private_data);
355 if (!data || !data->metadata) {
356 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
357 "partition_metadata: metadata not initialized");
360 if (data->metadata->in_transaction == 0) {
361 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
362 "partition_metadata: increment sequence number without transaction");
365 ret = partition_metadata_get_uint64(module, LDB_METADATA_SEQ_NUM, value, 0);
366 if (ret != LDB_SUCCESS) {
367 return ret;
370 (*value)++;
371 ret = partition_metadata_set_uint64(module, LDB_METADATA_SEQ_NUM, *value, false);
372 return ret;
377 * Transaction start
379 int partition_metadata_start_trans(struct ldb_module *module)
381 struct partition_private_data *data;
382 struct tdb_context *tdb;
384 data = talloc_get_type_abort(ldb_module_get_private(module),
385 struct partition_private_data);
386 if (!data || !data->metadata || !data->metadata->db) {
387 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
388 "partition_metadata: metadata not initialized");
390 tdb = data->metadata->db->tdb;
392 if (tdb_transaction_start(tdb) != 0) {
393 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
394 tdb_errorstr(tdb));
397 data->metadata->in_transaction++;
399 return LDB_SUCCESS;
404 * Transaction prepare commit
406 int partition_metadata_prepare_commit(struct ldb_module *module)
408 struct partition_private_data *data;
409 struct tdb_context *tdb;
411 data = talloc_get_type_abort(ldb_module_get_private(module),
412 struct partition_private_data);
413 if (!data || !data->metadata || !data->metadata->db) {
414 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
415 "partition_metadata: metadata not initialized");
417 tdb = data->metadata->db->tdb;
419 if (data->metadata->in_transaction == 0) {
420 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
421 "partition_metadata: not in transaction");
424 if (tdb_transaction_prepare_commit(tdb) != 0) {
425 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
426 tdb_errorstr(tdb));
429 return LDB_SUCCESS;
434 * Transaction end
436 int partition_metadata_end_trans(struct ldb_module *module)
438 struct partition_private_data *data;
439 struct tdb_context *tdb;
441 data = talloc_get_type_abort(ldb_module_get_private(module),
442 struct partition_private_data);
443 if (!data || !data->metadata || !data->metadata->db) {
444 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
445 "partition_metadata: metadata not initialized");
447 tdb = data->metadata->db->tdb;
449 if (data->metadata->in_transaction == 0) {
450 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
451 "partition_metadata: not in transaction");
454 data->metadata->in_transaction--;
456 if (tdb_transaction_commit(tdb) != 0) {
457 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
458 tdb_errorstr(tdb));
461 return LDB_SUCCESS;
466 * Transaction delete
468 int partition_metadata_del_trans(struct ldb_module *module)
470 struct partition_private_data *data;
471 struct tdb_context *tdb;
473 data = talloc_get_type_abort(ldb_module_get_private(module),
474 struct partition_private_data);
475 if (!data || !data->metadata || !data->metadata->db) {
476 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
477 "partition_metadata: metadata not initialized");
479 tdb = data->metadata->db->tdb;
481 if (data->metadata->in_transaction == 0) {
482 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
483 "partition_metadata: not in transaction");
486 data->metadata->in_transaction--;
488 tdb_transaction_cancel(tdb);
490 return LDB_SUCCESS;