summaryrefslogtreecommitdiff
path: root/lib/dbwrap/dbwrap_rbt.c
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2015-11-25 09:22:08 +0100
committerStefan Metzmacher <metze@samba.org>2015-11-27 10:10:18 +0100
commit590507951fc514a679f44b8bfdd03c721189c3fa (patch)
treef8ec34218660bbdadfa4babddb9db09aecfbba89 /lib/dbwrap/dbwrap_rbt.c
parentf3d1fc1d06822a951a2a3eeb5aa53748b9b5b299 (diff)
downloadsamba-590507951fc514a679f44b8bfdd03c721189c3fa.tar.gz
dbwrap_rbt: add nested traverse protection
Multiple dbwrap_traverse_read() calls are possible. store() and delete() on a fetch locked record are rejected during dbwrap_traverse_read(). A dbwrap_traverse() within a dbwrap_traverse_read() behaves like a dbwrap_traverse_read(). Nested dbwrap_traverse() calls are not possible. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11375 BUG: https://bugzilla.samba.org/show_bug.cgi?id=11394 Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Volker Lendecke <vl@samba.org>
Diffstat (limited to 'lib/dbwrap/dbwrap_rbt.c')
-rw-r--r--lib/dbwrap/dbwrap_rbt.c71
1 files changed, 40 insertions, 31 deletions
diff --git a/lib/dbwrap/dbwrap_rbt.c b/lib/dbwrap/dbwrap_rbt.c
index 37d9649a759..622ab0dd24b 100644
--- a/lib/dbwrap/dbwrap_rbt.c
+++ b/lib/dbwrap/dbwrap_rbt.c
@@ -27,6 +27,8 @@
struct db_rbt_ctx {
struct rb_root tree;
+ size_t traverse_read;
+ bool traverse_write;
};
struct db_rbt_rec {
@@ -126,6 +128,10 @@ static NTSTATUS db_rbt_store(struct db_record *rec, TDB_DATA data, int flag)
ssize_t reclen;
TDB_DATA this_key, this_val;
+ if (db_ctx->traverse_read > 0) {
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+ }
+
if (rec_priv->node != NULL) {
/*
@@ -222,6 +228,10 @@ static NTSTATUS db_rbt_delete(struct db_record *rec)
rec->db->private_data, struct db_rbt_ctx);
struct db_rbt_rec *rec_priv = (struct db_rbt_rec *)rec->private_data;
+ if (db_ctx->traverse_read > 0) {
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+ }
+
if (rec_priv->node == NULL) {
return NT_STATUS_OK;
}
@@ -232,16 +242,6 @@ static NTSTATUS db_rbt_delete(struct db_record *rec)
return NT_STATUS_OK;
}
-static NTSTATUS db_rbt_store_deny(struct db_record *rec, TDB_DATA data, int flag)
-{
- return NT_STATUS_MEDIA_WRITE_PROTECTED;
-}
-
-static NTSTATUS db_rbt_delete_deny(struct db_record *rec)
-{
- return NT_STATUS_MEDIA_WRITE_PROTECTED;
-}
-
struct db_rbt_search_result {
TDB_DATA key;
TDB_DATA val;
@@ -414,13 +414,8 @@ static int db_rbt_traverse_internal(struct db_context *db,
ZERO_STRUCT(rec);
rec.db = db;
rec.private_data = &rec_priv;
- if (rw) {
- rec.store = db_rbt_store;
- rec.delete_rec = db_rbt_delete;
- } else {
- rec.store = db_rbt_store_deny;
- rec.delete_rec = db_rbt_delete_deny;
- }
+ rec.store = db_rbt_store;
+ rec.delete_rec = db_rbt_delete;
db_rbt_parse_node(rec_priv.node, &rec.key, &rec.value);
ret = f(&rec, private_data);
@@ -440,18 +435,21 @@ static int db_rbt_traverse_internal(struct db_context *db,
return db_rbt_traverse_internal(db, rb_right, f, private_data, count, rw);
}
-static int db_rbt_traverse(struct db_context *db,
- int (*f)(struct db_record *db,
- void *private_data),
- void *private_data)
+static int db_rbt_traverse_read(struct db_context *db,
+ int (*f)(struct db_record *db,
+ void *private_data),
+ void *private_data)
{
struct db_rbt_ctx *ctx = talloc_get_type_abort(
db->private_data, struct db_rbt_ctx);
uint32_t count = 0;
+ int ret;
- int ret = db_rbt_traverse_internal(db, ctx->tree.rb_node,
- f, private_data, &count,
- true /* rw */);
+ ctx->traverse_read++;
+ ret = db_rbt_traverse_internal(db, ctx->tree.rb_node,
+ f, private_data, &count,
+ false /* rw */);
+ ctx->traverse_read--;
if (ret != 0) {
return -1;
}
@@ -461,18 +459,29 @@ static int db_rbt_traverse(struct db_context *db,
return count;
}
-static int db_rbt_traverse_read(struct db_context *db,
- int (*f)(struct db_record *db,
- void *private_data),
- void *private_data)
+static int db_rbt_traverse(struct db_context *db,
+ int (*f)(struct db_record *db,
+ void *private_data),
+ void *private_data)
{
struct db_rbt_ctx *ctx = talloc_get_type_abort(
db->private_data, struct db_rbt_ctx);
uint32_t count = 0;
+ int ret;
+
+ if (ctx->traverse_write) {
+ return -1;
+ };
+
+ if (ctx->traverse_read > 0) {
+ return db_rbt_traverse_read(db, f, private_data);
+ }
- int ret = db_rbt_traverse_internal(db, ctx->tree.rb_node,
- f, private_data, &count,
- false /* rw */);
+ ctx->traverse_write = true;
+ ret = db_rbt_traverse_internal(db, ctx->tree.rb_node,
+ f, private_data, &count,
+ true /* rw */);
+ ctx->traverse_write = false;
if (ret != 0) {
return -1;
}