summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs-xml/smbdotconf/printing/cupsencrypt.xml25
-rw-r--r--lib/tdb/common/transaction.c176
-rw-r--r--lib/tdb/configure.ac2
-rw-r--r--lib/tdb/docs/README8
-rw-r--r--lib/tdb/include/tdb.h1
-rw-r--r--lib/tdb/tools/tdbtorture.c6
-rw-r--r--source3/configure.in1
-rw-r--r--source3/include/proto.h1
-rw-r--r--source3/param/loadparm.c34
-rw-r--r--source3/printing/print_cups.c5
-rw-r--r--source3/smbd/dosmode.c12
-rw-r--r--source4/dsdb/samdb/ldb_modules/partition.c63
-rw-r--r--source4/lib/ldb/configure.ac2
-rw-r--r--source4/lib/ldb/external/libtdb.m42
-rw-r--r--source4/lib/ldb/include/ldb_module.h1
-rw-r--r--source4/lib/ldb/ldb.mk2
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_tdb.c33
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_tdb.h1
-rw-r--r--source4/min_versions.m44
19 files changed, 301 insertions, 78 deletions
diff --git a/docs-xml/smbdotconf/printing/cupsencrypt.xml b/docs-xml/smbdotconf/printing/cupsencrypt.xml
new file mode 100644
index 0000000000..f93b1c5935
--- /dev/null
+++ b/docs-xml/smbdotconf/printing/cupsencrypt.xml
@@ -0,0 +1,25 @@
+<samba:parameter name="cups encrypt"
+ context="G"
+ type="enum"
+ advanced="1" print="1"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+ <para>
+ This parameter is only applicable if <smbconfoption name="printing"/>
+ is set to <constant>cups</constant> and if you use CUPS newer than
+ 1.0.x.It is used to define whether or not Samba should use encryption
+ when talking to the CUPS server. Possible values are
+ <emphasis>auto</emphasis>, <emphasis>yes</emphasis> and
+ <emphasis>no</emphasis>
+ </para>
+
+ <para>
+ When set to auto we will try to do a TLS handshake on each CUPS
+ connection setup. If that fails, we will fall back to unencrypted
+ operation.
+ </para>
+
+</description>
+
+<value type="default">"no"</value>
+</samba:parameter>
diff --git a/lib/tdb/common/transaction.c b/lib/tdb/common/transaction.c
index 7acda640c8..1cb7063a38 100644
--- a/lib/tdb/common/transaction.c
+++ b/lib/tdb/common/transaction.c
@@ -116,6 +116,10 @@ struct tdb_transaction {
but don't create a new transaction */
int nesting;
+ /* set when a prepare has already occurred */
+ bool prepared;
+ tdb_off_t magic_offset;
+
/* old file size before transaction */
tdb_len_t old_map_size;
};
@@ -130,6 +134,14 @@ static int transaction_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
{
uint32_t blk;
+ /* Only a commit is allowed on a prepared transaction */
+ if (tdb->transaction->prepared) {
+ tdb->ecode = TDB_ERR_EINVAL;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_read: transaction already prepared, read not allowed\n"));
+ tdb->transaction->transaction_error = 1;
+ return -1;
+ }
+
/* break it down into block sized ops */
while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
@@ -187,6 +199,14 @@ static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
{
uint32_t blk;
+ /* Only a commit is allowed on a prepared transaction */
+ if (tdb->transaction->prepared) {
+ tdb->ecode = TDB_ERR_EINVAL;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: transaction already prepared, write not allowed\n"));
+ tdb->transaction->transaction_error = 1;
+ return -1;
+ }
+
/* if the write is to a hash head, then update the transaction
hash heads */
if (len == sizeof(tdb_off_t) && off >= FREELIST_TOP &&
@@ -498,11 +518,37 @@ fail:
/*
+ sync to disk
+*/
+static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t length)
+{
+ if (fsync(tdb->fd) != 0) {
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n"));
+ return -1;
+ }
+#ifdef HAVE_MMAP
+ if (tdb->map_ptr) {
+ tdb_off_t moffset = offset & ~(tdb->page_size-1);
+ if (msync(moffset + (char *)tdb->map_ptr,
+ length + (offset - moffset), MS_SYNC) != 0) {
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: msync failed - %s\n",
+ strerror(errno)));
+ return -1;
+ }
+ }
+#endif
+ return 0;
+}
+
+
+/*
cancel the current transaction
*/
int tdb_transaction_cancel(struct tdb_context *tdb)
{
- int i;
+ int i, ret = 0;
if (tdb->transaction == NULL) {
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_cancel: no transaction\n"));
@@ -525,6 +571,18 @@ int tdb_transaction_cancel(struct tdb_context *tdb)
}
SAFE_FREE(tdb->transaction->blocks);
+ if (tdb->transaction->magic_offset) {
+ const struct tdb_methods *methods = tdb->transaction->io_methods;
+ uint32_t zero = 0;
+
+ /* remove the recovery marker */
+ if (methods->tdb_write(tdb, tdb->transaction->magic_offset, &zero, 4) == -1 ||
+ transaction_sync(tdb, tdb->transaction->magic_offset, 4) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_cancel: failed to remove recovery magic\n"));
+ ret = -1;
+ }
+ }
+
/* remove any global lock created during the transaction */
if (tdb->global_lock.count != 0) {
tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 4*tdb->header.hash_size);
@@ -550,32 +608,7 @@ int tdb_transaction_cancel(struct tdb_context *tdb)
SAFE_FREE(tdb->transaction->hash_heads);
SAFE_FREE(tdb->transaction);
- return 0;
-}
-
-/*
- sync to disk
-*/
-static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t length)
-{
- if (fsync(tdb->fd) != 0) {
- tdb->ecode = TDB_ERR_IO;
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n"));
- return -1;
- }
-#ifdef HAVE_MMAP
- if (tdb->map_ptr) {
- tdb_off_t moffset = offset & ~(tdb->page_size-1);
- if (msync(moffset + (char *)tdb->map_ptr,
- length + (offset - moffset), MS_SYNC) != 0) {
- tdb->ecode = TDB_ERR_IO;
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: msync failed - %s\n",
- strerror(errno)));
- return -1;
- }
- }
-#endif
- return 0;
+ return ret;
}
@@ -826,36 +859,39 @@ static int transaction_setup_recovery(struct tdb_context *tdb,
}
/*
- commit the current transaction
+ prepare to commit the current transaction
*/
-int tdb_transaction_commit(struct tdb_context *tdb)
+int tdb_transaction_prepare_commit(struct tdb_context *tdb)
{
const struct tdb_methods *methods;
- tdb_off_t magic_offset = 0;
- uint32_t zero = 0;
int i;
if (tdb->transaction == NULL) {
- TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: no transaction\n"));
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: no transaction\n"));
+ return -1;
+ }
+
+ if (tdb->transaction->prepared) {
+ tdb->ecode = TDB_ERR_EINVAL;
+ tdb_transaction_cancel(tdb);
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction already prepared\n"));
return -1;
}
if (tdb->transaction->transaction_error) {
tdb->ecode = TDB_ERR_IO;
tdb_transaction_cancel(tdb);
- TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: transaction error pending\n"));
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction error pending\n"));
return -1;
}
if (tdb->transaction->nesting != 0) {
- tdb->transaction->nesting--;
return 0;
}
/* check for a null transaction */
if (tdb->transaction->blocks == NULL) {
- tdb_transaction_cancel(tdb);
return 0;
}
@@ -865,14 +901,14 @@ int tdb_transaction_commit(struct tdb_context *tdb)
nested their locks properly, so fail the transaction */
if (tdb->num_locks || tdb->global_lock.count) {
tdb->ecode = TDB_ERR_LOCK;
- TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: locks pending on commit\n"));
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: locks pending on commit\n"));
tdb_transaction_cancel(tdb);
return -1;
}
/* upgrade the main transaction lock region to a write lock */
if (tdb_brlock_upgrade(tdb, FREELIST_TOP, 0) == -1) {
- TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to upgrade hash locks\n"));
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to upgrade hash locks\n"));
tdb->ecode = TDB_ERR_LOCK;
tdb_transaction_cancel(tdb);
return -1;
@@ -881,7 +917,7 @@ int tdb_transaction_commit(struct tdb_context *tdb)
/* get the global lock - this prevents new users attaching to the database
during the commit */
if (tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
- TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: failed to get global lock\n"));
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to get global lock\n"));
tdb->ecode = TDB_ERR_LOCK;
tdb_transaction_cancel(tdb);
return -1;
@@ -889,21 +925,23 @@ int tdb_transaction_commit(struct tdb_context *tdb)
if (!(tdb->flags & TDB_NOSYNC)) {
/* write the recovery data to the end of the file */
- if (transaction_setup_recovery(tdb, &magic_offset) == -1) {
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: failed to setup recovery data\n"));
+ if (transaction_setup_recovery(tdb, &tdb->transaction->magic_offset) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: failed to setup recovery data\n"));
tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
tdb_transaction_cancel(tdb);
return -1;
}
}
+ tdb->transaction->prepared = true;
+
/* expand the file to the new size if needed */
if (tdb->map_size != tdb->transaction->old_map_size) {
if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size,
tdb->map_size -
tdb->transaction->old_map_size) == -1) {
tdb->ecode = TDB_ERR_IO;
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: expansion failed\n"));
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: expansion failed\n"));
tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
tdb_transaction_cancel(tdb);
return -1;
@@ -912,6 +950,51 @@ int tdb_transaction_commit(struct tdb_context *tdb)
methods->tdb_oob(tdb, tdb->map_size + 1, 1);
}
+ /* Keep the global lock until the actual commit */
+
+ return 0;
+}
+
+/*
+ commit the current transaction
+*/
+int tdb_transaction_commit(struct tdb_context *tdb)
+{
+ const struct tdb_methods *methods;
+ int i;
+
+ if (tdb->transaction == NULL) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: no transaction\n"));
+ return -1;
+ }
+
+ if (tdb->transaction->transaction_error) {
+ tdb->ecode = TDB_ERR_IO;
+ tdb_transaction_cancel(tdb);
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: transaction error pending\n"));
+ return -1;
+ }
+
+
+ if (tdb->transaction->nesting != 0) {
+ tdb->transaction->nesting--;
+ return 0;
+ }
+
+ /* check for a null transaction */
+ if (tdb->transaction->blocks == NULL) {
+ tdb_transaction_cancel(tdb);
+ return 0;
+ }
+
+ if (!tdb->transaction->prepared) {
+ int ret = tdb_transaction_prepare_commit(tdb);
+ if (ret)
+ return ret;
+ }
+
+ methods = tdb->transaction->io_methods;
+
/* perform all the writes */
for (i=0;i<tdb->transaction->num_blocks;i++) {
tdb_off_t offset;
@@ -953,17 +1036,6 @@ int tdb_transaction_commit(struct tdb_context *tdb)
if (transaction_sync(tdb, 0, tdb->map_size) == -1) {
return -1;
}
-
- /* remove the recovery marker */
- if (methods->tdb_write(tdb, magic_offset, &zero, 4) == -1) {
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: failed to remove recovery magic\n"));
- return -1;
- }
-
- /* ensure the recovery marker has been removed on disk */
- if (transaction_sync(tdb, magic_offset, 4) == -1) {
- return -1;
- }
}
tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
diff --git a/lib/tdb/configure.ac b/lib/tdb/configure.ac
index 2feaa6f5f5..c42a970721 100644
--- a/lib/tdb/configure.ac
+++ b/lib/tdb/configure.ac
@@ -2,7 +2,7 @@ AC_PREREQ(2.50)
AC_DEFUN([SMB_MODULE_DEFAULT], [echo -n ""])
AC_DEFUN([SMB_LIBRARY_ENABLE], [echo -n ""])
AC_DEFUN([SMB_ENABLE], [echo -n ""])
-AC_INIT(tdb, 1.1.3)
+AC_INIT(tdb, 1.1.4)
AC_CONFIG_SRCDIR([common/tdb.c])
AC_CONFIG_HEADER(include/config.h)
AC_LIBREPLACE_ALL_CHECKS
diff --git a/lib/tdb/docs/README b/lib/tdb/docs/README
index 63fcf5e049..454e4ba032 100644
--- a/lib/tdb/docs/README
+++ b/lib/tdb/docs/README
@@ -236,3 +236,11 @@ int tdb_transaction_commit(TDB_CONTEXT *tdb)
commit a current transaction, updating the database and releasing
the transaction locks.
+----------------------------------------------------------------------
+int tdb_transaction_prepare_commit(TDB_CONTEXT *tdb)
+
+ prepare to commit a current transaction, for two-phase commits.
+ Once prepared for commit, the only allowed calls are
+ tdb_transaction_commit() or tdb_transaction_cancel(). Preparing
+ allocates disk space for the pending updates, so a subsequent
+ commit should succeed (barring any hardware failures).
diff --git a/lib/tdb/include/tdb.h b/lib/tdb/include/tdb.h
index 94b5e366b9..22496f56f0 100644
--- a/lib/tdb/include/tdb.h
+++ b/lib/tdb/include/tdb.h
@@ -129,6 +129,7 @@ int tdb_fd(struct tdb_context *tdb);
tdb_log_func tdb_log_fn(struct tdb_context *tdb);
void *tdb_get_logging_private(struct tdb_context *tdb);
int tdb_transaction_start(struct tdb_context *tdb);
+int tdb_transaction_prepare_commit(struct tdb_context *tdb);
int tdb_transaction_commit(struct tdb_context *tdb);
int tdb_transaction_cancel(struct tdb_context *tdb);
int tdb_transaction_recover(struct tdb_context *tdb);
diff --git a/lib/tdb/tools/tdbtorture.c b/lib/tdb/tools/tdbtorture.c
index 9265cf07aa..0c9bbd613d 100644
--- a/lib/tdb/tools/tdbtorture.c
+++ b/lib/tdb/tools/tdbtorture.c
@@ -18,6 +18,7 @@
#define STORE_PROB 4
#define APPEND_PROB 6
#define TRANSACTION_PROB 10
+#define TRANSACTION_PREPARE_PROB 2
#define LOCKSTORE_PROB 5
#define TRAVERSE_PROB 20
#define TRAVERSE_READ_PROB 20
@@ -109,6 +110,11 @@ static void addrec_db(void)
goto next;
}
if (in_transaction && random() % TRANSACTION_PROB == 0) {
+ if (random() % TRANSACTION_PREPARE_PROB == 0) {
+ if (tdb_transaction_prepare_commit(db) != 0) {
+ fatal("tdb_transaction_prepare_commit failed");
+ }
+ }
if (tdb_transaction_commit(db) != 0) {
fatal("tdb_transaction_commit failed");
}
diff --git a/source3/configure.in b/source3/configure.in
index 1cf8d9ca4a..0850bf5a7f 100644
--- a/source3/configure.in
+++ b/source3/configure.in
@@ -788,6 +788,7 @@ if test x$enable_cups != xno; then
x"$ac_cv_header_cups_language_h" = xyes; then
AC_DEFINE(HAVE_CUPS,1,[Whether we have CUPS])
samba_cv_HAVE_CUPS=yes
+ AC_CHECK_LIB_EXT(cups, PRINT_LIBS, httpConnectEncrypt)
else
AC_MSG_WARN([cups-config around but cups-devel not installed])
CFLAGS=$ac_save_CFLAGS
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 77be0aba09..2e76764e01 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -4125,6 +4125,7 @@ const char **lp_admin_users(int );
const char **lp_svcctl_list(void);
char *lp_cups_options(int );
char *lp_cups_server(void);
+int lp_cups_encrypt(void);
char *lp_iprint_server(void);
int lp_cups_connection_timeout(void);
const char *lp_ctdbd_socket(void);
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 66fb8bf1bc..8da1f6348f 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -54,6 +54,10 @@
#include "includes.h"
#include "printing.h"
+#ifdef HAVE_HTTPCONNECTENCRYPT
+#include <cups/http.h>
+#endif
+
bool bLoaded = False;
extern enum protocol_types Protocol;
@@ -257,6 +261,7 @@ struct global {
int ldap_debug_threshold;
int iAclCompat;
char *szCupsServer;
+ int CupsEncrypt;
char *szIPrintServer;
char *ctdbdSocket;
char **szClusterAddresses;
@@ -774,6 +779,8 @@ static const struct enum_list enum_case[] = {
{-1, NULL}
};
+
+
static const struct enum_list enum_bool_auto[] = {
{False, "No"},
{False, "False"},
@@ -2628,6 +2635,16 @@ static struct parm_struct parm_table[] = {
.flags = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL,
},
{
+ .label = "cups encrypt",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.CupsEncrypt,
+ .special = NULL,
+ .enum_list = enum_bool_auto,
+ .flags = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL,
+ },
+ {
+
.label = "cups connection timeout",
.type = P_INTEGER,
.p_class = P_GLOBAL,
@@ -5471,6 +5488,23 @@ FN_LOCAL_LIST(lp_admin_users, szAdminUsers)
FN_GLOBAL_LIST(lp_svcctl_list, &Globals.szServicesList)
FN_LOCAL_STRING(lp_cups_options, szCupsOptions)
FN_GLOBAL_STRING(lp_cups_server, &Globals.szCupsServer)
+int lp_cups_encrypt(void)
+{
+#ifdef HAVE_HTTPCONNECTENCRYPT
+ switch (Globals.CupsEncrypt) {
+ case Auto:
+ Globals.CupsEncrypt = HTTP_ENCRYPT_REQUIRED;
+ break;
+ case True:
+ Globals.CupsEncrypt = HTTP_ENCRYPT_ALWAYS;
+ break;
+ case False:
+ Globals.CupsEncrypt = HTTP_ENCRYPT_NEVER;
+ break;
+ }
+#endif
+ return Globals.CupsEncrypt;
+}
FN_GLOBAL_STRING(lp_iprint_server, &Globals.szIPrintServer)
FN_GLOBAL_INTEGER(lp_cups_connection_timeout, &Globals.cups_connection_timeout)
FN_GLOBAL_CONST_STRING(lp_ctdbd_socket, &Globals.ctdbdSocket)
diff --git a/source3/printing/print_cups.c b/source3/printing/print_cups.c
index 8e792a944a..7edfb5edbe 100644
--- a/source3/printing/print_cups.c
+++ b/source3/printing/print_cups.c
@@ -93,7 +93,12 @@ static http_t *cups_connect(TALLOC_CTX *frame)
alarm(timeout);
}
+#ifdef HAVE_HTTPCONNECTENCRYPT
+ http = httpConnectEncrypt(server, port, lp_cups_encrypt());
+#else
http = httpConnect(server, port);
+#endif
+
CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
alarm(0);
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index 555718bd83..5ae7151303 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -325,8 +325,10 @@ uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT
} else {
p = path;
}
-
- if (p[0] == '.' && p[1] != '.' && p[1] != 0) {
+
+ /* Only . and .. are not hidden. */
+ if (p[0] == '.' && !((p[1] == '\0') ||
+ (p[1] == '.' && p[2] == '\0'))) {
result |= aHIDDEN;
}
}
@@ -484,8 +486,10 @@ uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
} else {
p = path;
}
-
- if (p[0] == '.' && p[1] != '.' && p[1] != 0) {
+
+ /* Only . and .. are not hidden. */
+ if (p[0] == '.' && !((p[1] == '\0') ||
+ (p[1] == '.' && p[2] == '\0'))) {
result |= aHIDDEN;
}
}
diff --git a/source4/dsdb/samdb/ldb_modules/partition.c b/source4/dsdb/samdb/ldb_modules/partition.c
index 71a1b8e942..3231f7ab0f 100644
--- a/source4/dsdb/samdb/ldb_modules/partition.c
+++ b/source4/dsdb/samdb/ldb_modules/partition.c
@@ -73,11 +73,14 @@ static struct partition_context *partition_init_ctx(struct ldb_module *module, s
return ac;
}
-#define PARTITION_FIND_OP(module, op) do { \
- struct ldb_context *ldbctx = module->ldb; \
+#define PARTITION_FIND_OP_NOERROR(module, op) do { \
while (module && module->ops->op == NULL) module = module->next; \
+} while (0)
+
+#define PARTITION_FIND_OP(module, op) do { \
+ PARTITION_FIND_OP_NOERROR(module, op); \
if (module == NULL) { \
- ldb_asprintf_errstring(ldbctx, \
+ ldb_asprintf_errstring(module->ldb, \
"Unable to find backend operation for " #op ); \
return LDB_ERR_OPERATIONS_ERROR; \
} \
@@ -654,7 +657,7 @@ static int partition_start_trans(struct ldb_module *module)
/* end a transaction */
static int partition_end_trans(struct ldb_module *module)
{
- int i, ret;
+ int i, ret, final_ret;
struct partition_private_data *data = talloc_get_type(module->private_data,
struct partition_private_data);
ret = ldb_next_end_trans(module);
@@ -662,28 +665,60 @@ static int partition_end_trans(struct ldb_module *module)
return ret;
}
+ /* if the backend has a prepare_commit op then use that, to ensure
+ that all partitions are committed safely together */
+ for (i=0; data && data->partitions && data->partitions[i]; i++) {
+ struct ldb_module *next_end = data->partitions[i]->module;
+ struct ldb_module *next_prepare = data->partitions[i]->module;
+ struct ldb_module *next_del = data->partitions[i]->module;
+
+ PARTITION_FIND_OP_NOERROR(next_prepare, prepare_commit);
+ if (next_prepare == NULL) {
+ continue;
+ }
+
+ PARTITION_FIND_OP(next_end, end_transaction);
+ PARTITION_FIND_OP(next_del, del_transaction);
+
+ if (next_end != next_prepare || next_del != next_end) {
+ ldb_asprintf_errstring(module->ldb, "ERROR: Mismatch between prepare and commit ops in ldb module");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = next_prepare->ops->prepare_commit(next_prepare);
+ if (ret != LDB_SUCCESS) {
+ /* if one fails, cancel all but this one */
+ int j;
+ for (j=0; data->partitions[j]; j++) {
+ if (j == i) continue;
+ next_del = data->partitions[j]->module;
+ PARTITION_FIND_OP(next_del, del_transaction);
+ next_del->ops->del_transaction(next_del);
+ }
+ ldb_next_del_trans(module);
+ return ret;
+ }
+ }
+
/* Look at base DN */
/* Figure out which partition it is under */
/* Skip the lot if 'data' isn't here yet (initialistion) */
+ final_ret = LDB_SUCCESS;
+
for (i=0; data && data->partitions && data->partitions[i]; i++) {
struct ldb_module *next = data->partitions[i]->module;
PARTITION_FIND_OP(next, end_transaction);
ret = next->ops->end_transaction(next);
if (ret != LDB_SUCCESS) {
- /* Back it out, if it fails on one */
- for (i--; i >= 0; i--) {
- next = data->partitions[i]->module;
- PARTITION_FIND_OP(next, del_transaction);
-
- next->ops->del_transaction(next);
- }
- ldb_next_del_trans(module);
- return ret;
+ /* this should only be happening if we had a serious
+ OS or hardware error */
+ ldb_asprintf_errstring(module->ldb, "ERROR: partition commit error");
+ final_ret = ret;
}
}
- return LDB_SUCCESS;
+ return final_ret;
}
/* delete a transaction */
diff --git a/source4/lib/ldb/configure.ac b/source4/lib/ldb/configure.ac
index d61b31afd4..b98cc88537 100644
--- a/source4/lib/ldb/configure.ac
+++ b/source4/lib/ldb/configure.ac
@@ -11,7 +11,7 @@ AC_DEFUN([SMB_MODULE_DEFAULT], [echo -n ""])
AC_DEFUN([SMB_LIBRARY_ENABLE], [echo -n ""])
AC_DEFUN([SMB_EXT_LIB], [echo -n ""])
AC_DEFUN([SMB_ENABLE], [echo -n ""])
-AC_INIT(ldb, 0.9.3)
+AC_INIT(ldb, 0.9.4)
AC_CONFIG_SRCDIR([common/ldb.c])
AC_LIBREPLACE_ALL_CHECKS
diff --git a/source4/lib/ldb/external/libtdb.m4 b/source4/lib/ldb/external/libtdb.m4
index 8c2cab702f..cdfc5ea2fb 100644
--- a/source4/lib/ldb/external/libtdb.m4
+++ b/source4/lib/ldb/external/libtdb.m4
@@ -4,4 +4,4 @@ AC_SUBST(TDB_LIBS)
AC_CHECK_HEADER(tdb.h,
[AC_CHECK_LIB(tdb, tdb_open, [TDB_LIBS="-ltdb"]) ],
- [PKG_CHECK_MODULES(TDB, tdb >= 1.1.0)])
+ [PKG_CHECK_MODULES(TDB, tdb >= 1.1.4)])
diff --git a/source4/lib/ldb/include/ldb_module.h b/source4/lib/ldb/include/ldb_module.h
index 4e1019184d..e07fd43e27 100644
--- a/source4/lib/ldb/include/ldb_module.h
+++ b/source4/lib/ldb/include/ldb_module.h
@@ -52,6 +52,7 @@ struct ldb_module_ops {
int (*request)(struct ldb_module *, struct ldb_request *); /* match any other operation */
int (*extended)(struct ldb_module *, struct ldb_request *); /* extended operations */
int (*start_transaction)(struct ldb_module *);
+ int (*prepare_commit)(struct ldb_module *);
int (*end_transaction)(struct ldb_module *);
int (*del_transaction)(struct ldb_module *);
int (*sequence_number)(struct ldb_module *, struct ldb_request *);
diff --git a/source4/lib/ldb/ldb.mk b/source4/lib/ldb/ldb.mk
index ff8c1f3baf..0589baf5d4 100644
--- a/source4/lib/ldb/ldb.mk
+++ b/source4/lib/ldb/ldb.mk
@@ -66,7 +66,7 @@ build-python:: ldb.$(SHLIBEXT)
pyldb.o: $(ldbdir)/pyldb.c
$(CC) $(PICFLAG) -c $(ldbdir)/pyldb.c $(CFLAGS) `$(PYTHON_CONFIG) --cflags`
-
+
ldb.$(SHLIBEXT): pyldb.o
$(SHLD) $(SHLD_FLAGS) -o ldb.$(SHLIBEXT) pyldb.o $(LIB_FLAGS) `$(PYTHON_CONFIG) --ldflags`
diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.c b/source4/lib/ldb/ldb_tdb/ldb_tdb.c
index 9df62be936..0f84b67afa 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -857,18 +857,46 @@ static int ltdb_start_trans(struct ldb_module *module)
return LDB_SUCCESS;
}
-static int ltdb_end_trans(struct ldb_module *module)
+static int ltdb_prepare_commit(struct ldb_module *module)
{
void *data = ldb_module_get_private(module);
struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
- ltdb->in_transaction--;
+ if (ltdb->in_transaction != 1) {
+ return LDB_SUCCESS;
+ }
if (ltdb_index_transaction_commit(module) != 0) {
tdb_transaction_cancel(ltdb->tdb);
+ ltdb->in_transaction--;
+ return ltdb_err_map(tdb_error(ltdb->tdb));
+ }
+
+ if (tdb_transaction_prepare_commit(ltdb->tdb) != 0) {
+ ltdb->in_transaction--;
return ltdb_err_map(tdb_error(ltdb->tdb));
}
+ ltdb->prepared_commit = true;
+
+ return LDB_SUCCESS;
+}
+
+static int ltdb_end_trans(struct ldb_module *module)
+{
+ void *data = ldb_module_get_private(module);
+ struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
+
+ if (!ltdb->prepared_commit) {
+ int ret = ltdb_prepare_commit(module);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ ltdb->in_transaction--;
+ ltdb->prepared_commit = false;
+
if (tdb_transaction_commit(ltdb->tdb) != 0) {
return ltdb_err_map(tdb_error(ltdb->tdb));
}
@@ -1209,6 +1237,7 @@ static const struct ldb_module_ops ltdb_ops = {
.extended = ltdb_handle_request,
.start_transaction = ltdb_start_trans,
.end_transaction = ltdb_end_trans,
+ .prepare_commit = ltdb_prepare_commit,
.del_transaction = ltdb_del_trans,
};
diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.h b/source4/lib/ldb/ldb_tdb/ldb_tdb.h
index 5a1c8fee2d..370cd0729b 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -30,6 +30,7 @@ struct ltdb_private {
bool check_base;
struct ltdb_idxptr *idxptr;
+ bool prepared_commit;
};
/*
diff --git a/source4/min_versions.m4 b/source4/min_versions.m4
index 1dd3501b99..0469fb827a 100644
--- a/source4/min_versions.m4
+++ b/source4/min_versions.m4
@@ -1,6 +1,6 @@
# Minimum and exact required versions for various libraries
# if we use the ones installed in the system.
-define(TDB_MIN_VERSION,1.1.3)
+define(TDB_MIN_VERSION,1.1.4)
define(TALLOC_MIN_VERSION,1.3.0)
-define(LDB_REQUIRED_VERSION,0.9.3)
+define(LDB_REQUIRED_VERSION,0.9.4)
define(TEVENT_REQUIRED_VERSION,0.9.5)