diff --git a/.gitignore b/.gitignore
index 4115b2d..7e13c2f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/tdb-1.3.8.tar.gz
+SOURCES/tdb-1.3.12.tar.gz
diff --git a/.libtdb.metadata b/.libtdb.metadata
index b7b6ff6..ffea0e7 100644
--- a/.libtdb.metadata
+++ b/.libtdb.metadata
@@ -1 +1 @@
-3ac6779e14ed37caa27d5243777a2c7c485ef087 SOURCES/tdb-1.3.8.tar.gz
+86fec2b5e698ef15da07be4a26672773575e37cd SOURCES/tdb-1.3.12.tar.gz
diff --git a/SOURCES/0001-waf-disable-python-align-tdb-s-wscript.patch b/SOURCES/0001-waf-disable-python-align-tdb-s-wscript.patch
new file mode 100644
index 0000000..afa0bbb
--- /dev/null
+++ b/SOURCES/0001-waf-disable-python-align-tdb-s-wscript.patch
@@ -0,0 +1,52 @@
+From 81ff0f306523079396e8538d5cbff7e9f008f062 Mon Sep 17 00:00:00 2001
+From: Ian Stakenvicius <axs@gentoo.org>
+Date: Fri, 27 Jan 2017 14:42:05 -0500
+Subject: [PATCH] waf: disable-python - align tdb's wscript
+
+Drop the configure option for --disable-python as it is now
+global in wafsamba.
+
+If samba is set to use a system copy of tdb, and tdb wasn't built
+with python support, then the system pytevent will not be found.  If
+samba is being built without python support then pytdb is not needed,
+so do not bother to try and find it.
+
+Signed-off-by: Ian Stakenvicius <axs@gentoo.org>
+Reviewed-by: Andrew Bartlett <abartlet@samba.org>
+Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
+---
+ lib/tdb/wscript | 9 ++-------
+ 1 file changed, 2 insertions(+), 7 deletions(-)
+
+diff --git a/lib/tdb/wscript b/lib/tdb/wscript
+index 34058e4c9fa5889c627a89c2e1a1731390555f84..0d682ebb4cdaa001904e0b40e50e1a2e46f230ee 100644
+--- a/lib/tdb/wscript
++++ b/lib/tdb/wscript
+@@ -60,10 +60,6 @@ def set_options(opt):
+                    help=("Disable the use of pthread robust mutexes"),
+                    action="store_true", dest='disable_tdb_mutex_locking',
+                    default=False)
+-    if opt.IN_LAUNCH_DIR():
+-        opt.add_option('--disable-python',
+-                       help=("disable the pytdb module"),
+-                       action="store_true", dest='disable_python', default=False)
+ 
+ 
+ def configure(conf):
+@@ -82,11 +78,10 @@ def configure(conf):
+                                      implied_deps='replace'):
+             conf.define('USING_SYSTEM_TDB', 1)
+             conf.env.building_tdb = False
+-            if conf.CHECK_BUNDLED_SYSTEM_PYTHON('pytdb', 'tdb', minversion=VERSION):
++            if not conf.env.disable_python and \
++                conf.CHECK_BUNDLED_SYSTEM_PYTHON('pytdb', 'tdb', minversion=VERSION):
+                 conf.define('USING_SYSTEM_PYTDB', 1)
+ 
+-    conf.env.disable_python = getattr(Options.options, 'disable_python', False)
+-
+     if (conf.CONFIG_SET('HAVE_ROBUST_MUTEXES') and
+         conf.env.building_tdb and
+         not conf.env.disable_tdb_mutex_locking):
+-- 
+2.9.3
+
diff --git a/SOURCES/0002-tdb-tools-add-documentation-for-the-tdbbackup-n-opti.patch b/SOURCES/0002-tdb-tools-add-documentation-for-the-tdbbackup-n-opti.patch
new file mode 100644
index 0000000..886de64
--- /dev/null
+++ b/SOURCES/0002-tdb-tools-add-documentation-for-the-tdbbackup-n-opti.patch
@@ -0,0 +1,43 @@
+From 0558715b5b125ffa7948f06451ea979c7045b20c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Bj=C3=B6rn=20Baumbach?= <bb@sernet.de>
+Date: Mon, 27 Mar 2017 17:43:07 +0200
+Subject: [PATCH] tdb/tools: add documentation for the tdbbackup -n option
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Björn Baumbach <bb@sernet.de>
+Reviewed-by: Jeremy Allison <jra@samba.org
+---
+ lib/tdb/man/tdbbackup.8.xml | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/lib/tdb/man/tdbbackup.8.xml b/lib/tdb/man/tdbbackup.8.xml
+index 740b3d5d5f302ffa032250e81ce84b51565f600b..a73fb561b1849924d1f7b530e8a90d10eba2f746 100644
+--- a/lib/tdb/man/tdbbackup.8.xml
++++ b/lib/tdb/man/tdbbackup.8.xml
+@@ -23,6 +23,7 @@
+ 		<arg choice="opt">-s suffix</arg>
+ 		<arg choice="opt">-v</arg>
+ 		<arg choice="opt">-h</arg>
++		<arg choice="opt">-n hashsize</arg>
+ 		<arg choice="opt">-l</arg>
+ 	</cmdsynopsis>
+ </refsynopsisdiv>
+@@ -71,6 +72,13 @@
+ 		</varlistentry>
+ 
+ 		<varlistentry>
++		<term>-n hashsize</term>
++		<listitem><para>
++		The <command>-n</command> option sets the hash size for the new backup tdb.
++		</para></listitem>
++		</varlistentry>
++
++		<varlistentry>
+ 		<term>-l</term>
+ 		<listitem><para>
+ 		This options disables any locking, by passing TDB_NOLOCK
+-- 
+2.9.3
+
diff --git a/SOURCES/0003-tdb-Fix-some-signed-unsigned-hickups.patch b/SOURCES/0003-tdb-Fix-some-signed-unsigned-hickups.patch
new file mode 100644
index 0000000..4c11b8a
--- /dev/null
+++ b/SOURCES/0003-tdb-Fix-some-signed-unsigned-hickups.patch
@@ -0,0 +1,65 @@
+From 97cafdcfaaaff17ebffe873b5e31462f0d1268b1 Mon Sep 17 00:00:00 2001
+From: Volker Lendecke <vl@samba.org>
+Date: Mon, 7 Nov 2016 21:38:58 +0100
+Subject: [PATCH] tdb: Fix some signed/unsigned hickups
+
+Signed-off-by: Volker Lendecke <vl@samba.org>
+Reviewed-by: Jeremy Allison <jra@samba.org>
+---
+ lib/tdb/common/lock.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/lib/tdb/common/lock.c b/lib/tdb/common/lock.c
+index 195dbb5daf265c8d8f997a3ccdd81fe7b642945c..594c28751f1d68c8305bd225f228c437fee81c9e 100644
+--- a/lib/tdb/common/lock.c
++++ b/lib/tdb/common/lock.c
+@@ -294,7 +294,7 @@ fail:
+ static struct tdb_lock_type *find_nestlock(struct tdb_context *tdb,
+ 					   tdb_off_t offset)
+ {
+-	unsigned int i;
++	int i;
+ 
+ 	for (i=0; i<tdb->num_lockrecs; i++) {
+ 		if (tdb->lockrecs[i].off == offset) {
+@@ -381,7 +381,7 @@ static int tdb_lock_and_recover(struct tdb_context *tdb)
+ 
+ static bool have_data_locks(const struct tdb_context *tdb)
+ {
+-	unsigned int i;
++	int i;
+ 
+ 	for (i = 0; i < tdb->num_lockrecs; i++) {
+ 		if (tdb->lockrecs[i].off >= lock_offset(-1))
+@@ -560,7 +560,8 @@ static int tdb_allrecord_check(struct tdb_context *tdb, int ltype,
+ 		return -1;
+ 	}
+ 
+-	if (tdb->allrecord_lock.count && tdb->allrecord_lock.ltype == ltype) {
++	if (tdb->allrecord_lock.count &&
++	    tdb->allrecord_lock.ltype == (uint32_t)ltype) {
+ 		tdb->allrecord_lock.count++;
+ 		return 0;
+ 	}
+@@ -706,7 +707,7 @@ int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype, bool mark_lock)
+ 	}
+ 
+ 	/* Upgradable locks are marked as write locks. */
+-	if (tdb->allrecord_lock.ltype != ltype
++	if (tdb->allrecord_lock.ltype != (uint32_t)ltype
+ 	    && (!tdb->allrecord_lock.off || ltype != F_RDLCK)) {
+ 		tdb->ecode = TDB_ERR_LOCK;
+ 		return -1;
+@@ -945,7 +946,8 @@ bool tdb_have_extra_locks(struct tdb_context *tdb)
+ /* The transaction code uses this to remove all locks. */
+ void tdb_release_transaction_locks(struct tdb_context *tdb)
+ {
+-	unsigned int i, active = 0;
++	int i;
++	unsigned int active = 0;
+ 
+ 	if (tdb->allrecord_lock.count != 0) {
+ 		tdb_allrecord_unlock(tdb, tdb->allrecord_lock.ltype, false);
+-- 
+2.9.3
+
diff --git a/SOURCES/0004-tdb-Do-lock-upgrades-properly.patch b/SOURCES/0004-tdb-Do-lock-upgrades-properly.patch
new file mode 100644
index 0000000..4a6e146
--- /dev/null
+++ b/SOURCES/0004-tdb-Do-lock-upgrades-properly.patch
@@ -0,0 +1,47 @@
+From a6f1532d7fedc6b6f36b511aebe8998e9452b7ff Mon Sep 17 00:00:00 2001
+From: Volker Lendecke <vl@samba.org>
+Date: Mon, 7 Nov 2016 21:40:15 +0100
+Subject: [PATCH] tdb: Do lock upgrades properly
+
+When a process holds a readlock and wants to upgrade, this needs to be
+reflected in the underlying lock. Without this, it is possible to cheat:
+One process holds a readlock, and another process wants to write this
+record. All the writer has to do is take a readonly lock on the key and
+then do the store.
+
+Signed-off-by: Volker Lendecke <vl@samba.org>
+Reviewed-by: Jeremy Allison <jra@samba.org>
+---
+ lib/tdb/common/lock.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/lib/tdb/common/lock.c b/lib/tdb/common/lock.c
+index 594c28751f1d68c8305bd225f228c437fee81c9e..4ad70cff3fe639abb781b204aa86a437e4a7adfe 100644
+--- a/lib/tdb/common/lock.c
++++ b/lib/tdb/common/lock.c
+@@ -321,6 +321,22 @@ int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype,
+ 
+ 	new_lck = find_nestlock(tdb, offset);
+ 	if (new_lck) {
++		if ((new_lck->ltype == F_RDLCK) && (ltype == F_WRLCK)) {
++			if (!tdb_have_mutexes(tdb)) {
++				int ret;
++				/*
++				 * Upgrade the underlying fcntl
++				 * lock. Mutexes don't do readlocks,
++				 * so this only applies to fcntl
++				 * locking.
++				 */
++				ret = tdb_brlock(tdb, ltype, offset, 1, flags);
++				if (ret != 0) {
++					return ret;
++				}
++			}
++			new_lck->ltype = F_WRLCK;
++		}
+ 		/*
+ 		 * Just increment the in-memory struct, posix locks
+ 		 * don't stack.
+-- 
+2.9.3
+
diff --git a/SOURCES/0005-tdb-Test-for-readonly-lock-upgrade-bug.patch b/SOURCES/0005-tdb-Test-for-readonly-lock-upgrade-bug.patch
new file mode 100644
index 0000000..edffe8e
--- /dev/null
+++ b/SOURCES/0005-tdb-Test-for-readonly-lock-upgrade-bug.patch
@@ -0,0 +1,203 @@
+From 397d1936ec34fa573c7d46cc51c971986e8f7fe8 Mon Sep 17 00:00:00 2001
+From: Volker Lendecke <vl@samba.org>
+Date: Tue, 8 Nov 2016 17:01:56 +0100
+Subject: [PATCH] tdb: Test for readonly lock upgrade bug
+
+Signed-off-by: Volker Lendecke <vl@samba.org>
+Reviewed-by: Jeremy Allison <jra@samba.org>
+
+Autobuild-User(master): Jeremy Allison <jra@samba.org>
+Autobuild-Date(master): Tue Apr 11 00:33:31 CEST 2017 on sn-devel-144
+---
+ lib/tdb/test/run-rdlock-upgrade.c | 166 ++++++++++++++++++++++++++++++++++++++
+ lib/tdb/wscript                   |   1 +
+ 2 files changed, 167 insertions(+)
+ create mode 100644 lib/tdb/test/run-rdlock-upgrade.c
+
+diff --git a/lib/tdb/test/run-rdlock-upgrade.c b/lib/tdb/test/run-rdlock-upgrade.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..042001b4231530e93618f481d3fbeef4ecfd309b
+--- /dev/null
++++ b/lib/tdb/test/run-rdlock-upgrade.c
+@@ -0,0 +1,166 @@
++#include "../common/io.c"
++#include "../common/tdb.c"
++#include "../common/lock.c"
++#include "../common/freelist.c"
++#include "../common/traverse.c"
++#include "../common/transaction.c"
++#include "../common/error.c"
++#include "../common/open.c"
++#include "../common/check.c"
++#include "../common/hash.c"
++#include "../common/mutex.c"
++#include "tap-interface.h"
++#include <stdlib.h>
++#include <sys/types.h>
++#include <sys/wait.h>
++#include <stdarg.h>
++#include "logging.h"
++
++static TDB_DATA key, data;
++
++static void do_chainlock(const char *name, int tdb_flags, int up, int down)
++{
++	struct tdb_context *tdb;
++	int ret;
++	ssize_t nread, nwritten;
++	char c = 0;
++
++	tdb = tdb_open_ex(name, 3, tdb_flags,
++			  O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
++	ok(tdb, "tdb_open_ex should succeed");
++
++	ret = tdb_chainlock_read(tdb, key);
++	ok(ret == 0, "tdb_chainlock_read should succeed");
++
++	nwritten = write(up, &c, sizeof(c));
++	ok(nwritten == sizeof(c), "write should succeed");
++
++	nread = read(down, &c, sizeof(c));
++	ok(nread == 0, "read should succeed");
++
++	exit(0);
++}
++
++static void do_trylock(const char *name, int tdb_flags, int up, int down)
++{
++	struct tdb_context *tdb;
++	int ret;
++	ssize_t nread, nwritten;
++	char c = 0;
++
++	tdb = tdb_open_ex(name, 3, tdb_flags,
++			  O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
++	ok(tdb, "tdb_open_ex should succeed");
++
++	/*
++	 * tdb used to have a bug where with fcntl locks an upgrade
++	 * from a readlock to writelock did not check for the
++	 * underlying fcntl lock. Mutexes don't distinguish between
++	 * readlocks and writelocks, so that bug does not apply here.
++	 */
++
++	ret = tdb_chainlock_read(tdb, key);
++	ok(ret == 0, "tdb_chainlock_read should succeed");
++
++	ret = tdb_chainlock_nonblock(tdb, key);
++	ok(ret == -1, "tdb_chainlock_nonblock should fail");
++
++	nwritten = write(up, &c, sizeof(c));
++	ok(nwritten == sizeof(c), "write should succeed");
++
++	nread = read(down, &c, sizeof(c));
++	ok(nread == 0, "read should succeed");
++
++	exit(0);
++}
++
++static int do_tests(const char *name, int tdb_flags)
++{
++	int ret;
++	pid_t chainlock_child, store_child;
++	int chainlock_down[2];
++	int chainlock_up[2];
++	int store_down[2];
++	int store_up[2];
++	char c;
++	ssize_t nread;
++
++	key.dsize = strlen("hi");
++	key.dptr = discard_const_p(uint8_t, "hi");
++	data.dsize = strlen("world");
++	data.dptr = discard_const_p(uint8_t, "world");
++
++	ret = pipe(chainlock_down);
++	ok(ret == 0, "pipe should succeed");
++
++	ret = pipe(chainlock_up);
++	ok(ret == 0, "pipe should succeed");
++
++	ret = pipe(store_down);
++	ok(ret == 0, "pipe should succeed");
++
++	ret = pipe(store_up);
++	ok(ret == 0, "pipe should succeed");
++
++	chainlock_child = fork();
++	ok(chainlock_child != -1, "fork should succeed");
++
++	if (chainlock_child == 0) {
++		close(chainlock_up[0]);
++		close(chainlock_down[1]);
++		close(store_up[0]);
++		close(store_up[1]);
++		close(store_down[0]);
++		close(store_down[1]);
++		do_chainlock(name, tdb_flags,
++			     chainlock_up[1], chainlock_down[0]);
++		exit(0);
++	}
++	close(chainlock_up[1]);
++	close(chainlock_down[0]);
++
++	nread = read(chainlock_up[0], &c, sizeof(c));
++	ok(nread == sizeof(c), "read should succeed");
++
++	/*
++	 * Now we have a process holding a chain read lock. Start
++	 * another process trying to write lock. This should fail.
++	 */
++
++	store_child = fork();
++	ok(store_child != -1, "fork should succeed");
++
++	if (store_child == 0) {
++		close(chainlock_up[0]);
++		close(chainlock_down[1]);
++		close(store_up[0]);
++		close(store_down[1]);
++		do_trylock(name, tdb_flags,
++			   store_up[1], store_down[0]);
++		exit(0);
++	}
++	close(store_up[1]);
++	close(store_down[0]);
++
++	nread = read(store_up[0], &c, sizeof(c));
++	ok(nread == sizeof(c), "read should succeed");
++
++	close(chainlock_up[0]);
++	close(chainlock_down[1]);
++	close(store_up[0]);
++	close(store_down[1]);
++	diag("%s tests done", name);
++	return exit_status();
++}
++
++int main(int argc, char *argv[])
++{
++	int ret;
++
++	ret = do_tests("rdlock-upgrade.tdb",
++		       TDB_CLEAR_IF_FIRST |
++		       TDB_INCOMPATIBLE_HASH);
++	ok(ret == 0, "rdlock-upgrade.tdb tests should succeed");
++
++	return exit_status();
++}
+diff --git a/lib/tdb/wscript b/lib/tdb/wscript
+index 0d682ebb4cdaa001904e0b40e50e1a2e46f230ee..693787cb75da6462a81dcae6fba8981b99e90e69 100644
+--- a/lib/tdb/wscript
++++ b/lib/tdb/wscript
+@@ -34,6 +34,7 @@ tdb1_unit_tests = [
+     'run-readonly-check',
+     'run-rescue',
+     'run-rescue-find_entry',
++    'run-rdlock-upgrade',
+     'run-rwlock-check',
+     'run-summary',
+     'run-transaction-expand',
+-- 
+2.9.3
+
diff --git a/SOURCES/0006-tdbtool-Add-storehex-command.patch b/SOURCES/0006-tdbtool-Add-storehex-command.patch
new file mode 100644
index 0000000..8c99b83
--- /dev/null
+++ b/SOURCES/0006-tdbtool-Add-storehex-command.patch
@@ -0,0 +1,168 @@
+From 5d288a9b1705b75e7e8dcf93a93b7fd6715ad5ef Mon Sep 17 00:00:00 2001
+From: Volker Lendecke <vl@samba.org>
+Date: Fri, 21 Apr 2017 14:10:33 +0200
+Subject: [PATCH] tdbtool: Add "storehex" command
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Volker Lendecke <vl@samba.org>
+Reviewed-by: Ralph Böhme <slow@samba.org>
+
+Autobuild-User(master): Jeremy Allison <jra@samba.org>
+Autobuild-Date(master): Sat Apr 22 09:16:16 CEST 2017 on sn-devel-144
+---
+ lib/tdb/man/tdbtool.8.xml | 10 ++++++
+ lib/tdb/tools/tdbtool.c   | 87 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 97 insertions(+)
+
+diff --git a/lib/tdb/man/tdbtool.8.xml b/lib/tdb/man/tdbtool.8.xml
+index 9a9b95e6a0621dc3c880c154d28c972ea02be401..045cbde73dd7d88c36a77c8ed35d49e69bf17554 100644
+--- a/lib/tdb/man/tdbtool.8.xml
++++ b/lib/tdb/man/tdbtool.8.xml
+@@ -160,6 +160,16 @@
+ 		</varlistentry>
+ 
+ 		<varlistentry>
++		<term><option>storehex</option>
++		<replaceable>KEY</replaceable>
++		<replaceable>DATA</replaceable>
++		</term>
++		<listitem><para>Store (replace) a record in the
++		current database where key and data are in hex format.
++		</para></listitem>
++		</varlistentry>
++
++		<varlistentry>
+ 		<term><option>show</option>
+ 		<replaceable>KEY</replaceable>
+ 		</term>
+diff --git a/lib/tdb/tools/tdbtool.c b/lib/tdb/tools/tdbtool.c
+index beb3af18e23051586991bbd101fa6a5d2fa8103d..e3535b93c7c4296a9b4f9d3b9797841f762062cd 100644
+--- a/lib/tdb/tools/tdbtool.c
++++ b/lib/tdb/tools/tdbtool.c
+@@ -48,6 +48,7 @@ enum commands {
+ 	CMD_DUMP,
+ 	CMD_INSERT,
+ 	CMD_MOVE,
++	CMD_STOREHEX,
+ 	CMD_STORE,
+ 	CMD_SHOW,
+ 	CMD_KEYS,
+@@ -83,6 +84,7 @@ COMMAND_TABLE cmd_table[] = {
+ 	{"dump",	CMD_DUMP},
+ 	{"insert",	CMD_INSERT},
+ 	{"move",	CMD_MOVE},
++	{"storehex",	CMD_STOREHEX},
+ 	{"store",	CMD_STORE},
+ 	{"show",	CMD_SHOW},
+ 	{"keys",	CMD_KEYS},
+@@ -229,6 +231,7 @@ static void help(void)
+ "  info                 : print summary info about the database\n"
+ "  insert    key  data  : insert a record\n"
+ "  move      key  file  : move a record to a destination tdb\n"
++"  storehex  key  data  : store a record (replace), key/value in hex format\n"
+ "  store     key  data  : store a record (replace)\n"
+ "  show      key        : show a record by key\n"
+ "  delete    key        : delete a record by key\n"
+@@ -346,6 +349,86 @@ static void store_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
+ 	}
+ }
+ 
++static bool hexchar(char c, uint8_t *v)
++{
++	if ((c >= '0') && (c <= '9')) {
++		*v = (c - '0');
++		return true;
++	}
++	if ((c >= 'A') && (c <= 'F')) {
++		*v = (c - 'A' + 10);
++		return true;
++	}
++	if ((c >= 'a') && (c <= 'f')) {
++		*v = (c - 'a' + 10);
++		return true;
++	}
++	return false;
++}
++
++static bool parse_hex(const char *src, size_t srclen, uint8_t *dst)
++{
++	size_t i=0;
++
++	if ((srclen % 2) != 0) {
++		return false;
++	}
++
++	while (i<srclen) {
++		bool ok;
++		uint8_t hi,lo;
++
++		ok = (hexchar(src[i++], &hi) && hexchar(src[i++], &lo));
++		if (!ok) {
++			return false;
++		}
++		*dst = (hi<<4)|lo;
++		dst += 1;
++	}
++
++	return true;
++}
++
++static void store_hex_tdb(char *keystr, size_t keylen,
++			  char *datastr, size_t datalen)
++{
++	if ((keystr == NULL) || (keylen == 0)) {
++		terror("need key");
++		return;
++	}
++	if ((datastr == NULL) || (datalen == 0)) {
++		terror("need data");
++		return;
++	}
++
++	{
++		uint8_t keybuf[keylen/2];
++		TDB_DATA key = { .dptr = keybuf, .dsize = sizeof(keybuf) };
++		uint8_t databuf[datalen/2];
++		TDB_DATA data = { .dptr = databuf, .dsize = sizeof(databuf) };
++		bool ok;
++
++		ok = parse_hex(keystr, keylen, keybuf);
++		if (!ok) {
++			terror("need hex key");
++			return;
++		}
++		ok = parse_hex(datastr, datalen, databuf);
++		if (!ok) {
++			terror("need hex data");
++			return;
++		}
++
++		printf("storing key/data:\n");
++		print_data((char *)key.dptr, key.dsize);
++		print_data((char *)data.dptr, data.dsize);
++
++		if (tdb_store(tdb, key, data, TDB_REPLACE) != 0) {
++			terror("store failed");
++		}
++	}
++}
++
+ static void show_tdb(char *keyname, size_t keylen)
+ {
+ 	TDB_DATA key, dbuf;
+@@ -693,6 +776,10 @@ static int do_command(void)
+ 			bIterate = 0;
+ 			store_tdb(arg1,arg1len,arg2,arg2len);
+ 			return 0;
++		case CMD_STOREHEX:
++			bIterate = 0;
++			store_hex_tdb(arg1,arg1len,arg2,arg2len);
++			return 0;
+ 		case CMD_SHOW:
+ 			bIterate = 0;
+ 			show_tdb(arg1, arg1len);
+-- 
+2.9.3
+
diff --git a/SOURCES/0007-tdb-runtime-check-for-robust-mutexes-may-hang-in-thr.patch b/SOURCES/0007-tdb-runtime-check-for-robust-mutexes-may-hang-in-thr.patch
new file mode 100644
index 0000000..904471e
--- /dev/null
+++ b/SOURCES/0007-tdb-runtime-check-for-robust-mutexes-may-hang-in-thr.patch
@@ -0,0 +1,218 @@
+From 19b193ebc974efdebdf347143938b5d053e67051 Mon Sep 17 00:00:00 2001
+From: Ralph Boehme <slow@samba.org>
+Date: Tue, 14 Mar 2017 14:24:18 +0100
+Subject: [PATCH] tdb: runtime check for robust mutexes may hang in threaded
+ programs
+
+The current runtime check for robust mutexes in
+tdb_runtime_check_for_robust_mutexes() is not thread-safe.
+
+When called in a multi-threaded program where any another thread doesn't
+have SIGCHLD blocked, we may end up hung in sigsuspend() waiting for a
+SIGCHLD of a child procecss and the signal was delivered to another
+thread.
+
+Revert to the previous behaviour of waiting for the child instead of
+waiting for the SIGCHLD signal.
+
+Ensure the pid we wait for is not reset to -1 in a toctou race with the
+signal handler.
+
+Check whether waitpid() returns ECHILD which can happen if the signal
+handler is run by more then one thread in parallel (yes, this can
+happen) or if tdb_robust_mutex_wait_for_child() and the signal handler
+are racing.
+
+Bug: https://bugzilla.samba.org/show_bug.cgi?id=12593
+
+Pair-programmed-with: Stefan Metzmacher <metze@samba.org>
+
+Signed-off-by: Ralph Boehme <slow@samba.org>
+Signed-off-by: Stefan Metzmacher <metze@samba.org>
+Reviewed-by: Andreas Schneider <asn@samba.org>
+---
+ lib/tdb/common/mutex.c | 116 +++++++++++++++++++++++++++++--------------------
+ 1 file changed, 70 insertions(+), 46 deletions(-)
+
+diff --git a/lib/tdb/common/mutex.c b/lib/tdb/common/mutex.c
+index cac3916713f2da97694cf8d02f67ab9cf0da3025..8a122d5d6a2ec321bce25cf06062acc808f1e126 100644
+--- a/lib/tdb/common/mutex.c
++++ b/lib/tdb/common/mutex.c
+@@ -752,12 +752,23 @@ static bool tdb_robust_mutex_setup_sigchild(void (*handler)(int),
+ 
+ static void tdb_robust_mutex_handler(int sig)
+ {
+-	if (tdb_robust_mutex_pid != -1) {
++	pid_t child_pid = tdb_robust_mutex_pid;
++
++	if (child_pid != -1) {
+ 		pid_t pid;
+-		int status;
+ 
+-		pid = waitpid(tdb_robust_mutex_pid, &status, WNOHANG);
+-		if (pid == tdb_robust_mutex_pid) {
++		pid = waitpid(child_pid, NULL, WNOHANG);
++		if (pid == -1) {
++			switch (errno) {
++			case ECHILD:
++				tdb_robust_mutex_pid = -1;
++				return;
++
++			default:
++				return;
++			}
++		}
++		if (pid == child_pid) {
+ 			tdb_robust_mutex_pid = -1;
+ 			return;
+ 		}
+@@ -776,6 +787,44 @@ static void tdb_robust_mutex_handler(int sig)
+ 	tdb_robust_mutext_old_handler(sig);
+ }
+ 
++static void tdb_robust_mutex_wait_for_child(pid_t *child_pid)
++{
++	int options = WNOHANG;
++
++	if (*child_pid == -1) {
++		return;
++	}
++
++	while (tdb_robust_mutex_pid > 0) {
++		pid_t pid;
++
++		/*
++		 * First we try with WNOHANG, as the process might not exist
++		 * anymore. Once we've sent SIGKILL we block waiting for the
++		 * exit.
++		 */
++		pid = waitpid(*child_pid, NULL, options);
++		if (pid == -1) {
++			if (errno == EINTR) {
++				continue;
++			} else if (errno == ECHILD) {
++				break;
++			} else {
++				abort();
++			}
++		}
++		if (pid == *child_pid) {
++			break;
++		}
++
++		kill(*child_pid, SIGKILL);
++		options = 0;
++	}
++
++	tdb_robust_mutex_pid = -1;
++	*child_pid = -1;
++}
++
+ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
+ {
+ 	void *ptr = NULL;
+@@ -788,9 +837,8 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
+ 	char c = 0;
+ 	bool ok;
+ 	static bool initialized;
+-	sigset_t mask, old_mask, suspend_mask;
++	pid_t saved_child_pid = -1;
+ 	bool cleanup_ma = false;
+-	bool cleanup_sigmask = false;
+ 
+ 	if (initialized) {
+ 		return tdb_mutex_locking_cached;
+@@ -798,8 +846,6 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
+ 
+ 	initialized = true;
+ 
+-	sigemptyset(&suspend_mask);
+-
+ 	ok = tdb_mutex_locking_supported();
+ 	if (!ok) {
+ 		return false;
+@@ -845,26 +891,13 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
+ 	}
+ 	m = (pthread_mutex_t *)ptr;
+ 
+-	/*
+-	 * Block SIGCHLD so we can atomically wait for it later with
+-	 * sigsuspend()
+-	 */
+-	sigemptyset(&mask);
+-	sigaddset(&mask, SIGCHLD);
+-	ret = pthread_sigmask(SIG_BLOCK, &mask, &old_mask);
+-	if (ret != 0) {
+-		goto cleanup;
+-	}
+-	cleanup_sigmask = true;
+-	suspend_mask = old_mask;
+-	sigdelset(&suspend_mask, SIGCHLD);
+-
+ 	if (tdb_robust_mutex_setup_sigchild(tdb_robust_mutex_handler,
+ 			&tdb_robust_mutext_old_handler) == false) {
+ 		goto cleanup;
+ 	}
+ 
+ 	tdb_robust_mutex_pid = fork();
++	saved_child_pid = tdb_robust_mutex_pid;
+ 	if (tdb_robust_mutex_pid == 0) {
+ 		size_t nwritten;
+ 		close(pipe_down[1]);
+@@ -914,14 +947,7 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
+ 		goto cleanup;
+ 	}
+ 
+-	while (tdb_robust_mutex_pid > 0) {
+-		ret = sigsuspend(&suspend_mask);
+-		if (ret != -1 || errno != EINTR) {
+-			abort();
+-		}
+-	}
+-	tdb_robust_mutex_setup_sigchild(tdb_robust_mutext_old_handler, NULL);
+-	tdb_robust_mutext_old_handler = SIG_ERR;
++	tdb_robust_mutex_wait_for_child(&saved_child_pid);
+ 
+ 	ret = pthread_mutex_trylock(m);
+ 	if (ret != EOWNERDEAD) {
+@@ -950,23 +976,21 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void)
+ 	tdb_mutex_locking_cached = true;
+ 
+ cleanup:
+-	while (tdb_robust_mutex_pid > 0) {
+-		kill(tdb_robust_mutex_pid, SIGKILL);
+-		ret = sigsuspend(&suspend_mask);
+-		if (ret != -1 || errno != EINTR) {
+-			abort();
+-		}
+-	}
++	/*
++	 * Note that we don't reset the signal handler we just reset
++	 * tdb_robust_mutex_pid to -1. This is ok as this code path is only
++	 * called once per process.
++	 *
++	 * Leaving our signal handler avoids races with other threads potentialy
++	 * setting up their SIGCHLD handlers.
++	 *
++	 * The worst thing that can happen is that the other newer signal
++	 * handler will get the SIGCHLD signal for our child and/or reap the
++	 * child with a wait() function. tdb_robust_mutex_wait_for_child()
++	 * handles the case where waitpid returns ECHILD.
++	 */
++	tdb_robust_mutex_wait_for_child(&saved_child_pid);
+ 
+-	if (tdb_robust_mutext_old_handler != SIG_ERR) {
+-		tdb_robust_mutex_setup_sigchild(tdb_robust_mutext_old_handler, NULL);
+-	}
+-	if (cleanup_sigmask) {
+-		ret = pthread_sigmask(SIG_SETMASK, &old_mask, NULL);
+-		if (ret != 0) {
+-			abort();
+-		}
+-	}
+ 	if (m != NULL) {
+ 		pthread_mutex_destroy(m);
+ 	}
+-- 
+2.9.3
+
diff --git a/SOURCES/0008-tdb-Improve-debugging-when-the-allrecord-lock-fails-.patch b/SOURCES/0008-tdb-Improve-debugging-when-the-allrecord-lock-fails-.patch
new file mode 100644
index 0000000..8dc1da6
--- /dev/null
+++ b/SOURCES/0008-tdb-Improve-debugging-when-the-allrecord-lock-fails-.patch
@@ -0,0 +1,54 @@
+From 1148e8f0408b62b0417daf8e2727cdaf7cffed09 Mon Sep 17 00:00:00 2001
+From: Andrew Bartlett <abartlet@samba.org>
+Date: Thu, 30 Mar 2017 19:11:06 +1300
+Subject: [PATCH] tdb: Improve debugging when the allrecord lock fails to
+ upgrade
+
+Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>
+
+Signed-off-by: Andrew Bartlett <abartlet@samba.org>
+Signed-off-by: Stefan Metzmacher <metze@samba.org>
+Reviewed-by: Andreas Schneider <asn@samba.org>
+---
+ lib/tdb/common/lock.c        | 2 ++
+ lib/tdb/common/transaction.c | 5 ++++-
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/lib/tdb/common/lock.c b/lib/tdb/common/lock.c
+index 4ad70cff3fe639abb781b204aa86a437e4a7adfe..e330201961a05bfef839659f260a5bbae078fbb5 100644
+--- a/lib/tdb/common/lock.c
++++ b/lib/tdb/common/lock.c
+@@ -257,12 +257,14 @@ int tdb_allrecord_upgrade(struct tdb_context *tdb)
+ 		TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ 			 "tdb_allrecord_upgrade failed: count %u too high\n",
+ 			 tdb->allrecord_lock.count));
++		tdb->ecode = TDB_ERR_LOCK;
+ 		return -1;
+ 	}
+ 
+ 	if (tdb->allrecord_lock.off != 1) {
+ 		TDB_LOG((tdb, TDB_DEBUG_ERROR,
+ 			 "tdb_allrecord_upgrade failed: already upgraded?\n"));
++		tdb->ecode = TDB_ERR_LOCK;
+ 		return -1;
+ 	}
+ 
+diff --git a/lib/tdb/common/transaction.c b/lib/tdb/common/transaction.c
+index 0dd057ba7a71151e5173cb6d9b25666f915eab27..4d08fee6c25e61c61c783d08fc64c611fab51119 100644
+--- a/lib/tdb/common/transaction.c
++++ b/lib/tdb/common/transaction.c
+@@ -982,7 +982,10 @@ static int _tdb_transaction_prepare_commit(struct tdb_context *tdb)
+ 
+ 	/* upgrade the main transaction lock region to a write lock */
+ 	if (tdb_allrecord_upgrade(tdb) == -1) {
+-		TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to upgrade hash locks\n"));
++		TDB_LOG((tdb, TDB_DEBUG_ERROR,
++			"tdb_transaction_prepare_commit: "
++			"failed to upgrade hash locks: %s\n",
++			 tdb_errorstr(tdb)));
+ 		_tdb_transaction_cancel(tdb);
+ 		return -1;
+ 	}
+-- 
+2.9.3
+
diff --git a/SOURCES/0009-tdb-Improve-debugging-in-_tdb_transaction_start.patch b/SOURCES/0009-tdb-Improve-debugging-in-_tdb_transaction_start.patch
new file mode 100644
index 0000000..bb45e0a
--- /dev/null
+++ b/SOURCES/0009-tdb-Improve-debugging-in-_tdb_transaction_start.patch
@@ -0,0 +1,30 @@
+From 36078263344fbad348fe21da757976ecd6d55be6 Mon Sep 17 00:00:00 2001
+From: Andrew Bartlett <abartlet@samba.org>
+Date: Fri, 31 Mar 2017 17:35:06 +1300
+Subject: [PATCH] tdb: Improve debugging in _tdb_transaction_start
+
+Signed-off-by: Andrew Bartlett <abartlet@samba.org>
+Reviewed-by: Stefan Metzmacher <metze@samba.org>
+Reviewed-by: Andreas Schneider <asn@samba.org>
+---
+ lib/tdb/common/transaction.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/lib/tdb/common/transaction.c b/lib/tdb/common/transaction.c
+index 4d08fee6c25e61c61c783d08fc64c611fab51119..f1050a2f7d9e9c86856d1469739c2a2d70ca1c85 100644
+--- a/lib/tdb/common/transaction.c
++++ b/lib/tdb/common/transaction.c
+@@ -476,6 +476,10 @@ static int _tdb_transaction_start(struct tdb_context *tdb,
+ 		SAFE_FREE(tdb->transaction);
+ 		if ((lockflags & TDB_LOCK_WAIT) == 0) {
+ 			tdb->ecode = TDB_ERR_NOLOCK;
++		} else {
++			TDB_LOG((tdb, TDB_DEBUG_ERROR,
++				 "tdb_transaction_start: "
++				 "failed to get transaction lock\n"));
+ 		}
+ 		return -1;
+ 	}
+-- 
+2.9.3
+
diff --git a/SPECS/libtdb.spec b/SPECS/libtdb.spec
index eda20d8..e10526c 100644
--- a/SPECS/libtdb.spec
+++ b/SPECS/libtdb.spec
@@ -5,8 +5,8 @@
 %{!?python_version: %global python_version %(%{__python} -c "from distutils.sysconfig import get_python_version; print(get_python_version())")}
 
 Name: libtdb
-Version: 1.3.8
-Release: 1%{?dist}
+Version: 1.3.12
+Release: 2%{?dist}
 Group: System Environment/Daemons
 Summary: The tdb library
 License: LGPLv3+
@@ -22,6 +22,15 @@ BuildRequires: python-devel
 Provides: bundled(libreplace)
 
 # Patches
+Patch0001: 0001-waf-disable-python-align-tdb-s-wscript.patch
+Patch0002: 0002-tdb-tools-add-documentation-for-the-tdbbackup-n-opti.patch
+Patch0003: 0003-tdb-Fix-some-signed-unsigned-hickups.patch
+Patch0004: 0004-tdb-Do-lock-upgrades-properly.patch
+Patch0005: 0005-tdb-Test-for-readonly-lock-upgrade-bug.patch
+Patch0006: 0006-tdbtool-Add-storehex-command.patch
+Patch0007: 0007-tdb-runtime-check-for-robust-mutexes-may-hang-in-thr.patch
+Patch0008: 0008-tdb-Improve-debugging-when-the-allrecord-lock-fails-.patch
+Patch0009: 0009-tdb-Improve-debugging-in-_tdb_transaction_start.patch
 
 %description
 A library that implements a trivial database.
@@ -54,6 +63,11 @@ Python bindings for libtdb
 %prep
 %setup -q -n tdb-%{version}
 
+for p in %patches ; do
+    %__patch -p3 -i $p
+done
+
+
 %build
 %configure --disable-rpath \
            --bundled-libraries=NONE \
@@ -110,9 +124,15 @@ rm -rf $RPM_BUILD_ROOT
 %postun -n python-tdb -p /sbin/ldconfig
 
 %changelog
+* Tue May  2 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.3.12-2
+- Resolves: rhbz#1441231 - The tdb robust mutexes runtime check is not thread safe and ends in a deadlock
+
+* Tue Feb 14 2017 Jakub Hrozek <jhrozek@redhat.com> - 1.3.12-1
+- Resolves: rhbz#1393812 - Rebase libtevent in RHEL-7.4 to version 4.6.x
+
 * Fri Apr  1 2016 Jakub Hrozek <jhrozek@redhat.com> - 1.3.8-1
 - Rebase libtdb to 1.3.8
-- Related: rhbz#1322690
+- Related: rhbz#1322691
 
 * Wed Aug 19 2015 Jakub Hrozek <jhrozek@redhat.com> - 1.3.6-2
 - Resolves: rhbz#1241015 - tdb deadlocks if you acquire allrecord_lock